淺析Redis分布式集群傾斜問題
對于分布式系統(tǒng)而言,整個集群處理請求的效率和存儲容量,往往取決于集群中響應(yīng)最慢或存儲增長最快的節(jié)點(diǎn)。所以在系統(tǒng)設(shè)計和容量規(guī)劃時,我們盡量保障集群中各節(jié)點(diǎn)的“數(shù)據(jù)和請求分布均衡“。但在實際生產(chǎn)系統(tǒng)中,出現(xiàn)數(shù)據(jù)容量和請求傾斜(類似Data Skew)問題是比較常見的。
示例:2019年春節(jié)抽獎服務(wù),業(yè)務(wù)評估峰值qps是2w,轉(zhuǎn)化到redis集群為10w qps和5GB內(nèi)存存儲,部署5個分片每個分片1GB+2W qps的redis集群(包含預(yù)留容量)。結(jié)果活動開始時,才發(fā)現(xiàn)服務(wù)存在”熱點(diǎn)key",請求嚴(yán)重傾斜, 峰值時的6w qps都集中到其中一個分片,導(dǎo)致這分片過載,整個抽獎服務(wù)雪崩。
redis分布式集群傾斜問題,主要分為兩類:1 數(shù)據(jù)存儲容量傾斜,數(shù)據(jù)存儲總是落到集群中少數(shù)節(jié)點(diǎn);2 qps請求傾斜,qps總是落到少數(shù)節(jié)點(diǎn)。
本文主要從以下幾點(diǎn)分析redis分布式集群傾斜:
redis集群出現(xiàn)傾斜的影響;
導(dǎo)致redis集群傾斜的常見原因;
redis集群傾斜問題的排查方式;
如何有效避免redis集群傾斜問題。
redis集群出現(xiàn)傾斜的影響
傾斜問題對于redis這類純內(nèi)存和單線程服務(wù)影響較大,存在以下痛點(diǎn):
qps集中到少數(shù)redis節(jié)點(diǎn),引起少數(shù)節(jié)點(diǎn)過載,會拖垮整個服務(wù),同時集群處理qps能力不具備可擴(kuò)展性;
數(shù)據(jù)容量傾斜,導(dǎo)致少數(shù)節(jié)點(diǎn)內(nèi)存爆增,出現(xiàn)OOM Killer和集群存儲容量不具備可擴(kuò)展性;
運(yùn)維管理變復(fù)雜,類似監(jiān)控告警內(nèi)存使用量、QPS、連接數(shù)、redis cpu busy等值不便統(tǒng)一;
因集群內(nèi)其他節(jié)點(diǎn)資源不能被充分利用,導(dǎo)致redis服務(wù)器/容器資源利率低;
增大自動化配置管理難度;單集群節(jié)點(diǎn)盡量統(tǒng)一參數(shù)配置;
分析完影響,那我們再看生產(chǎn)環(huán)境中,導(dǎo)致Redis集群嚴(yán)重“傾斜”的常見原因。
導(dǎo)致Redis集群傾斜的常見原因
一般是系統(tǒng)設(shè)計時,鍵空間(keyspace)設(shè)計不合理:
系統(tǒng)設(shè)計時,redis鍵空間(keyspace)設(shè)計不合理,出現(xiàn)”熱點(diǎn)key",導(dǎo)致這類key所在節(jié)點(diǎn)qps過載,集群出現(xiàn)qps傾斜;
系統(tǒng)存在大的集合key(hash,set,list等),導(dǎo)致大key所在節(jié)點(diǎn)的容量和QPS過載,集群出現(xiàn)qps和容量傾斜;
DBA在規(guī)劃集群或擴(kuò)容不當(dāng),導(dǎo)致數(shù)據(jù)槽(slot)數(shù)分配不均勻,導(dǎo)致容量和請求qps傾斜;
系統(tǒng)大量使用Keys hash tags, 可能導(dǎo)致某些數(shù)據(jù)槽位的key數(shù)量多,集群集群出現(xiàn)qps和容量傾斜;
工程師執(zhí)行monitor這類命令,導(dǎo)致當(dāng)前節(jié)點(diǎn)client輸出緩沖區(qū)增大;used_memory_rss被撐大;導(dǎo)致節(jié)點(diǎn)內(nèi)存容量增大,出現(xiàn)容量傾斜;
接下來,當(dāng)集群出現(xiàn)內(nèi)存容量、鍵數(shù)量或QPS請求量嚴(yán)重傾斜時,我們應(yīng)該排查定位問題呢?
Redis集群傾斜問題的排查方式
排查節(jié)點(diǎn)熱點(diǎn)key,確定top commands.
當(dāng)集群因熱點(diǎn)key導(dǎo)致集群qps傾斜,需快速定位熱點(diǎn)key和top commands。可使用開源工具redis-faina,或有實時redis分析平臺更好。
以下是使用redis-faina工具分析,可見兩個前綴key的QPS占比基本各為50%, 明顯熱點(diǎn)key;也能看到auth命令的異常(top commands)。
Overall?Stats
========================================
Lines?Processed?????????100000
Commands/Sec????????????7276.82
Top?Prefixes
========================================
ar_xxx?????????49849???(49.85%)
Top?Keys
========================================
c8a87fxxxxx????????49943???(49.94%)
a_r:xxxx???????????49849???(49.85%)
Top?Commands
========================================
GET?????????????49964???(49.96%)
AUTH????????????49943???(49.94%)
SELECT??????????88??????(0.09%)
系統(tǒng)是否使用較大的集合鍵
系統(tǒng)使用大key導(dǎo)致集群節(jié)點(diǎn)容量或qps傾斜,比如一個5kw字段的hash key, 內(nèi)存占用在近10GB,這個key所在slot的節(jié)點(diǎn)的內(nèi)存容量或qps都很有可能傾斜。
這類集合key每次操作幾個字段,很難從proxy或sdk發(fā)現(xiàn)key的大小。
可使用redis-cli --bigkeys 分析節(jié)點(diǎn)存在的大鍵。如果需全量分析,可使用redis-rdb-tools(https://github.com/sripathikrishnan/redis-rdb-tools) 對節(jié)點(diǎn)的RDB文件全量分析,通過結(jié)果size_in_bytes列得到大key的占用內(nèi)存字節(jié)數(shù)。
示例使用redis-cli 進(jìn)行抽樣分析:
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?list???found?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
Biggest???list?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)
檢查集群每個分片的數(shù)據(jù)槽分配是否均勻
下面以Redis Cluster集群為例確認(rèn)集群中,每個節(jié)點(diǎn)負(fù)責(zé)的數(shù)據(jù)槽位(slots)和key個數(shù)。下面demo的部分實例存在不輕度“傾斜”但不嚴(yán)重,可考慮進(jìn)行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.
系統(tǒng)是否大量使用keys hash tags
在redis集群中,有些業(yè)務(wù)為達(dá)到多鍵的操作,會使用hash tags把某類key分配同一個分片,可能導(dǎo)致數(shù)據(jù)、qps都不均勻的問題。可使用scan掃描keyspace是否有使用hash tags的,或使用monitor,vc-redis-sniffer工具分析傾斜節(jié)點(diǎn),是否大理包含有hash tag的key。
是否因為client output buffer異常,導(dǎo)致內(nèi)存容量傾斜
確認(rèn)是否有client出現(xiàn)output buffer使用量異常,引起內(nèi)存過大的問題;比如執(zhí)行monitor、keys命令或slave同步full sync時出現(xiàn)客戶端輸入緩沖區(qū)占用過大。
這類情況基本redis實例內(nèi)存會快速增長,很快會出現(xiàn)回落。通過監(jiān)測client輸出緩沖區(qū)使用情況;分析見下面示例:
#?通過監(jiān)控client_longest_output_list輸出列表的長度,是否有client使用大量的輸出緩沖區(qū).
redis-cli??-p?7000?info?clients
#?Clients
connected_clients:52
client_longest_output_list:9179
client_biggest_input_buf:0
blocked_clients:0
#?查看輸出緩沖區(qū)列表長度不為0的client。?可見monitor占用輸出緩沖區(qū)370MB
redis-cli??-p?7000?client?list?|?grep?-v?"oll=0"
id=1840?addr=xx64598??age=75?idle=0?flags=O?obl=0?oll=15234?omem=374930608?cmd=monitor
如何有效避免Redis集群傾斜問題
系統(tǒng)設(shè)計redis集群鍵空間和query pattern時,應(yīng)避免出現(xiàn)熱點(diǎn)key, 如果有熱點(diǎn)key邏輯,盡量打散分布不同的節(jié)點(diǎn)或添加程序本地緩存;
系統(tǒng)設(shè)計redis集群鍵空間時,應(yīng)避免使用大key,把key設(shè)計拆分打散;大key除了傾斜問題,對集群穩(wěn)定性有嚴(yán)重影響;
redis集群部署和擴(kuò)縮容處理,保證數(shù)據(jù)槽位分配平均;
系統(tǒng)設(shè)計角度應(yīng)避免使用keys hash tag;
日常運(yùn)維和系統(tǒng)中應(yīng)避免直接使用keys,monitor等命令,導(dǎo)致輸出緩沖區(qū)堆積;這類命令建議作rename處理;
合量配置normal的client output buffer, 建議設(shè)置10mb,slave限制為1GB按需要臨時調(diào)整(警示:和業(yè)務(wù)確認(rèn)調(diào)整再修改,避免業(yè)務(wù)出錯)
在實際生產(chǎn)業(yè)務(wù)場景中,大規(guī)模集群很難做到集群的完全均衡,只是盡量保證不出現(xiàn)嚴(yán)重傾斜問題。
