RedisPool的TestOnBorrow,TestOnReturn的坑


轉載:https://blog.csdn.net/qq403580298/article/details/82937579

今天嘗試Redis的分布式鎖,因為沒有分布式環境,使用多線程來代替,但是在使用多線程的時候,總是會有

redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketException: Socket closed或者

 
1
2
3
4
5
6
7
8
Caused by: redis.clients.jedis.exceptions.JedisException: Could not  return  the resource to the pool
     at redis.clients.util.Pool.returnResourceObject(Pool.java: 69 )
     at redis.clients.jedis.JedisPool.returnResource(JedisPool.java: 253 )
     ...  14  more
Caused by: java.lang.IllegalStateException: Object has already been returned to  this  pool or is invalid
     at org.apache.commons.pool2.impl.GenericObjectPool.returnObject(GenericObjectPool.java: 538 )
     at redis.clients.util.Pool.returnResourceObject(Pool.java: 67 )
     ...  15  more
 
1
2
3
4
5
6
7
8
9
10
redis.clients.jedis.exceptions.JedisDataException: ERR Protocol error: invalid bulk length
     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.getStatusCodeReply(Connection.java: 239 )
     at redis.clients.jedis.Jedis.set(Jedis.java: 139 )
     at com.sunxj.redis.DistributeLock.lock(DistributeLock.java: 85 )
     at com.sunxj.redis.DistributedLockTest.lambda$createThread$ 0 (DistributedLockTest.java: 32 )
     at java.lang.Thread.run(Thread.java: 748 )

  

1
2
3
4
5
6
7
Exception in thread  "Thread-71"  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.lpop(Jedis.java: 1055 )
     at us.codecraft.webmagic.scheduler.RedisScheduler.poll(RedisScheduler.java: 77 )
     at us.codecraft.webmagic.Spider.run(Spider.java: 308 )
     at java.lang.Thread.run(Thread.java: 748 )

  

主要問題就是在於Redis是一個單線程,多線程操作的話就會產生錯誤。首先看了一下Jconsole,發現大多數的線程都是Block狀態

 但是他們運行的特別慢,看了一下Runnable的線程,

可以發現線程卡在了SocketRead,name可以斷定是Redis的問題,redis一直被卡住,所以才非常慢。

通過查閱論壇和搜索,可以知道是因為set函數被掛起了,導致最后set不成功。前輩的解釋:

查看 Jedis 源碼發現它的Connection中對網絡輸出流做了一個封裝(RedisInputStream),其中自建了一個buffer。當發生異常的時候,這個buffer里還殘存着上次沒有發送或者發送不完整的命令。這個時候沒有做處理,直接將該連接返回到連接池,那么重用該連接執行下次命令的時候,就會將上次沒有發送的命令一起發送過去,所以才會出現上面的錯誤“返回值類型不對”。

而如果我們配置了TestOnBorrow或者TestOnReturn,就會檢測這是不是一個活的jedis。但是高並發下就會很多失敗,就沒有一些所以會被一直卡住,無法從redis獲得數據。(不知道解釋的對不對)有知道答案的請告訴我。。。

那我們應該怎么辦呢?

1. 最簡單的辦法就是為每一個線程建立一個jedis對象,並且lock或者release的的方法傳入jedis。

2. 但是這樣總是覺得很別扭,應為這是線程池的問題,因此,我們可以將TestOnBorrow或者TestOnReturn都設置為false,同時如果set或者release失敗了,我們直接返回,就不等待了!

兩種方法都可以的。 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM