淺析 Redis 分散式叢集傾斜問題
對於分散式系統而言,整個叢集處理請求的效率和儲存容量,往往取決於叢集中響應最慢或儲存增長最快的節點。所以在系統設計和容量規劃時,我們儘量保障叢集中各節點的“資料和請求分佈均衡“。但在實際生產系統中,出現數據容量和請求傾斜(類似Data Skew)問題是比較常見的。
示例:2019年春節抽獎服務,業務評估峰值qps是2w,轉化到redis叢集為10w qps和5GB記憶體儲存,部署5個分片每個分片1GB+2W qps的redis叢集(包含預留容量)。 結果活動開始時,才發現服務存在”熱點key",請求嚴重傾斜, 峰值時的6w qps都集中到其中一個分片,導致這分片過載,整個抽獎服務雪崩。
redis分散式叢集傾斜問題,主要分為兩類:1 資料儲存容量傾斜,資料儲存總是落到叢集中少數節點; 2 qps請求傾斜,qps總是落到少數節點。
本文主要從以下幾點分析redis分散式叢集傾斜:
-
redis叢集出現傾斜的影響;
-
導致redis叢集傾斜的常見原因;
-
redis叢集傾斜問題的排查方式;
-
如何有效避免redis叢集傾斜問題。
redis叢集出現傾斜的影響
傾斜問題對於redis這類純記憶體和單執行緒服務影響較大, 存在以下痛點:
-
qps集中到少數redis節點,引起少數節點過載,會拖垮整個服務,同時叢集處理qps能力不具備可擴充套件性;
-
資料容量傾斜,導致少數節點記憶體爆增,出現OOM Killer和叢集儲存容量不具備可擴充套件性;
-
運維管理變複雜,類似監控告警記憶體使用量、QPS、連線數、redis cpu busy等值不便統一;
-
因叢集內其他節點資源不能被充分利用,導致redis伺服器/容器資源利率低;
-
增大自動化配置管理難度;單叢集節點儘量統一引數配置;
分析完影響,那我們再看生產環境中,導致Redis叢集嚴重“傾斜”的常見原因。
導致Redis叢集傾斜的常見原因
一般是系統設計時,鍵空間(keyspace)設計不合理:
-
系統設計時,redis鍵空間(keyspace)設計不合理,出現”熱點key",導致這類key所在節點qps過載,叢集出現qps傾斜;
-
系統存在大的集合key(hash,set,list等),導致大key所在節點的容量和QPS過載,叢集出現qps和容量傾斜;
-
DBA在規劃叢集或擴容不當,導致資料槽(slot)數分配不均勻,導致容量和請求qps傾斜;
-
系統大量使用[Keys hash tags](http://redis.io/topics/cluster-spec), 可能導致某些資料槽位的key數量多,叢集叢集出現qps和容量傾斜;
-
工程師執行monitor這類命令,導致當前節點client輸出緩衝區增大;used_memory_rss被撐大;導致節點記憶體容量增大,出現容量傾斜;
接下來,當叢集出現記憶體容量、鍵數量或QPS請求量嚴重傾斜時,我們應該排查定位問題呢?
Redis叢集傾斜問題的排查方式
排查節點熱點key,確定top commands.
當叢集因熱點key導致叢集qps傾斜,需快速定位熱點key和top commands。可使用開源工具 [redis-faina](https://github.com/facebookarchive/redis-faina),或有實時redis分析平臺更好。
以下是使用redis-faina工具分析,可見兩個字首key的QPS佔比基本各為50%, 明顯熱點key;也能看到auth命令的異常(top commands)。
Overall Stats========================================
Lines Processed100000
Commands/Sec7276.82
Top Prefixes
========================================
ar_xxx49849(49.85%)
Top Keys
========================================
c8a87fxxxxx49943(49.94%)
a_r:xxxx49849(49.85%)
Top Commands
========================================
GET49964(49.96%)
AUTH49943(49.94%)
SELECT88(0.09%)
系統是否使用較大的集合鍵
系統使用大key導致叢集節點容量或qps傾斜,
比如一個5kw欄位的hash key, 記憶體佔用在近10GB,這個key所在slot的節點的記憶體容量或qps都很有可能傾斜。
這類集合key每次操作幾個欄位,很難從proxy或sdk發現key的大小。
可使用re
dis-cli --bigkeys 分析節點存在的大鍵。 如果需全量分析,可使用redis-rdb-tools(https://github.com/sripathikrishnan/redis-rdb-tools) 對節點的RDB檔案全量分析,通過結果size_in_bytes列得到大key的佔用記憶體位元組數。
示例使用redis-cli 進行抽樣分析:
redis-cli--bigkeys -p 7000
# 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 'key:000000019996' with 1024 bytes
[48.57%] Biggest listfound so far 'mylist' with 534196 items
-------- summary -------
Sampled 8265 keys in the keyspace!
Total key length in bytes is 132234 (avg len 16.00)
Biggest string found 'key:000000019996' has 1024 bytes
Biggestlist found 'mylist' has 534196 items
8264 strings with 8460296 bytes (99.99% of keys, avg size 1023.75)
1 lists with 534196 items (00.01% of keys, avg size 534196.00)
檢查叢集每個分片的資料槽分配是否均勻
下面以Redis Cluster叢集為例
確認叢集中,每個節點負責的資料槽位(slots)和key個數。下面demo的部分例項存在不輕度“傾斜”但不嚴重,可考慮進行reblance.
redis-trib.rb info redis_ip:port
nodeip:port (5e59101a...) -> 44357924 keys | 617 slots | 1 slaves.
nodeip:port (72f686aa...) -> 52257829 keys | 726 slots | 1 slaves.
nodeip:port (d1e4ac02...) -> 45137046 keys | 627 slots | 1 slaves.
---------------------省略------------------------
nodeip:port (f87076c1...) -> 44433892 keys | 617 slots | 1 slaves.
nodeip:port (a7801b06...) -> 44418216 keys | 619 slots | 1 slaves.
nodeip:port (400bbd47...) -> 45318509 keys | 614 slots | 1 slaves.
nodeip:port (c90a36c9...) -> 44417794 keys | 617 slots | 1 slaves.
[OK] 1186817927 keys in 25 masters.
72437.62 keys per slot on average.
系統是否大量使用keys hash tags
在redis叢集中,有些業務為達到多鍵的操作,會使用hash tags把某類key分配同一個分片,可能導致資料、qps都不均勻的問題。
可使用scan掃描keyspace是否有使用hash tags的,或使用monitor,[vc-redis-sniffer](https://www.vividcortex.com/resources/network-analyzer-for-redis)工具分析傾斜節點,是否大理包含有hash tag的key。
是否因為client output buffer異常,導致記憶體容量傾斜
確認是否有client出現output buffer使用量異常,引起記憶體過大的問題;比如執行monitor、keys命令或slave同步full sync時出現客戶端輸入緩衝區佔用過大。
這類情況基本redis例項記憶體會快速增長,很快會出現回落。通過監測client輸出緩衝區使用情況;分析見下面示例:
# 通過監控client_longest_output_list輸出列表的長度,是否有client使用大量的輸出緩衝區.
redis-cli-p 7000 info clients
# Clients
connected_clients:52
client_longest_output_list:9179
client_biggest_input_buf:0
blocked_clients:0
# 檢視輸出緩衝區列表長度不為0的client。 可見monitor佔用輸出緩衝區370MB
redis-cli-p 7000 client list | grep -v "oll=0"
id=1840 addr=xx64598age=75 idle=0 flags=O obl=0 oll=15234 omem=374930608 cmd=monitor
如何有效避免Redis叢集傾斜問題
-
系統設計redis叢集鍵空間和query pattern時,應避免出現熱點key, 如果有熱點key邏輯,儘量打散分佈不同的節點或新增程式本地快取;
-
系統設計redis叢集鍵空間
時,應避免使用大key,把key設計拆分打散;大key除了傾斜問題,對叢集穩定性有嚴重影響;
-
redis叢集部署和擴縮容處理,保證資料槽位分配平均;
-
系統設計角度應避免使用keys hash tag;
-
日常運維和系統中應避免直接使用keys,monitor等命令,導致輸出緩衝區堆積;這類命令建議作rename處理;
-
合量配置normal的client output buffer, 建議設定10mb,slave限制為1GB按需要臨時調整
(警示:和業務確認調整再修改,避免業務出錯)
在實際生產業務場景中,大規模叢集很難做到叢集的完全均衡,只是儘量保證不出現嚴重傾斜問題。