淺析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)文章
Redis分布式鎖的正確實(shí)現(xiàn)方法總結(jié)
在本篇文章里小編給大家整理的是關(guān)于Redis分布式鎖的正確實(shí)現(xiàn)方式介紹,有興趣的朋友們可以學(xué)習(xí)下。2020-02-02
Redisson?框架中的分布式鎖實(shí)現(xiàn)方法
這篇文章主要介紹了Redisson?框架中的分布式鎖,實(shí)現(xiàn)分布式鎖通常有三種方式:數(shù)據(jù)庫(kù)、Redis 和 Zookeeper,我們比較常用的是通過(guò) Redis 和 Zookeeper 實(shí)現(xiàn)分布式鎖,需要的朋友可以參考下2024-03-03
SpringBoot3+Redis實(shí)現(xiàn)分布式鎖的配置方法
這篇文章主要介紹了SpringBoot3+Redis實(shí)現(xiàn)分布式鎖,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-07-07
基于redis實(shí)現(xiàn)的點(diǎn)贊功能設(shè)計(jì)思路詳解
點(diǎn)贊是我們現(xiàn)在經(jīng)常見(jiàn)到的一個(gè)效果,如朋友圈、微博都有點(diǎn)贊的效果,下面這篇文章主要跟大家分享了基于redis實(shí)現(xiàn)的點(diǎn)贊功能設(shè)計(jì)思路的相關(guān)資料,文中介紹的非常詳細(xì),對(duì)大家實(shí)現(xiàn)點(diǎn)贊功能具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。2017-05-05
詳解redis數(shù)據(jù)結(jié)構(gòu)之壓縮列表
這篇文章主要介紹了詳解redis數(shù)據(jù)結(jié)構(gòu)之壓縮列表的相關(guān)資料,壓縮列表在redis中的結(jié)構(gòu)體名稱為ziplist,其是redis為了節(jié)約內(nèi)存而聲明的一種數(shù)據(jù)結(jié)構(gòu),需要的朋友可以參考下2017-05-05
基于redis實(shí)現(xiàn)世界杯排行榜功能項(xiàng)目實(shí)戰(zhàn)
前段時(shí)間,做了一個(gè)世界杯競(jìng)猜積分排行榜。對(duì)世界杯64場(chǎng)球賽勝負(fù)平進(jìn)行猜測(cè),猜對(duì)+1分,錯(cuò)誤+0分,一人一場(chǎng)只能猜一次。下面通過(guò)本文給大家分享基于redis實(shí)現(xiàn)世界杯排行榜功能項(xiàng)目實(shí)戰(zhàn),感興趣的朋友一起看看吧2018-10-10

