博客 / 詳情

返回

Redis大key有什麼危害?如何排查和處理?

這個問題在面試中還是比較容易遇到的,尤其是在考察 Redis 性能優化相關知識點的時候。

通常情況下,問了 bigkey(大 Key)還會繼續問 hotkey(熱 Key)。即使不準備面試也建議看看,實際開發中也能夠用到(hotkey 相關的內容會在下一篇文章中提到)。

什麼是 bigkey?

簡單來説,如果一個 key 對應的 value 所佔用的內存比較大,那這個 key 就可以看作是 bigkey。具體多大才算大呢?有一個不是特別精確的參考標準:

  • String 類型的 value 超過 1MB
  • 複合類型(List、Hash、Set、Sorted Set 等)的 value 包含的元素超過 5000 個(不過,對於複合類型的 value 來説,不一定包含的元素越多,佔用的內存就越多)。

bigkey 判定標準

bigkey 是怎麼產生的?有什麼危害?

bigkey 通常是由於下面這些原因產生的:

  • 程序設計不當,比如直接使用 String 類型存儲較大的文件對應的二進制數據。
  • 對於業務的數據規模考慮不周到,比如使用集合類型的時候沒有考慮到數據量的快速增長。
  • 未及時清理垃圾數據,比如哈希中冗餘了大量的無用鍵值對。

bigkey 除了會消耗更多的內存空間和帶寬,還會對性能造成比較大的影響。

在 Redis 常見阻塞原因總結這篇文章中我們提到:大 key 還會造成阻塞問題。具體來説,主要體現在下面三個方面:

  1. 客户端超時阻塞:由於 Redis 執行命令是單線程處理,然後在操作大 key 時會比較耗時,那麼就會阻塞 Redis,從客户端這一視角看,就是很久很久都沒有響應。
  2. 網絡阻塞:每次獲取大 key 產生的網絡流量較大,如果一個 key 的大小是 1 MB,每秒訪問量為 1000,那麼每秒會產生 1000MB 的流量,這對於普通千兆網卡的服務器來説是災難性的。
  3. 工作線程阻塞:如果使用 del 刪除大 key 時,會阻塞工作線程,這樣就沒辦法處理後續的命令。

大 key 造成的阻塞問題還會進一步影響到主從同步和集羣擴容。

綜上,大 key 帶來的潛在問題是非常多的,我們應該儘量避免 Redis 中存在 bigkey。

如何發現 bigkey?

1、使用 Redis 自帶的 --bigkeys 參數來查找。

# redis-cli -p 6379 --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 '"ballcat:oauth:refresh_auth:f6cdb384-9a9d-4f2f-af01-dc3f28057c20"' with 4437 bytes
[00.00%] Biggest list   found so far '"my-list"' with 17 items

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

Sampled 5 keys in the keyspace!
Total key length in bytes is 264 (avg len 52.80)

Biggest   list found '"my-list"' has 17 items
Biggest string found '"ballcat:oauth:refresh_auth:f6cdb384-9a9d-4f2f-af01-dc3f28057c20"' has 4437 bytes

1 lists with 17 items (20.00% of keys, avg size 17.00)
0 hashs with 0 fields (00.00% of keys, avg size 0.00)
4 strings with 4831 bytes (80.00% of keys, avg size 1207.75)
0 streams with 0 entries (00.00% of keys, avg size 0.00)
0 sets with 0 members (00.00% of keys, avg size 0.00)
0 zsets with 0 members (00.00% of keys, avg size 0.00

從這個命令的運行結果,我們可以看出:這個命令會掃描(Scan) Redis 中的所有 key ,會對 Redis 的性能有一點影響。並且,這種方式只能找出每種數據結構 top 1 bigkey(佔用內存最大的 String 數據類型,包含元素最多的複合數據類型)。然而,一個 key 的元素多並不代表佔用內存也多,需要我們根據具體的業務情況來進一步判斷。

在線上執行該命令時,為了降低對 Redis 的影響,需要指定 -i 參數控制掃描的頻率。redis-cli -p 6379 --bigkeys -i 3 表示掃描過程中每次掃描後休息的時間間隔為 3 秒。

2、使用 Redis 自帶的 SCAN 命令

SCAN 命令可以按照一定的模式和數量返回匹配的 key。獲取了 key 之後,可以利用 STRLENHLENLLEN等命令返回其長度或成員數量。

數據結構 命令 複雜度 結果(對應 key)
String STRLEN O(1) 字符串值的長度
Hash HLEN O(1) 哈希表中字段的數量
List LLEN O(1) 列表元素數量
Set SCARD O(1) 集合元素數量
Sorted Set ZCARD O(1) 有序集合的元素數量

對於集合類型還可以使用 MEMORY USAGE 命令(Redis 4.0+),這個命令會返回鍵值對佔用的內存空間。

3、藉助開源工具分析 RDB 文件。

通過分析 RDB 文件來找出 big key。這種方案的前提是你的 Redis 採用的是 RDB 持久化。

網上有現成的代碼/工具可以直接拿來使用:

  • redis-rdb-tools:Python 語言寫的用來分析 Redis 的 RDB 快照文件用的工具
  • rdb_bigkeys : Go 語言寫的用來分析 Redis 的 RDB 快照文件用的工具,性能更好。

4、藉助公有云的 Redis 分析服務。

如果你用的是公有云的 Redis 服務的話,可以看看其是否提供了 key 分析功能(一般都提供了)。

這裏以阿里雲 Redis 為例説明,它支持 bigkey 實時分析、發現,文檔地址:https://www.alibabacloud.com/help/zh/apsaradb-for-redis/lates... 。

阿里雲Key分析

如何處理 bigkey?

bigkey 的常見處理以及優化辦法如下(這些方法可以配合起來使用):

  • 分割 bigkey:將一個 bigkey 分割為多個小 key。例如,將一個含有上萬字段數量的 Hash 按照一定策略(比如二次哈希)拆分為多個 Hash。
  • 手動清理:Redis 4.0+ 可以使用 UNLINK 命令來異步刪除一個或多個指定的 key。Redis 4.0 以下可以考慮使用 SCAN 命令結合 DEL 命令來分批次刪除。
  • 採用合適的數據結構:例如,文件二進制數據不使用 String 保存、使用 HyperLogLog 統計頁面 UV、Bitmap 保存狀態信息(0/1)。
  • 開啓 lazy-free(惰性刪除/延遲釋放) :lazy-free 特性是 Redis 4.0 開始引入的,指的是讓 Redis 採用異步方式延遲釋放 key 使用的內存,將該操作交給單獨的子線程處理,避免阻塞主線程。
user avatar lankerens 頭像 markerhub 頭像 fulng 頭像 mo_or 頭像 redorblack 頭像 goudantiezhuerzi 頭像 buxiyan 頭像 91cyz 頭像 saoming_zhang 頭像 tengteng_5c7902af4b01e 頭像 gozhuyinglong 頭像 lianhuatongzina 頭像
15 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.