"Could not get a resource from the pool org.springframework.data.redis.RedisConnectionFailureException: Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool" 和 "Connect timed out」
複製代碼
爲何redis 的keys 會致使服務拿不到資源,而且咱們有連接池,咱們帶着這樣的問題,咱們來剖析一下java
從Jedis 中jar 包查看有三種連接池, 選擇哪一個連接池取決於你的Redis的環境redis
- JedisPool-單節點模式
- JedisSentinelPool - 哨兵模式
- ShardedJedisPool-集羣共享模式
咱們的服務用的哨兵模式,對於這幾種的redis 連接池的實現方式 請下載源碼自行查看,這塊不是這篇文章的重點算法
咱們經過下面的圖來看一下連接池的建立基本流程spring
看這個圖以前請先了解 common-pool2 實現池的概念和相關參數的解釋【下次有時間我在講解一下這塊的源碼】數據庫
先展現一下咱們系統的相關配置 和 這些配置對應的解釋網絡
因爲 redis單進程單線程的模式,當咱們使用keys 的時候查詢很慢的時候,勢必會阻塞後面client鏈接從而報獲取不到資源, 這裏面的前提條件是通過覈實 redis 的鏈接數是沒有達到咱們設置的鏈接池的最大數的併發
這裏面有個最大的疑問是,我都已經有鏈接池而且沒有達到你設置的最大的鏈接池數量,爲何報拿不到鏈接池的資源或則是鏈接超時呢,其實這裏面最關鍵的配置是 max-idle和max-wait,so way, 其實經過上面的鋪墊的知識就能夠得出 redis 是單進程單線程 而且默認是FIFO排隊機制,當個人最大空閒資源耗盡的時候須要經過TCP 方式 和 Redis Server 創建鏈接,同時因爲keys 操做很耗時 因此這個建立在阻塞的而且當達到咱們max-wait 就會返回 獲取不到鏈接池的資源或則是鏈接超時。運維
經過上面的結論 咱們是否能夠認爲 調整 max-idle 和 max-wait 的設置 就能夠解決這個問題,這個答案是否認的,只有解決性能問題纔是最終解決方案。tcp
Redis 這種特性用不用鏈接池都同樣?post
雖然基於內存的Redis數據庫有着超高的性能,可是底層的網絡通訊卻佔用了一次數據請求的大量時間,由於每次數據交互都須要先創建鏈接,假設一次數據交互總共用時30ms,超高性能的Redis數據庫處理數據所花的時間可能不到1ms,也便是說前期的鏈接佔用了29ms,jedis直連方式,也就是每次new jedis都會新建tcp鏈接,使用後再斷開鏈接,這對於頻繁訪問redis的場景顯然不是高效的使用方式。鏈接池則能夠實如今客戶端創建多個連接而且不釋放,當須要使用鏈接的時候經過必定的算法獲取已經創建的鏈接,使用完了之後則還給鏈接池,這就免去了數據庫鏈接所佔用的時間。所以,一般會使用鏈接池的方式對Jedis鏈接進行管理,全部jedis對象會預先放在池子中(JedisPool),每次要鏈接redis,只須要在池子中借,用完了再歸還給池子。客戶端鏈接Redis使用的是TCP協議,直連的方式每次須要創建TCP鏈接,而鏈接池的方式是能夠預先初始化好jedis鏈接,每次只須要從jedis鏈接池借用便可,借用和歸還操做是在本地進行的,只有少許的併發同步開銷,遠遠小於新建tcp鏈接的開銷。此外,鏈接池的方式能夠有效保護和控制資源的使用,而直連的方式沒法限制jedis對象的個數,而且可能存在鏈接泄漏的狀況。
對於咱們鏈接哨兵模式 若是某一個節點掛掉了會不會出現 獲取不到鏈接池和超時呢?且聽下回分解
做者:易企秀工程師 henry_chen