jedis 常見問題

目錄

1.redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out。

2.redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool

3.redis.clients.jedis.exceptions.JedisDataException: MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.

建議


摘錄自我球docs,不需要再寫一份,歡迎技術交流,簡歷投遞:https://github.com/singgel 

 

1.redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out。

生產系統剛開始運行階段,系統穩定。但是運行一段時間後,發現部分時間段系統接口響應變慢。查看客戶端日誌經常會出現這樣的錯誤

 

首先從客戶端反饋的日誌,懷疑是服務器和客戶端間的網絡問題。爲排除這個問題,我們編寫腳本,在客戶端定時ping服務端(redis服務),持續運行一段後,發現未有丟包的情況,排除網絡問題。

 

查看redis服務端日誌,未發現有異常情況。查看redis服務器資源監控,發現每幾分鐘左右,IO會有一波峯值,但是CPU和帶寬壓力都在正常範圍。

 

這裏介紹下我們的redis部署模式:一主一從通過redis clusetr做HA,主從均有開啓持久化。初步懷疑間隔性IO操作佔用資源導致redis讀寫變慢(在此,拋出一個問題:在服務器資源CPU和帶寬均未達到瓶頸的情況下,持續的IO高峯操作是否會影響物理內存的讀寫)。接下來採取的措施是:關閉主庫的持久化,用從庫來做持久化,但是這種模式下存在一個問題,如果主發生故障,主從切換後問題同樣存在,大家有更好的建議可以指點下。

 

運行一段時候,發現問題有所改善,但是依然還是會有time out的情況,只有繼續排查問題。由於redis操作採用單線程,考慮會不會有某些慢查詢導致time out。執行slowlog查看慢查詢語句,發現有大量的keys命令操作,keys命令在大量併發情況下性能非常差,結合官方給出的warning

https://redis.io/commands/keys/

 

正式環境中,儘量避免使用keys,接下來找出使用keys的代碼做優化,至此,time out問題解決。

 

2.redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool

生產環境長時間的運行後,經常會有接口返回數據失敗的情況,或者是從監控上發現數據庫壓力某一時間暴增。查看客戶端日誌發現這樣的錯誤

 

從錯誤日誌看,是提示無法獲取連接。有兩種情況:

 

1、客戶端的連接池滿了,無法創建新的連接

 

檢查客戶端連接最大限制maxActive是否足夠

 

2、redis服務端連接溢出,無法分配新的連接

 

檢查服務端tcp連接:netstat -nat|grep -i "6379"|wc -l

 

檢查服務端連接是否達到最大值:查看服務端支持的最大連接:CONFIG GET maxclients,查看當前服務端建立的   連接:connected_clients

 

通過上述檢查後,發現redis服務端connected_clients連接數持續過高,經常在最大值徘徊。但是結合客戶端配置的最大連接配置maxActive,計算出所有客戶端連接佔滿的情況下最大的連接數也達不到connected_clients的連接數。

 

執行client list命令,發現大量的client的idle時間特別長:

 

正常的client連接,在持續使用的情況下,是不可能空閒這麼長時間,連接長時間空閒,客戶端也會關閉連接。

 

查看redis服務端下面兩項配置:

 

        timeout:client連接空閒多久會被關閉(這個配置容易被誤導爲:連接超時和操作執行超時)

 

        tcp-keepalive:redis服務端主動向空閒的客戶端發起ack請求,以判斷連接是否有效

 

檢查上述配置發現 timeout和tcp-keepalive均未啓用(均爲0),這種情況下,redis服務端沒有有效的機制來確保服務端已經建立的連接是否已經失效。當服務器和客戶端網絡出現閃斷,導致tcp連接中斷,這種情況下的client將會一直被redis服務端所持有,就會出現上面我們看到的idle時間特長的client連接。

 

接下來設置timeout和tcp-keepalive來清理失效的連接。

如果redis服務端未設置timeout,客戶端會如何處理長時間未使用的連接?

這個問題可以從分析redis的sdk源碼查找答案,不過這個過程會比較枯燥。

接下來我們直接通過抓取客戶端和服務端的tcp數據包來獲取答案:

這裏我用wireshark來抓取中間的tcp數據包,抓取一個完整的redis連接(從發起到結束)的tcp數據包

從tcp3次握手建立連接,到最後客戶端發送reset包給服務端終止了這個連接。

追蹤整個tcp的數據流:

*2
$4
AUTH
$8
password
+OK
*1
$4
PING
+PONG
*1
$4
PING
+PONG
*1
$4
QUIT
+OK

從tcp數據流可以看出,整個tcp連接中間經歷的操作:

        1、客戶端發送密碼建立連接,服務端響應OK

        2、客戶端發送PING命令校驗連接,服務端響應PONG表示成功

        3、客戶端再次發送PING命令校驗連接,服務端響應PONG表示成功

        4、客戶端發送QUIT命令退出連接,服務端響應OK表示退出成功

當服務端響應QUIT命令OK後,客戶端發送RESET的tcp包終止整個tcp連接。中間客戶端發起了兩次PING命令校驗連接和一次QUIT命令來退出連接,每次間隔30s,加起來整個連接存活了90s。

 

上面問題中提到的數據庫某一時間壓力暴增,是由於在緩存模式下,redis請求失敗,請求的壓力瞬間集中到數據庫。

 

 

3.redis.clients.jedis.exceptions.JedisDataException: MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.

突然間服務不能訪問,返回錯誤

從錯誤提示,可以看出是向磁盤保存數據失敗。引起這個問題的原因一般是內存不足,但是生產環境我們一般都會爲系統分配足夠的內存運行,而且查看內存情況也顯示還有可用內存。

查看redis日誌,發現有這個錯誤:Can’t save in background: fork: Cannot allocate memory

redis在保存內存的數據到磁盤時,爲了防止主進程假死,會Fork一個子進程來完成這個保存操作。但是這個Fork的子進程會需要分配和主進程相同的內存,這時候就相當於需要的內存double了,如果這時候可用內存不足以分配需要的內存,將會導致Fock子進程失敗而無法保存數據到磁盤。

修改linux內核參數:vm.overcommit_memory=1。至此,問題解決。

overcommit_memory有三種取值:0, 1, 2

        0::檢查是否有足夠的可用內存供進程使用;有則允許申請,否則,內存申請失敗,並把錯誤返回給應用進程;

        1:表示內核允許分配所有的物理內存,而不管當前的內存狀態如何;

        2:表示內核允許分配超過所有物理內存和交換空間總和的內存。

 

 

 

建議

1、結合實際使用場景,考慮是否需要用到redis的持久化,如果單純用來做應用層的緩存(在緩存未命中的情況下訪問數據庫),可以關閉持久化。

2、緩存模式下,儘量爲每塊緩存設置時效性,避免冷數據長時間佔用資源。

3、生產環境中儘量避免使用keys操作,由於redis是單線程模式,大量的keys操作會阻塞其他的命令執行。

4、設置合理的內存回收策略,保證內存可用性的同時能適當的提供緩存的命中率。

5、提前計算出系統可能會用的內存大小,合理的分配內存。需要注意在開啓持久化模式下,需要預留更多的內存提供給Fock的子進程做數據磁盤flush操作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章