Big Key 導致 Redis 頻繁重連的問題排查

背景

監控是系統的重要模塊,我們給產線的 Redis 機器配置了全方位的監控,包括機器性能指標測試以及 Redis 服務測試等等。今天收到了 PagerDuty 告警,報告說 Redis 服務間歇性異常。

問題描述

Redis 是一個集羣,三主三從,每個節點各配置了一個監控,監控的測試邏輯大致是,用 INFOCLUSTER SLOTSCLUSTER NODES 等命令查看節點以及集羣的基本信息是否正常,然後給主節點(master) set 一個 dummy key,看是否在規定時間內能同步到從節點(slave)。 報警來自於一臺從節點,觀察了一下報錯信息:

Redis is loading the dataset in memory

問題定位

上述提示可能在以下兩種情況出現:

  1. 當主節點啓動的時候
  2. 當從節點跟主節點重連進行全量數據同步的時候

也就是說,當數據集(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 的內存監控圖表: redis_memory

可以看到,從 23 號開始,目標節點的內存開始出現異常升高,但因爲每個節點的內存限制是 16G,所以內存指標並沒有報警,反而是服務先出現了異常。 23 號正好是我們上線的日期,所以問題大概率與新功能有關了。查了一下,這次確實新增了一些 Redis 的緩存數據,格式大概是 hash_service_statistic:{serviceId},記錄的是 service 的一些統計數據。不過按道理數據會根據 serviceId 不同而被打散,但爲什麼新增的數據似乎都被分配到同一個節點上了呢?原來產線上的 serviceId 值未被初始化,都是 0,這是一個未開發完全的功能,此次上線的只是數據聚合的部分。所以圖中顯示的增長的大約 5G 數據,其實都是來自於同一個 key hash_service_statistic:0,妥妥的 Big Key 了。

由於 key 太大,導致了對應節點數據複製緩慢,在 TPS 較高的情況下,從節點間斷性重連,並且因爲數據落後主節點過多會進行全量數據同步(默認的 repl-backlog-size1MB),導致出現 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

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