Redis 切片叢集的資料傾斜分析

ZhanLi發表於2022-06-22

Redis 中如何應對資料傾斜

什麼是資料傾斜

如果 Redis 中的部署,採用的是切片叢集,資料是會按照一定的規則分散到不同的例項中儲存,比如,使用 Redis ClusterCodis

資料傾斜會有下面兩種情況:

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-test1Hot-key-test2...然後將這些 Key 分散到多個例項節點中,當客戶端進行訪問的時候,隨機一個下標的 Key 進行訪問,這樣就能將流量分散到不同的例項中了,避免了一個快取節點的過載。

一般來講,可以通過新增字尾或者字首,把一個 hotkey 的數量變成 redis 例項個數 N 的倍數 M,從而由訪問一個redis key變成訪問N * M個redis key。 N*Mredis 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切片叢集的資料傾斜分析/

相關文章