在redis 3.0版本後,官方推出了redis cluster 分布式解決方案,當一個redis節點掛了可以快速地切換到另一個節點。當遇到單機內存、並發等瓶頸時,可以採用分布式方案要解決問題.
redis-cluster架構中,被設計成共有16384(2的14次方)個hash slot。每個master分得一部分slot,其算法為:hash_slot = crc16(key) mod 16384 ,這就找到對應slot。群集至少需要3主3從,且每個實例使用不同的配置文件。
在cluster架構下,默認的,一般redis-master用於接收讀寫,而redis-slave則用於備份,當有請求是在向slave發起時,會直接重定向到對應key所在的master來處理。但如果不介意讀取的是redis-cluster中有可能過期的數據並且對寫請求不感興趣時,則亦可通過readonly命令,將slave設置成可讀,然後通過slave獲取相關的key,達到讀寫分離。
redis-cluster 不可用 的情況:
1 集群主庫半數宕機(無論是否從庫存活)
2 集群某一節點的主從全數宕機。
當某個master掛掉後,在cluster集群仍然可用的前提下,由於某個master可能有多個slave,某個salve將提升為master節點,那麼就會存在競爭,那麼此時它們的選舉機制是怎樣的呢?於是我們進入了正題:
要理解下面的過程我們需要了解一些概念:
currentEpoch:
這是一個集群狀態相關的概念,可以當作記錄集群狀態變更的遞增版本號。每個集群節點,都會通過 server.cluster->currentEpoch 記錄當前的 currentEpoch。
集群節點創建時,不管是 master 還是 slave,都置 currentEpoch 為 0。當前節點接收到來自其他節點的包時,如果發送者的 currentEpoch(消息頭部會包含發送者的 currentEpoch)大於當前節點的currentEpoch,那麼當前節點會更新 currentEpoch 為發送者的 currentEpoch。因此,集群中所有節點的 currentEpoch 最終會達成一致,相當於對集群狀態的認知達成了一致。
其過程如下:
1.slave發現自己的master變為FAIL
2.發起選舉前,slave先給自己的epoch(即currentEpoch)增一,然後請求其它master給自己投票。slave是通過廣播FAILOVER_AUTH_REQUEST包給集中的每一個masters。
3.slave發起投票後,會等待至少兩倍NODE_TIMEOUT時長接收投票結果,不管NODE_TIMEOUT何值,也至少會等待2秒。
4.master接收投票後給slave響應FAILOVER_AUTH_ACK,並且在(NODE_TIMEOUT*2)時間內不會給同一master的其它slave投票。
5.如果slave收到FAILOVER_AUTH_ACK響應的epoch值小於自己的epoch,則會直接丟棄。一旦slave收到多數master的FAILOVER_AUTH_ACK,則聲明自己贏得了選舉。
6.如果slave在兩倍的NODE_TIMEOUT時間內(至少2秒)未贏得選舉,則放棄本次選舉,然後在四倍NODE_TIMEOUT時間(至少4秒)後重新發起選舉。
只所以強制延遲至少0.5秒選舉,是為確保master的fail狀態在整個集群內傳開,否則可能只有小部分master知曉,而master只會給處於fail狀態的master的slaves投票。如果一個slave的master狀態不是fail,則其它master不會給它投票,Redis通過八卦協議(即Gossip協議,也叫謠言協議)傳播fail。而在固定延遲上再加一個隨機延遲,是為了避免多個slaves同時發起選舉。
延遲計算公式:
DELAY = 500ms + random(0 ~ 500ms) + SLAVE_RANK * 1000ms
SLAVE_RANK表示此slave已經從master複製數據的總量的rank。Rank越小代表已複製的數據越新。這種方式下,持有最新數據的slave將會首先發起選舉(理論上)。