簡介
Redis Cluster 是 在 3.0 版本正式推出的高可用集群方案,相比Redis Sentinel,Redis Cluster方案不需要額外部署Sentinel集群,而是通過集群內(nèi)部通信實現(xiàn)集群監(jiān)控净捅,故障時主從切換;同時,支持內(nèi)部基于哈希實現(xiàn)數(shù)據(jù)分片廉羔,支持動態(tài)水平擴容;某節(jié)點宕機只會影響該節(jié)點的槽位僻造,不會影響到其他主節(jié)點
拓撲
Redis 集群是一個網(wǎng)狀結(jié)構(gòu)憋他,無中心結(jié)構(gòu),每個節(jié)點都通過 TCP 連接跟其他每個節(jié)點連接髓削。
在一個有 N 個節(jié)點的集群中竹挡,每個節(jié)點都有 N-1 個流出的 TCP 連接,和 N-1 個流入的連接立膛。 這些 TCP 連接會永久保持揪罕,并不是按需創(chuàng)建的。
節(jié)點們使用一個 gossip 協(xié)議來傳播集群的信息:發(fā)現(xiàn)新的節(jié)點宝泵、 發(fā)送ping包(用來確保所有節(jié)點都在正常工作中)好啰、在特定情況發(fā)生時發(fā)送集群消息。集群連接也用于在集群中發(fā)布或訂閱消息儿奶。
集群中有多個主節(jié)點框往,每個主節(jié)點有多個從節(jié)點,主從節(jié)點間數(shù)據(jù)一致闯捎,最少需要3個主節(jié)點椰弊,每個主節(jié)點最少需要1個從節(jié)點
- 高可用:當master節(jié)點故障時许溅,自動主從切換
- 高性能:主節(jié)點提供讀寫服務(wù),從節(jié)點只讀服務(wù)秉版,提高系統(tǒng)吞吐量
- 可擴展性:集群的數(shù)據(jù)分片存儲贤重,主節(jié)點間數(shù)據(jù)各不同,各自維護對應(yīng)數(shù)據(jù)沐飘,可以為集群添加節(jié)點進行擴容游桩,也可以下線部分節(jié)點進行水平縮容
gossip 協(xié)議
原理:所有節(jié)點都持有一份元數(shù)據(jù),不同的節(jié)點如果出現(xiàn)了元數(shù)據(jù)的變更耐朴,就不斷將元數(shù)據(jù)發(fā)送給其它的節(jié)點借卧,讓其它節(jié)點也進行元數(shù)據(jù)的變更。
gossip 協(xié)議包含多種消息筛峭,包含 ping,pong,meet,fail 等等
- meet:某個節(jié)點發(fā)送 meet 給新加入的節(jié)點铐刘,讓新節(jié)點加入集群中,然后新節(jié)點就會開始與其它節(jié)點進行通信影晓。
- ping:每個節(jié)點都會頻繁給其它節(jié)點發(fā)送 ping镰吵,其中包含自己的狀態(tài)還有自己維護的集群元數(shù)據(jù),互相通過 ping 交換元數(shù)據(jù)挂签。
- pong:返回 ping 和 meeet疤祭,包含自己的狀態(tài)和其它信息,也用于信息廣播和更新饵婆。
- fail:某個節(jié)點判斷另一個節(jié)點 fail 之后勺馆,就發(fā)送 fail 給其它節(jié)點,通知其它節(jié)點說侨核,某個節(jié)點宕機
數(shù)據(jù)分區(qū)
槽是 Redis 集群管理數(shù)據(jù)的基本單位
redis cluster 有固定的 16384 個 hash slot草穆,對每個 key 計算 CRC16 值,然后對 16384 取模搓译,可以獲取 key 對應(yīng)的 hash slot悲柱,利用鏈表解決哈希沖突
公式:HASH_SLOT = CRC16(key) mod 16384
redis cluster 中每個 master 都會持有部分 slot,比如有 3 個 master些己,那么可能每個 master 持有 5000 多個 hash slot豌鸡。hash slot 讓 node 的增加和移除很簡單,增加一個 master段标,就將其他 master 的 hash slot 移動部分過去涯冠,減少一個 master,就將它的 hash slot 移動到其他 master 上去怀樟。移動 hash slot 的成本是非常低的功偿。
每個集群節(jié)點維護著一個16384 bit (2KB)的位數(shù)組盆佣,每個bit對應(yīng)相同編號的槽往堡,用 0 / 1標識對于某個槽自己是否擁有
集群節(jié)點同時還維護著槽到集群節(jié)點的映射械荷,是由長度為16384,數(shù)組下標代表槽編號虑灰,值為節(jié)點信息的數(shù)組
作者之所以設(shè)計16384個槽位吨瞎,主要原因就是集群節(jié)點間每次ping都需要發(fā)送自己2KB的槽位數(shù)組,設(shè)置的槽位太大會增加傳輸消耗
hash tag
默認情況下穆咐,key在哪個slot上由key進行哈希后的結(jié)果決定颤诀,但有的時候我們希望把同一批相關(guān)的key存放到同一個slot上,提升性能與保證原子性对湃,這時就可以利用hash tag崖叫。
假設(shè)一個key是9999:order,表示用戶ID為9999的訂單信息拍柒,只需要用{}將key中我們需要進行哈希計算那部分包起來心傀,即{9999}:order;另外其他的{9999}:user同樣可以這樣操作
這樣就將同一個用戶的所有相關(guān)信息都放到了同一個哈希槽中
高可用
- 判斷節(jié)點宕機:如果一個節(jié)點認為某個節(jié)點 pfail 了拆讯,那么會在 gossip ping 消息中脂男,ping 給其他節(jié)點,如果超過半數(shù)的節(jié)點都認為 pfail 了种呐,那么就會變成 fail
- 從節(jié)點選舉:每個從節(jié)點宰翅,都根據(jù)自己對 master 復(fù)制數(shù)據(jù)的 offset,來設(shè)置一個選舉時間爽室,offset 越大(復(fù)制數(shù)據(jù)越多)的從節(jié)點汁讼,選舉時間越靠前,優(yōu)先進行選舉肮之。所有的 master node 開始 slave 選舉投票掉缺,給要進行選舉的 slave 進行投票,如果大部分 master node(N/2 + 1)都投票給了某個從節(jié)點戈擒,那么選舉通過眶明,那個從節(jié)點可以切換成 master。
從節(jié)點執(zhí)行主備切換筐高,從節(jié)點切換為主節(jié)點搜囱。
集群客戶端
基于重定向的客戶端,很消耗網(wǎng)絡(luò)IO柑土,因為大部分情況下蜀肘,可能都會出現(xiàn)一次請求重定向,才能找到正確的節(jié)點稽屏。
JedisCluster初始化時會隨機選擇一個節(jié)點獲取集群元數(shù)據(jù)扮宠,初始化hash slot對應(yīng)jedisPool的Map映射表,后續(xù)的操作如下狐榔,無需通過集群的重定向來執(zhí)行命令:
- 把key作為參數(shù)坛增,執(zhí)行CRC16算法获雕,獲取key對應(yīng)的slot值
- 通過該slot值,去slots的map集合中獲取jedisPool實例
- 通過jedisPool實例獲取jedis實例收捣,最終完成redis數(shù)據(jù)存取工作