Redis 大key(bigkey)問題的排查與解決方案

王鯨弋發表於2020-12-15

業務中遇到一個神奇的問題:Redis的一個key設定過期時間以後,這個key就消失了。通過命令列復現了這個問題:設定過期時間以後,這個key就消失了

什麼是 bigkey ?

Bigkey是指當Redis 的字串型別過大,非字串型別元素過多。

bigkey 帶來了什麼危害?

  1. Redis 阻塞^1 :因為 Redis 單執行緒特性,如果操作某個 Bigkey 耗時比較久,則後面的請求會被阻塞。
  2. 記憶體空間不均勻^1 :比如在 Redis cluster 或者 codis 中,會造成節點的記憶體使用不均勻。
  3. 過期時可能阻塞^1 :如果 Bigkey 設定了過期時間,當過期後,這個 key 會被刪除,假如沒有使用 Redis 4.0 的過期非同步刪除,就會存在阻塞 Redis 的可能性,並且慢查詢中查不到(因為這個刪除是內部迴圈事件)。
  4. 導致傾斜^2 :某個例項上正好儲存了 bigkey。bigkey 的 value 值很大(String 型別),或者是 bigkey 儲存了大量集合元素(集合型別),會導致這個例項的資料量增加,記憶體資源消耗也相應增加。例項的處理壓力就會增大,速度變慢,甚至還可能會引起這個例項的記憶體資源耗盡,從而崩潰。

如何排查 Redis 的 bigkey?

Redis 可以在執行 redis-cli 命令時帶上–bigkeys 選項,進而對整個資料庫中的鍵值對大小情況進行統計分析,比如說,統計每種資料型別的鍵值對個數以及平均大小。此外,這個命令執行後,會輸出每種資料型別中最大的 bigkey 的資訊,對於 String 型別來說,會輸出最大 bigkey 的位元組長度,對於集合型別來說,會輸出最大 bigkey 的元素個數,如下所示:``。

redis-cli -h xxxxxx.redis.rds.aliyuncs.com -a shiliName:password --bigkeys
# Scanning the entire keyspace to find biggest keys as well as
# average sizes per key type.  You can use -i 0.1 to sleep 0.1 sec
# per 100 SCAN commands (not usually needed).


[00.00%] Biggest string found so far 'comment_video_commentInfos_1480216061_1921681272_19620_104338970_203_55' with 419 bytes
.
.
.
[97.13%] Biggest string found so far 'apiFindSetAll:' with 400577 bytes

-------- summary -------

Sampled 22748641 keys in the keyspace!
Total key length in bytes is 810624573 (avg len 35.63)

Biggest string found 'apiFindSetAll:' has 400577 bytes
Biggest   list found 'bbb/xxx:0' has 9737534 items
Biggest    set found 'vl_mixxx:im:xxx_history_members:live-chat-23201' has 3989 members
Biggest   hash found 'xxx::iblue::group::star::listInfo' has 5063 fields
Biggest   zset found 'xxxx:data_id:260917' has 30649 members

22627532 strings with 4682556354 bytes (99.47% of keys, avg size 206.94)
103 lists with 10110292 items (00.00% of keys, avg size 98158.17)
12668 sets with 36132 members (00.06% of keys, avg size 2.85)
16328 hashs with 44235 fields (00.07% of keys, avg size 2.71)
92010 zsets with 510359 members (00.40% of keys, avg size 5.55)

bigkey 怎麼處理?

  1. 刪除 bigkey ^2 :不過,非同步刪除操作是 Redis 4.0 以後才有的功能,如果你使用的是 4.0 之前的版本,當你遇到 bigkey 刪除時,我給你個小建議:先使用集合型別提供的 SCAN 命令讀取資料,然後再進行刪除。因為用 SCAN 命令可以每次只讀取一部分資料並進行刪除,這樣可以避免一次性刪除大量 key 給主執行緒帶來的阻塞。例如,對於 Hash 型別的 bigkey 刪除,你可以使用 HSCAN 命令,每次從 Hash 集合中獲取一部分鍵值對(例如 200 個),再使用 HDEL 刪除這些鍵值對,這樣就可以把刪除壓力分攤到多次操作中,那麼,每次刪除操作的耗時就不會太長,也就不會阻塞主執行緒了
  2. 拆分 ^1:有時也可以考慮對 Bigkey 進行拆分,具體方法如下:對於 string 型別的 Bigkey,可以考慮拆分成多個 key-value。對於 hash 或者 list 型別,可以考慮拆分成多個 hash 或者 list。
  3. 不用Redis:Redis對於長文字不是最優的,可考慮文件型資料庫如:MongoDB等

原文發表在CSDN:Redis 大key(bigkey)問題的排查與解決方案

本作品採用《CC 協議》,轉載必須註明作者和本文連結
善始善終 嗯!

相關文章