Spring data redis, multi-threading issue with Jedis

放肆的年华 提交于 2021-02-20 03:45:46

问题


I am using redis in a heavily multi-threaded java application and getting intermittent ClassCastExceptions. Reading through various discussions seemed to point out this might be because the Jedis connection instance getting shared between multiple threads (https://github.com/xetorthio/jedis/issues/359). The solution suggested is to use JedisPool which is thread-safe.

I have configured redis through Spring redis support by using RedisTemplate. A thing to note is I am using multiple templates (to support different models for serialization and de-serialization). Here is snippet of my configuration -

<bean id="jedisConnFactory"
      class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
      redis:usePool="true" redis:poolConfig-ref="jedisPoolConfig" redis:hostName="${redis.datasource.hostName}"
      redis:database="${redis.database.index}" redis:port="${redis.datastore.port}"/>

<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
    <property name="maxIdle" value="${redis.conn.maxIdle}"/>
    <property name="maxTotal" value="${redis.conn.maxTotal}"/>
    <property name="minIdle" value="${redis.conn.minIdle}"/>
    <property name="testOnBorrow" value="true"/>
</bean>

<bean id="redisTemplate"
      class="org.springframework.data.redis.core.RedisTemplate"
      redis:connectionFactory-ref="jedisConnFactory"
      redis:keySerializer-ref="redisStringSerializer"
      redis:valueSerializer-ref="redisStringSerializer"
      redis:defaultSerializer-ref="redisStringSerializer"/>

Note the use of usePool=true which prompts spring to use JedisPool. Looking through spring code also suggests that spring is handling resource allocation and release properly.

Any help identifying the issue will be appreciated.

Edit: Stack trace -

Thread 1:
[ERROR] [03/01/2015 07:05:32.044] [events-system-akka.actor.default-dispatcher-2281] [akka://events-system/user/$YN/$b/$b/$b] java.lang.Long cannot be cast to java.util.List
java.lang.ClassCastException: java.lang.Long cannot be cast to java.util.List
    at redis.clients.jedis.Connection.getRawObjectMultiBulkReply(Connection.java:230)
    at redis.clients.jedis.Connection.getObjectMultiBulkReply(Connection.java:236)
    at redis.clients.jedis.BinaryJedis.zscan(BinaryJedis.java:3608)
    at org.springframework.data.redis.connection.jedis.JedisConnection$3.doScan(JedisConnection.java:2998)
    at org.springframework.data.redis.core.KeyBoundCursor.doScan(KeyBoundCursor.java:39)
    at org.springframework.data.redis.core.ScanCursor.scan(ScanCursor.java:85)
    at org.springframework.data.redis.core.ScanCursor.hasNext(ScanCursor.java:168)
    at org.springframework.data.redis.core.ConvertingCursor.hasNext(ConvertingCursor.java:56)
    ...
    application specific stack trace
    ...

Thread 2:    
[ERROR] [03/01/2015 07:03:07.295] [events-system-akka.actor.default-dispatcher-2273] [akka://events-system/user/$VN/$b/$b/$b] Unknown redis exception; nested exception is java.lang.ClassCastException: [B cannot be cast to java.lang.Long
org.springframework.data.redis.RedisSystemException: Unknown redis exception; nested exception is java.lang.ClassCastException: [B cannot be cast to java.lang.Long
    at org.springframework.data.redis.FallbackExceptionTranslationStrategy.getFallback(FallbackExceptionTranslationStrategy.java:48)
    at org.springframework.data.redis.FallbackExceptionTranslationStrategy.translate(FallbackExceptionTranslationStrategy.java:38)
    at org.springframework.data.redis.connection.jedis.JedisConnection.convertJedisAccessException(JedisConnection.java:195)
    at org.springframework.data.redis.connection.jedis.JedisConnection.zRem(JedisConnection.java:2321)
    at org.springframework.data.redis.core.DefaultZSetOperations$19.doInRedis(DefaultZSetOperations.java:283)
    at org.springframework.data.redis.core.DefaultZSetOperations$19.doInRedis(DefaultZSetOperations.java:280)
    at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:190)
    at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:152)
    at org.springframework.data.redis.core.AbstractOperations.execute(AbstractOperations.java:85)
    at org.springframework.data.redis.core.DefaultZSetOperations.remove(DefaultZSetOperations.java:280)
    ...
    application specific stack trace
    ...
Caused by: java.lang.ClassCastException: [B cannot be cast to java.lang.Long
    at redis.clients.jedis.Connection.getIntegerReply(Connection.java:210)
    at redis.clients.jedis.BinaryJedis.zrem(BinaryJedis.java:1624)
    at org.springframework.data.redis.connection.jedis.JedisConnection.zRem(JedisConnection.java:2319)
    ... 21 more

回答1:


Forgot to post an update on this here.

In my case, my analysis was that the connection pool by default used ForkJoinPool which works in a work-stealing mode. This made another thread take over the results part of the operation over and gave ClassCastException when there was a mismatch in Type of the result.

This did resolve the issue I had.



来源:https://stackoverflow.com/questions/28814502/spring-data-redis-multi-threading-issue-with-jedis

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!