節點 | 處理槽位 |
---|---|
A | 0 - 5000 |
B | 5001 - 10000 |
C | 10001 - 16383 |
每個Redis實例會自己維護一份slot - Redis節點的映射關系,假設你在節點A上設置了某個key,但是這個key通過CRC16計算出來的槽位是由節點B維護的,那么就會提示你需要去節點B上進行操作。
slot-to-node
不知道你思考過一個問題沒,如果Redis Cluster中的某個master節點掛了,它是如何保證集群自身的高可用的?如果這個時候我們集群需要擴容節點,它該負責哪些槽位呢?我們一個一個問題的來看一下。
我們開篇聊過,Redis Cluster可以很方便的進行橫向擴容,那當新的節點加入進來的時候,它是如何獲取對應的slot的呢?
答案是通過reshard(重新分片)來實現。reshard可以將已經分配給某個節點的任意數量的slot遷移給另一個節點,在Redis內部是由redis-trib負責執行的。你可以理解為Redis其實已經封裝好了所有的命令,而redis-trib則負責向獲取slot的節點和被轉移slot的節點發送命令來最終實現reshard。
假設我們需要向集群中加入一個D節點,而此時集群內已經有A、B、C三個節點了。
此時redis-trib會向A、B、C三個節點發送遷移出槽位的請求,同時向D節點發送準備導入槽位的請求,做好準備之后A、B、C這三個源節點就開始執行遷移,將對應的slot所對應的鍵值對遷移至目標節點D。最后redis-trib會向集群中所有主節點發送槽位的變更信息。
Redis Cluster中保證集群高可用的思路和實現和Redis Sentinel如出一轍
簡單來說,針對A節點,某一個節點認為A宕機了,那么此時是主觀宕機。而如果集群內超過半數的節點認為A掛了, 那么此時A就會被標記為客觀宕機。
一旦節點A被標記為了客觀宕機,集群就會開始執行故障轉移。其余正常運行的master節點會進行投票選舉,從A節點的slave節點中選舉出一個,將其切換成新的master對外提供服務。當某個slave獲得了超過半數的master節點投票,就成功當選。
cluster-failover
當選成功之后,新的master會執行slaveof no one
來讓自己停止復制A節點,使自己成為master。然后將A節點所負責處理的slot,全部轉移給自己,然后就會向集群發PONG消息來廣播自己的最新狀態。
按照一致性哈希的思想,如果某個節點掛了,那么就會沿著那個圓環,按照順時針的順序找到遇到的第一個Redis實例。
而對于Redis Cluster,某個key它其實并不關心它最終要去到哪個節點,他只關心他最終落到哪個slot上,無論你節點怎么去遷移,最終還是只需要找到對應的slot,然后再找到slot關聯的節點,最終就能夠找到最終的Redis實例了。
那這個PONG消息又是什么東西呢?別急,下面就會聊到。
這就是Redis Cluster各個節點之間交換數據、通信所采用的一種協議,叫做gossip。
gossip: 流言、八卦、小道消息
gossip是在1989年的論文上提出的,我看了一堆資料都說的是1987年發表的,但是文章里的時間明確是1989年1月份發表。
image-20201215100703648
感興趣的可以去看看Epidemic Algorithms for Replicated . Database Maintenance,在當時提出gossip主要是為了解決在分布式數據庫中,各個副本節點的數據同步問題。但隨著技術的發展,gossip后續也被廣泛運用于信息擴散、故障探測等等。
Redis Cluster就是利用了gossip來實現自身的信息擴散的。那使用gossip具體是如何通信的呢?
gossip
很簡單,就像圖里這樣。每個Redis節點每秒鐘都會向其他的節點發送PING,然后被PING的節點會回一個PONG。
Redis Cluster中,節點之間的消息類型有5種,分別是MEET、PING、PONG、FAIL和PUBLISH。這些消息分別傳遞了什么內容呢?我簡單總結了一下。
消息類型 | 消息內容 |
---|---|
MEET | 給某個節點發送MEET消息,請求接收消息的節點加入到集群中 |
PING | 每隔一秒鐘,選擇5個最久沒有通信的節點,發送PING消息,檢測對應的節點是否在線;同時還有一種策略是,如果某個節點的通信延遲大于了cluster-node-time的值的一半,就會立即給該節點發送PING消息,避免數據交換延遲過久 |
PONG | 當節點接收到MEET或者PING消息之后,會回一個PONG消息給發送方,代表自己收到了MEET或者PING消息。同時,節點也可以主動的通過PONG消息向集群中廣播自己的信息,讓其他節點獲取到自己最新的屬性,就像完成了故障轉移之后新的master向集群發送PONG消息一樣 |
FAIL | 用于廣播自己的對某個節點的宕機判斷,假設當前節點對A節點判斷為宕機,就會立即向Redis Cluster廣播自己對于A節點的判斷,所有收到消息的節點就會對A節點做標記 |
PUBLISH | 用于向指定的Channel發送消息,某個節點收到PUBLISH消息之后會直接在集群內廣播,這樣一來,客戶端無論連接到任何節點都能夠訂閱這個Channel |
既然Redis Cluster選擇了gossip,那肯定存在一些gossip的優點,我們接下來簡單梳理一下。 gossip可以在O(logN) 輪就可以將信息傳播到所有的節點,為什么是O(logN)呢?因為每次ping,當前節點會帶上自己的信息外加整個Cluster的1/10數量的節點信息,一起發送出去。你可以簡單的把這個模型抽象為: 你轉發了一個特別有意思的文章到朋友圈,然后你的朋友們都覺得還不錯,于是就一傳十、十傳百這樣的散播出去了,這就是朋友圈的裂變傳播。 當然,gossip仍然存在一些缺點。例如消息可能最終會經過很多輪才能到達目標節點,而這可能會帶來較大的延遲。同時由于節點會隨機選出5個最久沒有通信的節點,這可能會造成某一個節點同時收到n個重復的消息。 總的來說,Redis Cluster相當于是把Redis的主從架構和Sentinel集成到了一起,從Redis Cluster的高可用機制、判斷故障轉移以及執行故障轉移的過程,都和主從、Sentinel相關,這也是為什么我在之前的文章里說,主從是Redis高可用架構的基石。 以上就是解析Redis Cluster原理的詳細內容,更多關于Redis Cluster的資料請關注腳本之家其它相關文章!十一、使用gossip的優劣
優點
描述
擴展性
網絡可以允許節點的任意增加和減少,新增加的節點的狀態最終會與其他節點一致。
容錯性
由于每個節點都持有一份完整元數據,所以任何節點宕機都不會影響gossip的運行
健壯性
與容錯性類似,由于所有節點都持有數據,地位平臺,是一個去中心化的設計,任何節點都不會影響到服務的運行
最終一致性
當有新的信息需要傳遞時,消息可以快速的發送到所有的節點,讓所有的節點都擁有最新的數據
十二、總結
下一篇:比較幾種Redis集群方案