淺析Redis?切片集群的數(shù)據(jù)傾斜問(wèn)題
Redis 中如何應(yīng)對(duì)數(shù)據(jù)傾斜
什么是數(shù)據(jù)傾斜
如果 Redis 中的部署,采用的是切片集群,數(shù)據(jù)是會(huì)按照一定的規(guī)則分散到不同的實(shí)例中保存,比如,使用 Redis Cluster
或 Codis
。
數(shù)據(jù)傾斜會(huì)有下面兩種情況:
1、數(shù)據(jù)量?jī)A斜:在某些情況下,實(shí)例上的數(shù)據(jù)分布不均衡,某個(gè)實(shí)例上的數(shù)據(jù)特別多。
2、數(shù)據(jù)訪問(wèn)傾斜:雖然每個(gè)集群實(shí)例上的數(shù)據(jù)量相差不大,但是某個(gè)實(shí)例上的數(shù)據(jù)是熱點(diǎn)數(shù)據(jù),被訪問(wèn)得非常頻繁。
發(fā)生了數(shù)據(jù)傾斜,會(huì)造成那些數(shù)據(jù)量大的和訪問(wèn)高的實(shí)例節(jié)點(diǎn),系統(tǒng)的負(fù)載升高,響應(yīng)速度變慢。嚴(yán)重的情況造成內(nèi)存資源耗盡,引起系統(tǒng)崩潰。
數(shù)據(jù)量?jī)A斜
數(shù)據(jù)量?jī)A斜,也就是實(shí)例上的數(shù)據(jù)分布不均衡,某個(gè)實(shí)例中的數(shù)據(jù)分布的特別多 。
數(shù)據(jù)量的傾斜,主要有下面三種情況:
1、bigkey導(dǎo)致傾斜;
2、Slot分配不均衡導(dǎo)致傾斜;
3、Hash Tag導(dǎo)致傾斜。
下面來(lái)一一的分析下
bigkey導(dǎo)致傾斜
什么是 bigkey
:我們將含有較大數(shù)據(jù)或含有大量成員、列表數(shù)的 Key 稱之為大Key。
一個(gè) STRING 類型的 Key,它的值為 5MB(數(shù)據(jù)過(guò)大)
一個(gè) LIST 類型的 Key,它的列表數(shù)量為 20000 個(gè)(列表數(shù)量過(guò)多)
一個(gè) ZSET 類型的 Key,它的成員數(shù)量為 10000 個(gè)(成員數(shù)量過(guò)多)
一個(gè) HASH 格式的 Key,它的成員數(shù)量雖然只有 1000 個(gè)但這些成員的 value 總大小為 100MB(成員體積過(guò)大)
如果某個(gè)實(shí)例中保存了 bigkey
,那么就有可能導(dǎo)致集群的數(shù)據(jù)傾斜。
bigkey
存在問(wèn)題
內(nèi)存空間不均勻:如果采用切片集群的部署方案,容易造成某些實(shí)例節(jié)點(diǎn)的內(nèi)存分配不均勻;
造成網(wǎng)絡(luò)擁塞:讀取 bigkey 意味著需要消耗更多的網(wǎng)絡(luò)流量,可能會(huì)對(duì) Redis 服務(wù)器造成影響;
過(guò)期刪除:bigkey 不單讀寫(xiě)慢,刪除也慢,刪除過(guò)期 bigkey 也比較耗時(shí);
遷移困難:由于數(shù)據(jù)龐大,備份和還原也容易造成阻塞,操作失??;
如何避免
對(duì)于bigkey
可以從以下兩個(gè)方面進(jìn)行處理
1、合理優(yōu)化數(shù)據(jù)結(jié)構(gòu)
1、對(duì)較大的數(shù)據(jù)進(jìn)行壓縮處理;
2、拆分集合:將大的集合拆分成小集合(如以時(shí)間進(jìn)行分片)或者單個(gè)的數(shù)據(jù)。
2、選擇其他的技術(shù)來(lái)存儲(chǔ) bigkey
;
使用其他的存儲(chǔ)形式,考慮使用 cdn 或者文檔性數(shù)據(jù)庫(kù) MongoDB。
Slot分配不均衡導(dǎo)致傾斜
例如在 Redis Cluster
通過(guò) Slot 來(lái)給數(shù)據(jù)分配實(shí)例
1、Redis Cluster
方案采用哈希槽來(lái)處理 KEY 在不同實(shí)例中的分布,一個(gè)切片集群共有 16384 個(gè)哈希槽,這些哈希槽類似于數(shù)據(jù)分區(qū),每個(gè)鍵值對(duì)都會(huì)根據(jù)它的 key,被映射到一個(gè)哈希槽中;
2、一個(gè) KEY ,首先會(huì)根據(jù) CRC16 算法計(jì)算一個(gè)16 bit的值;然后,再用這個(gè) 16bit 值對(duì) 16384 取模,得到 0~16383 范圍內(nèi)的模數(shù),每個(gè)模數(shù)代表一個(gè)相應(yīng)編號(hào)的哈希槽。
3、然后把哈希槽分配到所有的實(shí)例中,例如,如果集群中有N個(gè)實(shí)例,那么,每個(gè)實(shí)例上的槽個(gè)數(shù)為16384/N個(gè)。
如果 Slot 分配的不均衡,就會(huì)導(dǎo)致某幾個(gè)實(shí)例中數(shù)據(jù)量偏大,進(jìn)而導(dǎo)致數(shù)據(jù)傾斜的發(fā)生。
出現(xiàn)這種問(wèn)題,我們就可以使用遷移命令把這些 Slot 遷移到其它實(shí)例上,即可。
Hash Tag導(dǎo)致傾斜
Hash Tag
用于 redis 集群中,其作用是將具有某一固定特征的數(shù)據(jù)存儲(chǔ)到同一臺(tái)實(shí)例上。其實(shí)現(xiàn)方式為在 key 中加個(gè) {}
,例如 test{1}
。
使用 Hash Tag
后客戶端在計(jì)算 key 的 crc16 時(shí),只計(jì)算 {}
中數(shù)據(jù)。如果沒(méi)使用 Hash Tag
,客戶端會(huì)對(duì)整個(gè) key 進(jìn)行 crc16 計(jì)算。
數(shù)據(jù)key | 哈希計(jì)算 | 對(duì)應(yīng)的Slot |
---|---|---|
user:info:{3231} | CRC16('3231') mod 16384 | 1024 |
user:info:{5328} | CRC16('5328') mod 16384 | 3210 |
user:order:{3231} | CRC16('3231') mod 16384 | 1024 |
user:order:{5328} | CRC16('5328') mod 16384 | 3210 |
這樣通過(guò) Hash Tag
就可以將某一固定特征數(shù)據(jù)存儲(chǔ)到一臺(tái)實(shí)例上,避免逐個(gè)查詢集群中實(shí)例。
栗如:如果我們進(jìn)行事務(wù)操作或者數(shù)據(jù)的范圍查詢,因?yàn)?code>Redis Cluster和 Codis 本身并不支持跨實(shí)例的事務(wù)操作和范圍查詢,當(dāng)業(yè)務(wù)應(yīng)用有這些需求時(shí),就只能先把這些數(shù)據(jù)讀取到業(yè)務(wù)層進(jìn)行事務(wù)處理,或者是逐個(gè)查詢每個(gè)實(shí)例,得到范圍查詢的結(jié)果。
Hash Tag
潛在的問(wèn)題就是,可能存在大量數(shù)據(jù)被映射到同一個(gè)實(shí)例的情況出現(xiàn),導(dǎo)致集群的數(shù)據(jù)傾斜,集群中的負(fù)載不均衡。
所有當(dāng)我使用 Hash Tag
的時(shí)候就做好評(píng)估,我們的業(yè)務(wù)訴求如果不使用 Hash Tag
可以解決嗎,如果不可避免的使用,我們需要評(píng)估好數(shù)據(jù)量,盡量避免數(shù)據(jù)傾斜的出現(xiàn)。
數(shù)據(jù)訪問(wèn)傾斜
雖然每個(gè)集群實(shí)例上的數(shù)據(jù)量相差不大,但是某個(gè)實(shí)例上的數(shù)據(jù)是熱點(diǎn)數(shù)據(jù),被訪問(wèn)得非常頻繁,這就是數(shù)據(jù)訪問(wèn)傾斜。
數(shù)據(jù)量訪問(wèn)傾斜的罪魁禍?zhǔn)拙褪?Hot Key
切片集群中的 Key 最終會(huì)存儲(chǔ)到集群中的一個(gè)固定的 Redis 實(shí)例中。某一個(gè) Key 在一段時(shí)間內(nèi)訪問(wèn)遠(yuǎn)高于其它的 Key,也就是該 Key 對(duì)應(yīng)的 Redis 實(shí)例,會(huì)收到過(guò)大的流量請(qǐng)求,該實(shí)例容易出現(xiàn)過(guò)載和卡頓現(xiàn)象,甚至還會(huì)被打掛掉。
常見(jiàn)引發(fā)熱點(diǎn) Key 的情況:
1、新聞中的熱點(diǎn)事件;
2、秒殺活動(dòng)中的,性價(jià)比高的商品;
如何發(fā)現(xiàn) Hot Key1、提現(xiàn)預(yù)判;
根據(jù)業(yè)務(wù)經(jīng)驗(yàn)進(jìn)行提前預(yù)判;
2、在客戶端進(jìn)行收集;
通過(guò)在客戶端增加命令的采集,來(lái)統(tǒng)計(jì)發(fā)現(xiàn)熱點(diǎn) Key;
3、使用 Redis 自帶的命令排查;
使用monitor命令統(tǒng)計(jì)熱點(diǎn)key(不推薦,高并發(fā)條件下會(huì)有造成redis 內(nèi)存爆掉的隱患);
hotkeys參數(shù),redis 4.0.3提供了redis-cli的熱點(diǎn)key發(fā)現(xiàn)功能,執(zhí)行redis-cli時(shí)加上–hotkeys選項(xiàng)即可。但是該參數(shù)在執(zhí)行的時(shí)候,如果key比較多,執(zhí)行起來(lái)比較慢。
4、在Proxy層做收集
如果集群架構(gòu)引入了 proxy,可以在 proxy 中做統(tǒng)計(jì)
5、自己抓包評(píng)估
Redis客戶端使用TCP協(xié)議與服務(wù)端進(jìn)行交互,通信協(xié)議采用的是RESP。自己寫(xiě)程序監(jiān)聽(tīng)端口,按照RESP協(xié)議規(guī)則解析數(shù)據(jù),進(jìn)行分析。缺點(diǎn)就是開(kāi)發(fā)成本高,維護(hù)困難,有丟包可能性。
Hot Key 如何解決
知道了Hot Key
如何來(lái)應(yīng)對(duì)呢
1、對(duì) Key 進(jìn)行分散處理;
舉個(gè)栗子
有一個(gè)熱 Key 名字為Hot-key-test
,可以將其分散為Hot-key-test1
,Hot-key-test2
...然后將這些 Key 分散到多個(gè)實(shí)例節(jié)點(diǎn)中,當(dāng)客戶端進(jìn)行訪問(wèn)的時(shí)候,隨機(jī)一個(gè)下標(biāo)的 Key 進(jìn)行訪問(wèn),這樣就能將流量分散到不同的實(shí)例中了,避免了一個(gè)緩存節(jié)點(diǎn)的過(guò)載。
一般來(lái)講,可以通過(guò)添加后綴或者前綴,把一個(gè) hotkey 的數(shù)量變成 redis 實(shí)例個(gè)數(shù) N 的倍數(shù) M,從而由訪問(wèn)一個(gè)redis key
變成訪問(wèn)N * M
個(gè)redis key。 N*M
個(gè)redis key
經(jīng)過(guò)分片分布到不同的實(shí)例上,將訪問(wèn)量均攤到所有實(shí)例。
const M = N * 2 //生成隨機(jī)數(shù) random = GenRandom(0, M) //構(gòu)造備份新key bakHotKey = hotKey + “_” + random data = redis.GET(bakHotKey) if data == NULL { data = GetFromDB() redis.SET(bakHotKey, expireTime + GenRandom(0,5)) }
2、使用本地緩存;
業(yè)務(wù)端還可以使用本地緩存,將這些熱 key 記錄在本地緩存,來(lái)減少對(duì)遠(yuǎn)程緩存的沖擊。
這里,有個(gè)地方需要注意下,熱點(diǎn)數(shù)據(jù)多副本方法只能針對(duì)只讀的熱點(diǎn)數(shù)據(jù)。如果熱點(diǎn)數(shù)據(jù)是有讀有寫(xiě)的話,就不適合采用多副本方法了,因?yàn)橐WC多副本間的數(shù)據(jù)一致性,會(huì)帶來(lái)額外的開(kāi)銷。
對(duì)于有讀有寫(xiě)的熱點(diǎn)數(shù)據(jù),我們就要給實(shí)例本身增加資源了,例如使用配置更高的機(jī)器,來(lái)應(yīng)對(duì)大量的訪問(wèn)壓力。
總結(jié)
1、數(shù)據(jù)傾斜會(huì)有下面兩種情況;
1、數(shù)據(jù)量?jī)A斜:在某些情況下,實(shí)例上的數(shù)據(jù)分布不均衡,某個(gè)實(shí)例上的數(shù)據(jù)特別多。
2、數(shù)據(jù)訪問(wèn)傾斜:雖然每個(gè)集群實(shí)例上的數(shù)據(jù)量相差不大,但是某個(gè)實(shí)例上的數(shù)據(jù)是熱點(diǎn)數(shù)據(jù),被訪問(wèn)得非常頻繁。
2、數(shù)據(jù)量的傾斜,主要有下面三種情況;
1、bigkey導(dǎo)致傾斜;
2、Slot分配不均衡導(dǎo)致傾斜;
3、Hash Tag導(dǎo)致傾斜。
3、數(shù)據(jù)訪問(wèn)傾斜,原因就是 Hot Key
造成的,出現(xiàn)Hot Key
,一般下面有下面兩種方式去解決;
1、對(duì) Key 進(jìn)行分散處理;
2、使用本地緩存;
參考
【Redis核心技術(shù)與實(shí)戰(zhàn)】https://time.geekbang.org/column/intro/100056701
【Redis設(shè)計(jì)與實(shí)現(xiàn)】https://book.douban.com/subject/25900156/
【Redis 的學(xué)習(xí)筆記】https://github.com/boilingfrog/Go-POINT/tree/master/redis
【Redis中的切片集群】https://boilingfrog.github.io/2022/02/20/redis中常見(jiàn)的集群部署方案/#切片集群
【Redis 切片集群的數(shù)據(jù)傾斜分析】https://boilingfrog.github.io/2022/06/22/Redis切片集群的數(shù)據(jù)傾斜分析/
到此這篇關(guān)于Redis 切片集群的數(shù)據(jù)傾斜分析的文章就介紹到這了,更多相關(guān)Redis數(shù)據(jù)傾斜內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于使用IDEA的springboot框架往Redis里寫(xiě)入數(shù)據(jù)亂碼問(wèn)題
這篇文章主要介紹了用IDEA的springboot框架往Redis里寫(xiě)入數(shù)據(jù)亂碼問(wèn)題,本文給大家分享解決方法通過(guò)圖文示例相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10Redisson分布式限流的實(shí)現(xiàn)原理解析
這篇文章主要為大家介紹了Redisson分布式限流的實(shí)現(xiàn)原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02Spring Boot 項(xiàng)目集成Redis的方式詳解
這篇文章主要介紹了Spring Boot 項(xiàng)目集成Redis的方式,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧,需要的朋友可以參考下2021-08-08分布式利器redis及redisson的延遲隊(duì)列實(shí)踐
這篇文章為大家主要介紹了分布式利器redis及redisson的延遲隊(duì)列實(shí)踐,搜遍全網(wǎng)好像還沒(méi)有使用redisson的延遲隊(duì)列的,redisson作為一個(gè)分布式利器,這么好用的工具沒(méi)人用有點(diǎn)可惜2022-03-03Redis Cluster集群數(shù)據(jù)分片機(jī)制原理
這篇文章主要介紹了Redis Cluster集群數(shù)據(jù)分片機(jī)制原理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04