超高併發下 Redis 分 key 的實現原理
衆所周知 Redis 扛併發的能力是非常強的,所以高併發場景下經常會使用 Redis,但是 Redis 單分片的寫入瓶頸在 2w 左右,讀瓶頸在 10w 左右,如果在超高併發下即使是集羣部署 Redis,單分片的 Redis 也是有可能扛不住的,如下圖所示:
雖然 Redis 做了集羣部署,但是 Redis 的 key 只會存在一個分片上,此時超高併發下 redis1 很有可能會被打垮。那麼在超高的併發如何解決某個熱 key 帶來的單分片被打垮的問題呢?下面聊聊 Redis 分 key 來解決這個問題的方案。
1、什麼是 Redis 分 key
Redis 分 key 就是將一個熱點 key 通過拆分成若干 key,然後讓這若干個 key 分散到 Redis 集羣的不同節點,如下圖所示:
將熱點 key 拆分成 3 個小 key,然後通過 Redis 的算法將這 3 個 key 分散到 Redis 集羣的分片上(集羣有多少個分片,就拆分成幾個 key)。這樣由原先的一個 key 拆分成 3 個小 key,在超高併發下由這 3 個 key 共同的來承擔原先一個熱點 key 扛的流量。
2、拆分後的 key 分散到集羣的分片上
拆分 key 的思路可以很好的解決單個熱點 key 可能打垮 Redis 集羣中某個分片的問題,但是我們如何保證一個小 key 落到一個分片上呢?首先我們來回顧一下 Redis 集羣中 key 落分片的原理,如下所示的 Redis 的集羣:
從原理上分析 key 落在哪個節點上是經過了兩次的映射,第一次映射是 CRC16 計算出來 key 哈希值除以 16384 之後得到是對應的槽,第二次映射是槽映射到 redis 的節點,這樣可以知道 key 落在哪個分片上。
根據上述的原理,我們可以通過 Redis 的命令來獲取 Redis 集羣上的集羣關係來計算 key 落在哪個分片上。我們現在爲了保證一個 key 落在一個分片上,可以通過手動的方式來設置 key,設置的過程如下:
(1)手寫第一個 key_longxia,然後自己手動根據 CRC16 和槽映射關係之後就知道它落到了哪個節點(假設是 redis0 上)如下所示:
(2)準備第二個 key(如 key_longxia01),假設計算之後發現也落到了 redis0 上,那麼我們換一個 key(如 key_biancheng), 經過計算發現其落在 redis1 上,如下所示:
(3)同樣的方式,準備第三個 key(如 key_long), 保證其可以落在 redis2 上即可,如下所示:
分 key 的時候,我們不要追求 key 是有規律的了,可以隨便加點前綴與後綴,只要保證每個小 key 都分散到集羣的分片上即可。
通過上述的試探我們得到了 3 個拆分後的小 key,並且這些小 key 可以落到集羣的節點上,整理出這些拆分後的 key 如下所示:
3、分 key 的工作原理
經過手動嘗試出來的三個 key 我們寫固定到代碼中(或者放在配置中心上)。當業務請求過來之後,我們可以通過業務 id 與拆分出來的 key 數量取餘數的方式映射出當前請求打到哪個 key 上(如 key_longxia), 然後通過這個可以經過 redis 的兩次映射找到對應的節點,找到節點後就可以操作數據了。
總結:
(1)Redis 分可以的原理就是將一個熱點 key 拆分成若干個小 key 後分散不集羣的不同節點上(集羣有幾個節點就拆分成幾個小 key)
(2)爲保證 key 可以分散到集羣節點上,採用的是手動嘗試的方式來獲取拆分後的小 key。
(3)分 key 的方案常用於超高併發業務場景下,如搶優惠券、實時榜單等。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/KSt6JIhoPx0Vx-l1wXTRmw