Search code examples
javaspringredisspring-data-redislettuce

Deserializing issue with Spring Data Redis with Lettuce


Environmnet:
aix 7.1
redis 2.6.17
jdk 1.6
spring-data-commons-1.12.11.RELEASE
spring-data-keyvalue-1.1.11.RELEASE
spring-data-redis-1.7.11
lettuce-3.5.0.Final
A Redis server running on the same host with web applications (clients to Redis)

The problem:
I have set the following RedisTemplate Bean configuration:

@Bean
public RedisTemplate<String, Object> redisTemplate() {
    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
    redisTemplate.setConnectionFactory(redisConnectionFactory());
    redisTemplate.setEnableTransactionSupport(true);
    redisTemplate.setKeySerializer(new StringRedisSerializer());
    redisTemplate.sethashKeySerializer(new StringRedisSerializer);
    return redisTemplate;
}

and also the following is a code of a validation checker for a Redis server:

public class ObservableRedisStateChecker implements Runnable {
    ...
    public void run() {
       try {
           Thread.sleep(3000);
           redisTemplate.opfForValue().get("validation");
           notifyObservers(true);
       } catch (Exception e) {
           noifyObservers(false);  // meaning that the Redis' state isn't fine.
       }
    ...
}

The above ObservableRedisStateChecker checks periodically and notify other instances the state of the Redis server. The code usually works fine, but when too many requests are made, the following error occurs:

org.springframework.data.redis.serializer.SerializationException: 
Cannot deserialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: 
Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; 
nested exception is java.io.EOFException

An weird point is that when I launch a simple test application which runs a very same code with the above validation code on the same host the error occurs, while the error is occurring, the test application says no error. the error is just occurred on the web applications.
The test code is as follows:

...
ExecutorService es = Executors.newCachedThreadPool()
RedisTemplate<String, Obejct> redisTemplate = ...

es.submit(new RedisValidationCheckTest(redisTemplate));
es.submit(new RedisValidationCheckTest(redisTemplate));
es.submit(new RedisValidationCheckTest(redisTemplate));
es.submit(new RedisValidationCheckTest(redisTemplate));
es.submit(new RedisValidationCheckTest(redisTemplate));
es.submit(new RedisValidationCheckTest(redisTemplate));
es.submit(new RedisValidationCheckTest(redisTemplate));
es.submit(new RedisValidationCheckTest(redisTemplate));
es.submit(new RedisValidationCheckTest(redisTemplate));
es.submit(new RedisValidationCheckTest(redisTemplate));
...

What's wrong with it?


Solution

  • It seems like a serialization issue.

    You didn't set a deserializer for your value. So redis uses the default serializaer: JdkSerializationRedisSerializer, which is not good at all. I recommand using Jackson, or just a StringRedisSerializer.

    Probably due to network issues, it receives some incomplete response and the jdk deserializer doesn't recognize it and complains. Add this to your config

    redisTemplate.setValueSerializer(new StringRedisSerializer());

    Also, I suggest you change your code from

    redisTemplate.opfForValue().get("validation");

    to

    redisTemplate.getConnectionFactory().getConnection().ping()

    As the latter is meant for validation.