Я пытаюсь настроить Hazelcast в конфигурации клиент-сервер для использования с JCache API в клиенте.Это мультитенантная установка, поэтому я должен динамически создавать отдельные кэши в клиентском коде, а не в конфигурации Hazelcast.Некоторые из кэшированных объектов взяты из сторонней библиотеки и не могут быть сериализуемыми, поэтому я использую Subzero для извлечения Kryo в качестве глобального сериализатора.
КогдаЯ настроил Kryo для переопределения собственной сериализации Java, и сразу получаю следующую ошибку на CacheManager.createCache (name, String.class, Object.class):
Exception in thread "main" com.hazelcast.nio.serialization.HazelcastSerializationException: There is no suitable de-serializer for type 6000. This exception is likely to be caused by differences in the serialization configuration between members or between clients and members.
at com.hazelcast.internal.serialization.impl.AbstractSerializationService.newHazelcastSerializationException(AbstractSerializationService.java:238)
at com.hazelcast.internal.serialization.impl.AbstractSerializationService.readObject(AbstractSerializationService.java:265)
at com.hazelcast.internal.serialization.impl.ByteArrayObjectDataInput.readObject(ByteArrayObjectDataInput.java:574)
at com.hazelcast.config.CacheConfig.readFactories(CacheConfig.java:644)
at com.hazelcast.config.CacheConfig.readData(CacheConfig.java:557)
at com.hazelcast.internal.serialization.impl.DataSerializableSerializer.readInternal(DataSerializableSerializer.java:158)
at com.hazelcast.internal.serialization.impl.DataSerializableSerializer.read(DataSerializableSerializer.java:105)
at com.hazelcast.internal.serialization.impl.DataSerializableSerializer.read(DataSerializableSerializer.java:50)
at com.hazelcast.internal.serialization.impl.StreamSerializerAdapter.read(StreamSerializerAdapter.java:48)
at com.hazelcast.internal.serialization.impl.AbstractSerializationService.toObject(AbstractSerializationService.java:187)
at com.hazelcast.spi.impl.NodeEngineImpl.toObject(NodeEngineImpl.java:322)
at com.hazelcast.client.impl.protocol.task.cache.CacheCreateConfigMessageTask.extractCacheConfigFromMessage(CacheCreateConfigMessageTask.java:87)
at com.hazelcast.client.impl.protocol.task.cache.CacheCreateConfigMessageTask.processMessage(CacheCreateConfigMessageTask.java:56)
at com.hazelcast.client.impl.protocol.task.AbstractMessageTask.initializeAndProcessMessage(AbstractMessageTask.java:123)
at com.hazelcast.client.impl.protocol.task.AbstractMessageTask.doRun(AbstractMessageTask.java:111)
at com.hazelcast.client.impl.protocol.task.AbstractMessageTask.run(AbstractMessageTask.java:101)
at com.hazelcast.spi.impl.operationservice.impl.OperationRunnerImpl.run(OperationRunnerImpl.java:155)
at com.hazelcast.spi.impl.operationexecutor.impl.OperationThread.process(OperationThread.java:125)
at com.hazelcast.spi.impl.operationexecutor.impl.OperationThread.run(OperationThread.java:100)
at ------ submitted from ------.(Unknown Source)
at com.hazelcast.client.spi.impl.ClientInvocationFuture.resolveAndThrowIfException(ClientInvocationFuture.java:96)
at com.hazelcast.client.spi.impl.ClientInvocationFuture.resolveAndThrowIfException(ClientInvocationFuture.java:33)
at com.hazelcast.spi.impl.AbstractInvocationFuture.get(AbstractInvocationFuture.java:154)
at com.hazelcast.client.cache.impl.ClientCacheHelper.createCacheConfig(ClientCacheHelper.java:126)
at com.hazelcast.client.cache.impl.HazelcastClientCacheManager.createCacheConfig(HazelcastClientCacheManager.java:137)
at com.hazelcast.cache.impl.AbstractHazelcastCacheManager.createCacheInternal(AbstractHazelcastCacheManager.java:122)
at com.hazelcast.cache.impl.AbstractHazelcastCacheManager.createCache(AbstractHazelcastCacheManager.java:150)
at com.hazelcast.cache.impl.AbstractHazelcastCacheManager.createCache(AbstractHazelcastCacheManager.java:67)
at com.veeva.App.testCache(App.java:57)
at com.veeva.App.main(App.java:90)
Это происходит, когдаклиент отправляет информацию о конфигурации кэша на сервер.
Для моего расследования я запускаю демонстрационные серверы на своем локальном компьютере из загрузки Hazelcast 3.10.2.(Я начал работать с Hazelcast 3.9.3. Получил тот же результат. Обновился, надеясь, что он изменится. Даже вернулся к 3.8.9. То же самое.) Я изменил сценарий console.sh, добавив Subzero и JCache API в classpath,и ссылаться на мой собственный файл конфигурации:
java -Djava.net.preferIPv4Stack=true -Dhazelcast.config=../lib/hazelcast-jcache.xml -cp ../lib/hazelcast-all-3.10.2.jar:../lib/cache-api-1.1.0.jar:../lib/subzero-all-0.7.jar com.hazelcast.console.ConsoleApp
Мой файл конфигурации hazelcast-jcache.xml основан на hazelcast-default.xml со следующими различиями:
<cache name="default">
<key-type class-name="java.lang.Object"/>
<value-type class-name="java.lang.Object"/>
<statistics-enabled>true</statistics-enabled>
<management-enabled>true</management-enabled>
<backup-count>1</backup-count>
<async-backup-count>0</async-backup-count>
<eviction size="1000" max-size-policy="ENTRY_COUNT" eviction-policy="LFU"/>
</cache>
<serialization>
<serializers>
<global-serializer override-java-serialization="true">
info.jerrinot.subzero.Serializer
</global-serializer>
</serializers>
</serialization>
Мой код клиентанастроены все те же зависимости библиотек, что и сервер:
<dependencies>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>info.jerrinot</groupId>
<artifactId>subzero-core</artifactId>
<version>0.7</version>
<exclusions>
<exclusion>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast-all</artifactId>
<version>3.10.2</version>
</dependency>
</dependencies>
Я исключаю транзитивную зависимость hazelcast в Subzero, поэтому я могу указать свою собственную версию.
Мой клиент настроен программно набыть таким же, как серверы:
private void init() throws URISyntaxException {
ClientConfig config = new ClientConfig();
config.setInstanceName("Boogabooga");
SubZero.useAsGlobalSerializer(config); // internally calls setOverrideJavaSerialization(true)
instance = HazelcastClient.newHazelcastClient(config);
CachingProvider cachingProvider = Caching.getCachingProvider("com.hazelcast.cache.HazelcastCachingProvider");
cacheManager = cachingProvider.getCacheManager(new URI(instance.getName()), null);
}
Код, который создает кеш, просто
private void testCache(String cacheName, String key, Object value) {
Cache<String, Object> myCache = cacheManager.getCache(cacheName);
if (myCache == null) {
LOG.info("Creating Cache " + cacheName);
CompleteConfiguration<String, Object> cacheConfig = new MutableConfiguration<String, Object>()
.setTypes(String.class, Object.class);
myCache = cacheManager.createCache(cacheName, cacheConfig);
} else {
LOG.info("Found Cache " + cacheName);
}
myCache.put(key, object);
Object objectReturned = myCache.get(key);
LOG.info("returned == put ?: " + Objects.equals(object, objectReturned));
}
Я попытался изменить объявленный тип ключа с String на просто Object, поэтомукеш это объект-объект.Без разницы.
Если я отключу переопределение сериализации Java Kryo как на клиенте, так и на сервере, все почти будет работать.Вызов createCache () работает нормально, с String, Object и / или Serializable в качестве аргументов класса.Я могу хранить простые сериализуемые и несериализуемые объекты в кэше сервера.Классы не обязательно должны находиться в пути к классам сервера.
Когда я снова сталкиваюсь с проблемами, я пытаюсь кэшировать массив несериализуемых объектов.Сериализация массива явно передается в сериализатор Java, который затем начинает волноваться, когда отдельные элементы не сериализуемы.Итак, я вернулся к тому, чтобы заставить работать Крио.
Один из обходных путей, который я нашел, - это обернуть любой массив или коллекцию несериализуемым классом, чтобы Kryo вызывался на верхнем уровне вместо собственного сериализатора.Я могу создать утилиту, которая оборачивает Cache и реализует обходной путь с помощью универсального класса-обертки, но это хак, и я бы предпочел, чтобы Kryo просто обрабатывал всю мою сериализацию.Это должно быть быстрее и эффективнее в любом случае.