redis 服務(wù)基本上坑不多,基本上注意一下幾點:
- 主動設(shè)置 key 過期時間
- 注意不要有大 key
最近遇到了一個新的問題,查看了 redis 源碼和文檔,發(fā)現(xiàn)代碼設(shè)計上存在另一個坑。
背景
場景: redis 實例啟動的時候,自動加載 aof 文件,如果文件超過 6G,加載需要 5分鐘。
啟動時,redis 會先監(jiān)聽端口,再進行 aof 數(shù)據(jù)加載,以便于客戶端及時掌握redis的加載進度。
加載 aof 時,ping 命令會返回 LOADING,此時redis 不可讀也不可寫。
如果他是主節(jié)點,主節(jié)點 loading=1, 客戶端的狀態(tài) master_link_status=down
如果他是從節(jié)點, loading=1, master_link_status=err, flags=slaves
一般 redis 驅(qū)動只有判斷 flags 為 s_down o_down disconnected 這三種狀態(tài)判斷節(jié)點不可用。
問題:loading 時, redis 和 sentinel 都認為此節(jié)點可正常提供服務(wù),其實這個時候不可讀也不可寫。
從節(jié)點
情景1: loading 數(shù)據(jù)節(jié)點為從節(jié)點,客戶端做了讀寫分離
問題:多數(shù)客戶端的驅(qū)動只檢測端口,不檢測loading狀態(tài),會認為此節(jié)點為正常節(jié)點,導致部分業(yè)務(wù)讀數(shù)據(jù)失敗。
改進思路:
- sentinel 判斷為 loading 的狀態(tài)認為此節(jié)點不可用。
- 客戶端驅(qū)動判斷 loading 節(jié)點為不可用
- redis 先加載數(shù)據(jù),后監(jiān)聽端口
我們的做法: 修改驅(qū)動代碼,客戶端判斷 redis 節(jié)點為 flags=slave and master-link-status=err 狀態(tài)時,判斷此從節(jié)點不可用。
主節(jié)點
情景2:loading 數(shù)據(jù)節(jié)點為主節(jié)點,客戶端沒做讀寫分離,讀寫都在主節(jié)點
問題:sentinel 認為該主節(jié)點為正常狀態(tài),不做故障轉(zhuǎn)移,導致所有業(yè)務(wù)讀寫都失敗。
改進思路:
- sentinel 判斷為 loading 的狀態(tài)認為此節(jié)點不可用,主動進行故障轉(zhuǎn)移
- redis 先加載數(shù)據(jù),后監(jiān)聽端口
總結(jié):
- 監(jiān)控 master_link_status 的狀態(tài),還可以監(jiān)控 loading 的狀態(tài),發(fā)現(xiàn)異常情況及時告警。
- redis 加載 AOF 為異步操作,嘗試修改代碼先加載數(shù)據(jù)后監(jiān)聽端口,最后還是端口先監(jiān)聽,此路不可行。
- 讀寫分離的節(jié)點,可以通過修改驅(qū)動來剔除loading的從節(jié)點。
- 主動設(shè)置 key 的過期時間可以有效的降低 aof 的大小,從而縮短加載時間來規(guī)避問題。
- 對于節(jié)點為 loading 的狀態(tài),通過修改 sentinel 的判斷邏輯來解決此問題,將此節(jié)點設(shè)置為 o_down。
參考:
https://github.com/scenbuffalo/redis/commit/840df3c9dc88de671ae294f4942ec5fd62c456b7 說明:此補丁在 5.0 不適用