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

Я пытаюсь настроить 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 просто обрабатывал всю мою сериализацию.Это должно быть быстрее и эффективнее в любом случае.

...