问题
I am using redis in a heavily multi-threaded java application and getting intermittent ClassCastException
s. 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