redis 簡單整理——客戶端常見異常[十七]
前言
這個還是比較常見的,也就是比較對開發有用的部分。
正文
1.無法從連線池獲取到連線
JedisPool中的Jedis物件個數是有限的,預設是8個。這裡假設使用的默 認配置,如果有8個Jedis物件被佔用,並且沒有歸還,此時呼叫者還要從 JedisPool中借用Jedis,就需要進行等待(例如設定了maxWaitMillis>0),如 果在maxWaitMillis時間內仍然無法獲取到Jedis物件就會丟擲如下異常:
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool … Caused by: java.util.NoSuchElementException: Timeout waiting for idle object at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool. java:449)
還有一種情況,就是設定了blockWhenExhausted=false,那麼呼叫者發現 池子中沒有資源時,會立即丟擲異常不進行等待,下面的異常就是 blockWhenExhausted=false時的效果:
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool … Caused by: java.util.NoSuchElementException: Pool exhausted at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool. java:464)
可能的原因:
客戶端:
1. 客戶端:高併發下連線池設定過小,出現供不應求,所以會出現上面 的錯誤,但是正常情況下只要比預設的最大連線數(8個)多一些即可,因 為正常情況下JedisPool以及Jedis的處理效率足夠高。
2. 客戶端:沒有正確使用連線池,比如沒有進行釋放
3. 客戶端:存在慢查詢操作,這些慢查詢持有的Jedis物件歸還速度會比 較慢,造成池子滿了。
服務端:
服務端:客戶端是正常的,但是Redis服務端由於一些原因造成了客戶 端命令執行過程的阻塞,也會使得客戶端丟擲這種異常。
2.客戶端讀寫超時
造成該異常的原因也有以下幾種: ·讀寫超時間設定得過短。 ·命令本身就比較慢。 ·客戶端與服務端網路不正常。 ·Redis自身發生阻塞。
- 客戶端連線超時
-1. 連線超時設定得過短
-2. Redis發生阻塞,造成tcp-backlog已滿,造成新的連線失敗。
-3. 客戶端與服務端網路不正常。
- 客戶端緩衝區異常
造成這個異常的原因可能有如下幾種:
1)輸出緩衝區滿。例如將普通客戶端的輸出緩衝區設定為1M,如果使用get命令獲取一個bigkey(例如3M),就會出現這個異常。
2)長時間閒置連線被服務端主動斷開
- 不正常併發讀寫:Jedis物件同時被多個執行緒併發操作,可能會出現 上述異常
5.Lua指令碼正在執行
如果Redis當前正在執行Lua指令碼,並且超過了lua-time-limit,此時Jedis呼叫Redis時,會收到下面的異常。
這個時候使用kill script
- Redis正在載入持久化檔案
Jedis呼叫Redis時,如果Redis正在載入持久化檔案
- Redis使用的記憶體超過maxmemory配置
Jedis執行寫操作時,如果Redis的使用記憶體大於maxmemory的設定,會 收到下面的異常,此時應該調整maxmemory並找到造成記憶體增長的原因
- 客戶端連線數過大
如果客戶端連線數超過了maxclients,新申請的連線就會出現如下異常
解決方案:
客戶端:如果maxclients引數不是很小的話,應用方的客戶端連線數基 本不會超過maxclients,通常來看是由於應用方對於Redis客戶端使用不當造 成的。此時如果應用方是分散式結構的話,可以通過下線部分應用節點(例 如佔用連線較多的節點),使得Redis的連線數先降下來。從而讓絕大部分 節點可以正常執行,此時再通過查詢程式bug或者調整maxclients進行問題的修復
服務端: 如果此時客戶端無法處理,而當前Redis為高可用模式(例如 Redis Sentinel和Redis Cluster),可以考慮將當前Redis做故障轉移。
結
下一節redis 常見案例分析。