問題描述
使用jedis sdk訪問redis時,有時會拋如下異常
java.lang.ClassCastException: java.lang.Long cannot be cast to [B
at redis.clients.jedis.Connection.getBinaryBulkReply(Connection.java:259)
at redis.clients.jedis.Connection.getBulkReply(Connection.java:248)
at redis.clients.jedis.Jedis.hget(Jedis.java:674)
有時可能還會伴隨着超時異常:
redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out
at redis.clients.util.RedisInputStream.ensureFill(RedisInputStream.java:202)
at redis.clients.util.RedisInputStream.readByte(RedisInputStream.java:40)
at redis.clients.jedis.Protocol.process(Protocol.java:151)
at redis.clients.jedis.Protocol.read(Protocol.java:215)
at redis.clients.jedis.Connection.readProtocolWithCheckingBroken(Connection.java:340)
at redis.clients.jedis.Connection.getBinaryBulkReply(Connection.java:259)
at redis.clients.jedis.Connection.getBulkReply(Connection.java:248)
at redis.clients.jedis.Jedis.hget(Jedis.java:674)
原因&解決
主要有以下三類原因:
-
一個jedis連接在使用時拋出異常(如超時異常)后被返回連接池,這個連接下次使用時就可能跑類似異常,具體跟sockt buffer有上次請求數據的有關,參考鏈接1。
針對這種情況,需要將jedis正確close,有些文章可能會說需要調用returnBrokenResource方法,這已經是個遠古方法了,至少在2.9.0以上,直接close即可,如果進行了異常捕獲,則需要在finally中進行close。
-
多線程訪問jedis對象
根據jedis的文檔,JedisPool線程安全而Jedis非線程安全,檢查代碼是否有多線程邏輯。
-
redis集群資源負載重、寫滿等
我這里就是這個原因,代碼中對redis先讀后寫,不停拋這個異常。如果注釋掉寫,只讀運行沒問題。注釋掉讀,就開始拋下面的異常,這種負載重拋異常的情況在鏈接2的issue也有人提及。
redis.clients.jedis.exceptions.JedisDataException: ERR at redis.clients.jedis.Protocol.processError(Protocol.java:127) at redis.clients.jedis.Protocol.process(Protocol.java:161) at redis.clients.jedis.Protocol.read(Protocol.java:215) at redis.clients.jedis.Connection.readProtocolWithCheckingBroken(Connection.java:340) at redis.clients.jedis.Connection.getOne(Connection.java:322) at redis.clients.jedis.ShardedJedisPipeline.sync(ShardedJedisPipeline.java:44)
最后找運維申請了個新redis就正常讀寫了,如果你們redis是自己的維護的,就檢查下日志吧。