背景
監控是系統的重要模塊,我們給產線的 Redis 機器配置了全方位的監控,包括機器性能指標測試以及 Redis 服務測試等等。今天收到了 PagerDuty 告警,報告說 Redis 服務間歇性異常。
問題描述
Redis 是一個集羣,三主三從,每個節點各配置了一個監控,監控的測試邏輯大致是,用 INFO
,CLUSTER SLOTS
,CLUSTER NODES
等命令查看節點以及集羣的基本信息是否正常,然後給主節點(master) set
一個 dummy key,看是否在規定時間內能同步到從節點(slave)。 報警來自於一臺從節點,觀察了一下報錯信息:
Redis is loading the dataset in memory
問題定位
上述提示可能在以下兩種情況出現:
- 當主節點啓動的時候
- 當從節點跟主節點重連進行全量數據同步的時候
也就是說,當數據集(dataset)還未被全部加載進內存中時,如果客戶端給 Redis 發送命令,則會收到上述錯誤提示。考慮到報錯的是一臺從節點,所以是第二種情況:從節點頻繁跟主節點重連。
連上告警的節點,執行 INFO MEMORY
,連續幾次的關鍵信息如下:
redis> info memory
# Memory
used_memory_human:53.27M
used_memory_peak_human:9.68G
used_memory_peak_perc:0.54%
maxmemory_human:16.00G
redis> info memory
# Memory
used_memory_human:2.19G
used_memory_peak_human:9.68G
used_memory_peak_perc:22.63%
maxmemory_human:16.00G
redis> info memory
# Memory
used_memory_human:4.13G
used_memory_peak_human:9.68G
used_memory_peak_perc:42.69%
maxmemory_human:16.00G
redis> info memory
# Memory
used_memory_human:7.15G
used_memory_peak_human:9.68G
used_memory_peak_perc:73.88%
maxmemory_human:16.00G
redis> info memory
# Memory
used_memory_human:9.50G
used_memory_peak_human:9.68G
used_memory_peak_perc:98.08%
maxmemory_human:16.00G
直觀可以看到,節點在持續加載數據直到內存升到 9.5G
左右,過程持續大約一分鐘。穩定一小段時間之後,又重複數據加載的過程。
問題排查
首先我們考慮是不是節點所在的物理機有問題,於是用 CLUSTER FAILOVER
強制做了主從切換,觀察一段時間發現,原先告警的節點升爲主節點之後狀態就正常了,而原先正常的主節點變爲從節點之後開始告警。說明問題與機器無關,跟主從關係有關。
我們開始將關注點主從複製,有一個細節:Redis 節點的最高內存佔用是 9.68G,而按照之前我們的印象應該是 5G 左右,於是我們去查看了 Redis 的內存監控圖表:
可以看到,從 23 號開始,目標節點的內存開始出現異常升高,但因爲每個節點的內存限制是 16G,所以內存指標並沒有報警,反而是服務先出現了異常。 23 號正好是我們上線的日期,所以問題大概率與新功能有關了。查了一下,這次確實新增了一些 Redis 的緩存數據,格式大概是 hash_service_statistic:{serviceId}
,記錄的是 service 的一些統計數據。不過按道理數據會根據 serviceId
不同而被打散,但爲什麼新增的數據似乎都被分配到同一個節點上了呢?原來產線上的 serviceId
值未被初始化,都是 0,這是一個未開發完全的功能,此次上線的只是數據聚合的部分。所以圖中顯示的增長的大約 5G
數據,其實都是來自於同一個 key hash_service_statistic:0
,妥妥的 Big Key 了。
由於 key 太大,導致了對應節點數據複製緩慢,在 TPS 較高的情況下,從節點間斷性重連,並且因爲數據落後主節點過多會進行全量數據同步(默認的 repl-backlog-size
是 1MB
),導致出現 Redis is loading the dataset in memory。
問題解決
將 Big Key 刪除,然後將 serviceId
初始化一遍。
redis> del hash_service_statistic:0
-> Redirected to slot [7924] located at *.*.*.*:7001
(integer) 1
(43.94s)
key 的刪除都花了 43.94 秒...
總結
又是一個深刻的教訓:線上出問題,很多時候與新上的 feature 有關。 用 Redis Cluster 做緩存時要謹防 Big Key 的出現,儘量將 Key 打散在各個節點中。 產線的服務需要配置好全方位的監控,合理的監控可以在真正嚴重的問題出現之前就給予告警。
參考
ERROR: LOADING Redis is loading the dataset in memory
Redis Replication