Redis 中如何應對資料傾斜
什麼是資料傾斜
如果 Redis 中的部署,採用的是切片叢集,資料是會按照一定的規則分散到不同的例項中儲存,比如,使用 Redis Cluster
或 Codis
。
資料傾斜會有下面兩種情況:
1、資料量傾斜:在某些情況下,例項上的資料分佈不均衡,某個例項上的資料特別多。
2、資料訪問傾斜:雖然每個叢集例項上的資料量相差不大,但是某個例項上的資料是熱點資料,被訪問得非常頻繁。
發生了資料傾斜,會造成那些資料量大的和訪問高的例項節點,系統的負載升高,響應速度變慢。嚴重的情況造成記憶體資源耗盡,引起系統崩潰。
資料量傾斜
資料量傾斜,也就是例項上的資料分佈不均衡,某個例項中的資料分佈的特別多 。
資料量的傾斜,主要有下面三種情況:
1、bigkey導致傾斜;
2、Slot分配不均衡導致傾斜;
3、Hash Tag導致傾斜。
下面來一一的分析下
bigkey導致傾斜
什麼是 bigkey
:我們將含有較大資料或含有大量成員、列表數的 Key 稱之為大Key。
-
一個 STRING 型別的 Key,它的值為 5MB(資料過大)
-
一個 LIST 型別的 Key,它的列表數量為 20000 個(列表數量過多)
-
一個 ZSET 型別的 Key,它的成員數量為 10000 個(成員數量過多)
-
一個 HASH 格式的 Key,它的成員數量雖然只有 1000 個但這些成員的 value 總大小為 100MB(成員體積過大)
如果某個例項中儲存了 bigkey
,那麼就有可能導致叢集的資料傾斜。
bigkey
存在問題
-
記憶體空間不均勻:如果採用切片叢集的部署方案,容易造成某些例項節點的記憶體分配不均勻;
-
造成網路擁塞:讀取 bigkey 意味著需要消耗更多的網路流量,可能會對 Redis 伺服器造成影響;
-
過期刪除:bigkey 不單讀寫慢,刪除也慢,刪除過期 bigkey 也比較耗時;
-
遷移困難:由於資料龐大,備份和還原也容易造成阻塞,操作失敗;
如何避免
對於bigkey
可以從以下兩個方面進行處理
1、合理優化資料結構
-
1、對較大的資料進行壓縮處理;
-
2、拆分集合:將大的集合拆分成小集合(如以時間進行分片)或者單個的資料。
2、選擇其他的技術來儲存 bigkey
;
- 使用其他的儲存形式,考慮使用 cdn 或者文件性資料庫 MongoDB。
Slot分配不均衡導致傾斜
例如在 Redis Cluster
通過 Slot 來給資料分配例項
1、Redis Cluster
方案採用雜湊槽來處理 KEY 在不同例項中的分佈,一個切片叢集共有 16384 個雜湊槽,這些雜湊槽類似於資料分割槽,每個鍵值對都會根據它的 key,被對映到一個雜湊槽中;
2、一個 KEY ,首先會根據 CRC16 演算法計算一個16 bit的值;然後,再用這個 16bit 值對 16384 取模,得到 0~16383 範圍內的模數,每個模數代表一個相應編號的雜湊槽。
3、然後把雜湊槽分配到所有的例項中,例如,如果叢集中有N個例項,那麼,每個例項上的槽個數為16384/N個。
如果 Slot 分配的不均衡,就會導致某幾個例項中資料量偏大,進而導致資料傾斜的發生。
出現這種問題,我們就可以使用遷移命令把這些 Slot 遷移到其它例項上,即可。
Hash Tag導致傾斜
Hash Tag
用於 redis 叢集中,其作用是將具有某一固定特徵的資料儲存到同一臺例項上。其實現方式為在 key 中加個 {}
,例如 test{1}
。
使用 Hash Tag
後客戶端在計算 key 的 crc16 時,只計算 {}
中資料。如果沒使用 Hash Tag
,客戶端會對整個 key 進行 crc16 計算。
資料key | 雜湊計算 | 對應的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 |
這樣通過 Hash Tag
就可以將某一固定特徵資料儲存到一臺例項上,避免逐個查詢叢集中例項。
慄如:如果我們進行事務操作或者資料的範圍查詢,因為Redis Cluster
和 Codis 本身並不支援跨例項的事務操作和範圍查詢,當業務應用有這些需求時,就只能先把這些資料讀取到業務層進行事務處理,或者是逐個查詢每個例項,得到範圍查詢的結果。
Hash Tag
潛在的問題就是,可能存在大量資料被對映到同一個例項的情況出現,導致叢集的資料傾斜,叢集中的負載不均衡。
所有當我使用 Hash Tag
的時候就做好評估,我們的業務訴求如果不使用 Hash Tag
可以解決嗎,如果不可避免的使用,我們需要評估好資料量,儘量避免資料傾斜的出現。
資料訪問傾斜
雖然每個叢集例項上的資料量相差不大,但是某個例項上的資料是熱點資料,被訪問得非常頻繁,這就是資料訪問傾斜。
資料量訪問傾斜的罪魁禍首就是 Hot Key
切片叢集中的 Key 最終會儲存到叢集中的一個固定的 Redis 例項中。某一個 Key 在一段時間內訪問遠高於其它的 Key,也就是該 Key 對應的 Redis 例項,會收到過大的流量請求,該例項容易出現過載和卡頓現象,甚至還會被打掛掉。
常見引發熱點 Key 的情況:
1、新聞中的熱點事件;
2、秒殺活動中的,價效比高的商品;
如何發現 Hot Key
- 1、提現預判;
根據業務經驗進行提前預判;
- 2、在客戶端進行收集;
通過在客戶端增加命令的採集,來統計發現熱點 Key;
- 3、使用 Redis 自帶的命令排查;
使用monitor命令統計熱點key(不推薦,高併發條件下會有造成redis 記憶體爆掉的隱患);
hotkeys引數,redis 4.0.3提供了redis-cli的熱點key發現功能,執行redis-cli時加上–hotkeys選項即可。但是該引數在執行的時候,如果key比較多,執行起來比較慢。
- 4、在Proxy層做收集
如果叢集架構引入了 proxy,可以在 proxy 中做統計
- 5、自己抓包評估
Redis客戶端使用TCP協議與服務端進行互動,通訊協議採用的是RESP。自己寫程式監聽埠,按照RESP協議規則解析資料,進行分析。缺點就是開發成本高,維護困難,有丟包可能性。
Hot Key 如何解決
知道了Hot Key
如何來應對呢
- 1、對 Key 進行分散處理;
舉個例子
有一個熱 Key 名字為Hot-key-test
,可以將其分散為Hot-key-test1
,Hot-key-test2
...然後將這些 Key 分散到多個例項節點中,當客戶端進行訪問的時候,隨機一個下標的 Key 進行訪問,這樣就能將流量分散到不同的例項中了,避免了一個快取節點的過載。
一般來講,可以通過新增字尾或者字首,把一個 hotkey 的數量變成 redis 例項個數 N 的倍數 M,從而由訪問一個redis key
變成訪問N * M
個redis key。 N*M
個redis key
經過分片分佈到不同的例項上,將訪問量均攤到所有例項。
const M = N * 2
//生成隨機數
random = GenRandom(0, M)
//構造備份新key
bakHotKey = hotKey + “_” + random
data = redis.GET(bakHotKey)
if data == NULL {
data = GetFromDB()
redis.SET(bakHotKey, expireTime + GenRandom(0,5))
}
- 2、使用本地快取;
業務端還可以使用本地快取,將這些熱 key 記錄在本地快取,來減少對遠端快取的衝擊。
這裡,有個地方需要注意下,熱點資料多副本方法只能針對只讀的熱點資料。如果熱點資料是有讀有寫的話,就不適合採用多副本方法了,因為要保證多副本間的資料一致性,會帶來額外的開銷。
對於有讀有寫的熱點資料,我們就要給例項本身增加資源了,例如使用配置更高的機器,來應對大量的訪問壓力。
總結
1、資料傾斜會有下面兩種情況;
-
1、資料量傾斜:在某些情況下,例項上的資料分佈不均衡,某個例項上的資料特別多。
-
2、資料訪問傾斜:雖然每個叢集例項上的資料量相差不大,但是某個例項上的資料是熱點資料,被訪問得非常頻繁。
2、資料量的傾斜,主要有下面三種情況;
-
1、bigkey導致傾斜;
-
2、Slot分配不均衡導致傾斜;
-
3、Hash Tag導致傾斜。
3、資料訪問傾斜,原因就是 Hot Key
造成的,出現Hot Key
,一般下面有下面兩種方式去解決;
-
1、對 Key 進行分散處理;
-
2、使用本地快取;
參考
【Redis核心技術與實戰】https://time.geekbang.org/column/intro/100056701
【Redis設計與實現】https://book.douban.com/subject/25900156/
【Redis 的學習筆記】https://github.com/boilingfrog/Go-POINT/tree/master/redis
【Redis中的切片叢集】https://boilingfrog.github.io/2022/02/20/redis中常見的叢集部署方案/#切片叢集
【Redis 切片叢集的資料傾斜分析】https://boilingfrog.github.io/2022/06/22/Redis切片叢集的資料傾斜分析/