Jedis是Redis的Java客戶端實現,封裝了對Redis的通訊和命令處理等。html
Jedis提供了資源池,能夠很方便地實現對Redis的API調用。java
以前是經過組內對Jedis封裝的Spring Bean來獲取和使用Jedis的,如今但願自行實現相似功能,設計目標以下:nginx
具體思路就是針對設計目標而定的:git
因爲需求比較基礎,尚未太多應用場景,實現也沒考慮太複雜。總體邏輯不到50行,能夠在個人GitHub上大體看一下。github
後續使用能夠直接使用Spring將Bean注入。redis
因爲不按常規方法使用JedisPool可能背離了JedisPool設計的使用場景,所以在其中踩了很多坑。瀏覽器
其次,雖然日常經常使用組內的Jedis組件,但實際上對Jedis的API不瞭解,本次根據日常使用過程當中的一些感覺進行「黑盒臨摹」,在爬坑過程當中其實也學習了其餘一些方面的經驗,好比Guava Reflections等。安全
背景微信
最開始經過FactoryBean提供的鏈接並未使用動態代理,也就是說僅提供了一個Jedis,全部線程使用同一個Jedis鏈接。多線程
現象
業務中較頻繁地報異常,異常信息爲java.lang.ClassCastException: java.util.ArrayList cannot be cast to [B
等,基本是ClassCastException
,異常拋出位置爲調用Jedis的位置。
OK
、NIL
等響應,但這種bug過低級了,不該該出如今Jedis這種久經考驗的庫中,排除;緣由
最終在另外一篇資料指引下來到jedis/issues,在參考資料中發現了最可信最合理的緣由:Jedis並不是線程安全,不該當併發操做。
正確使用
Single connection. Single thread.
正如參考資料中回答提到的,每一個線程(每次調用)都從JedisPool中獲取一個鏈接,並在使用後歸還。
也正是由於這一點跟最初的FactoryBean封裝方式衝突了,後來才改用提供動態代理類的方式封裝FactoryBean。
背景
我使用的Jedis版本爲3.0.1,網上的很多資料指出在使用鏈接後歸還可使用JedisPool的void returnResource(Jedis resource)
方法,但在3.0.1版本中這個方法是protected可見的,沒有間接調用方法。
另外Jedis源碼中找不到註釋,這有點奇怪,我想固然地認爲版本升級後能夠自動歸還資源了,因而僅在設置最大鏈接數以後就部署到業務中了。
現象
業務線程啓動後每訪問必定次數(調用Jedis達到必定次數)後就徹底不響應請求了:
仍是在參考資料的指引下查看Tomcat監聽的端口,的確不少鏈接處於CLOSE_WAIT
狀態,代表客戶端已斷開鏈接(我本身測試的時候刷新頁面太多,不少就中途斷開了)。
緣由
結合TCP四次揮手過程,應該是中間有資源釋放不了致使沒有進入LAST_ACK
狀態,推測是Jedis鏈接資源未歸還而總鏈接數有限制,致使不少線程在等待獲取Jedis資源。
正確使用
在Jedis鏈接使用完畢後,須要調用Jedis的close()
方法將資源歸還JedisPool,close
方法是用於替代returnResource
方法的。
這個方法語義比較奇怪,真實做用是「歸還或關閉鏈接」,最開始其實就是考慮到資源複用的問題纔沒有考慮使用這個close
方法的。
對比了一下組內的組件,思路差很少,還有如下的點可以擴展:
ClassCastException - B cannot be cast to java.lang.Long · Issue #186 · xetorthio/jedis
nginx 499狀態碼 - 微信-大數據從業者 - 博客園
深刻分析Tomcat無響應問題及解決方法 - 月下狼的我的頁面 - OSCHINA
jedis:鏈接池(JedisPool)使用示例 - 10km的專欄 - CSDN博客
Jedis使用|returnBrokenResource|returnResource廢棄替代 - 詩人不寫詩 - CSDN博客
本文搬自個人博客,歡迎參觀!