HazelcastSerializationException с использованием Subzero / Kryo в качестве глобального сериализатора при вызове CacheManager.createCache ()

Я пытаюсь настроить Hazelcast в конфигурации клиент-сервер для использования с JCache API на клиенте. Это многопользовательская настройка, поэтому мне нужно динамически создавать отдельные кеши в клиентском коде, а не в конфигурации Hazelcast. Некоторые из кэшированных объектов взяты из сторонней библиотеки и не являются сериализуемыми, поэтому я использую Ниже нуля, чтобы задействовать Крио в качестве глобального сериализатора.

Когда я настраиваю 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 в путь к классам, и ссылку на мой собственный файл конфигурации:

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, поэтому кешем является Object-Object. Нет разницы.

Если я отключу переопределение сериализации Java с помощью Kryo как на клиенте, так и на сервере, все почти будет работать. Вызов createCache () работает нормально со String, Object и / или Serializable в качестве аргументов класса. Я могу хранить простые сериализуемые и несериализуемые объекты в кешах сервера. Классы не обязательно должны быть в пути к классам сервера.

Когда я снова сталкиваюсь с проблемой, это когда я пытаюсь кэшировать множество несериализуемых объектов. Сериализация массива, по-видимому, попадает в сериализатор Java, который затем сходит с ума, когда отдельные элементы не сериализуемы. Итак, я вернулся к попыткам заставить работать переопределение Крио.

Я нашел один обходной путь - обернуть любой массив или коллекцию несериализуемым классом, чтобы Kryo вызывалась на верхнем уровне вместо собственного сериализатора. Я могу создать утилиту, которая обертывает Cache и реализует обходной путь с помощью универсального класса оболочки, но это хакерство, и я бы предпочел, чтобы Kryo просто обрабатывала всю мою сериализацию. В любом случае он должен быть быстрее и эффективнее.

Вы нашли какое-нибудь решение? У меня такая же проблема. Использование SubZero 0.9 и Hazelcast 3.12. После переключения на JCache я получаю HazelcastSerializationException (для типа 6000 не существует подходящего десериализатора. Это исключение, вероятно, вызвано различиями в конфигурации сериализации между участниками или между клиентами и участниками)

Sina Nourian 05.05.2020 08:41

@SinaNourian, наконец-то мы получили работу, так это обходной путь, упомянутый в последнем абзаце. Мы отключили переопределение, поэтому материал Serializable проходит через сериализацию Java. Мы оборачиваем любые коллекции или массивы несериализуемых объектов несериализуемым классом-оболочкой, поэтому все это передается Kryo. После этого мы также переключили всю конфигурацию на клиентскую сторону, потому что есть проблемы, если есть какие-либо конфликты между тем, что представляет собой серверный XML, и конфигурацией клиента, включая подпись классов ключей и значений. Так что попробуйте сделать конфиг всего в одном месте.

Jay HH 06.05.2020 17:20
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
2
564
0

Другие вопросы по теме