Redis集群搭建及選舉原理

2020-03-17     sandag

redis集群簡述

哨兵模式中如果主從中 master宕機了,是通過哨兵來選舉出新的master,在這個選舉切換主從的過程,整個redis服務是不可用的。而且哨兵模式中只有一個主節點對外提供服務,因此沒法支持更高的並發。而且當個主節點的內存設置也不宜過大。否則會導致持久化文件過大,影響數據恢復或主從同步的效率。

redis集群是由 一系列的 主從節點群組成的分布式伺服器群,它具有複製、高可用和分片特性。 Redis集群不需要 sentinel哨兵也能完成節點移除和故障轉移的功能。需要將每個節點設置成集群模式,這種集群模式沒有中心節點 ,客戶端通過 CRC16算法對key進行hash

得到一個值,來判斷該 key存儲在哪個主從服務上面,因此就算是某一個主從整個宕機,redis集群也是部分可用的。方便 水平擴展, 可以根據業務規模可以隨時加減配置。 據官方文檔稱可以線性擴展到上萬個節點 ( 但是 官方推薦不超過 1000個節點)。redis集群的性能和高可用性均優於哨兵模式 。

Redis 集群搭建

1. 修改 redis.conf 配置文件

  1. daemonize yes 後台啟動
  2. cluster-enabled yes 開啟集群模式
  3. cluster-config-file nodes-6379.conf 集群配置信息存放文件名
  4. cluster-node-timeout 5000 節點離線時間限制,到達此值時發起某個主從重新選舉 master
  5. protected-mode no 關閉保護模式
  6. requirepass xxx 設置本機密碼
  7. masterauth xxx 設置訪問別的機器的密碼

2. 注意關閉伺服器的防火牆,否則可能造成節點之間無法通信,無法搭建集群

使用修改好的配置文件啟動 redis 服務,我這裡使用三個一主一從來搭建。因此先將 6 個 redis 服務使用指定的配置文件 redis-master.conf 啟動起來: src/redis-server redis-master.conf

3.搭建集群服務

為了保險起見最好先檢查下每台機器的 redis 服務是否正常啟動了 ps -ef|grep redis

可以看見 redis 服務進程後面有個 cluster 的標誌,普通啟動的 redis 服務是沒有這個標誌的

5.0 版本可以直接使用 C 語言客戶端提供的指令去構建集群:

src/redis-cli -a xxx --cluster create --cluster-replicas 1 192.168.0.67:6379 192.168.0.68:6379 192.168.0.69:6379 192.168.0.70:6379 192.168.0.71:6379 192.168.0.72:6379

-a 配置的密碼

--cluster create 表示集群創建

--cluster-replicas 表示每個 master 幾個 slave ,上面一共 6 個 redis 節點,因此會構建三個一主一從。

執行命令之前,如果你的 redis 環境以前搭建過主從或者哨兵之類的,數據不幹凈可能會報錯,最好將持久化文件刪掉,然後 flushdb ,將以前髒數據清理掉,否則可能出現如下錯誤:

正常執行會返回一個集群分配計劃,我們按照它的計劃即可:

然後節點之間就開始通信構建集群,最後會看見 16384 個 slots 分配完畢,可以看見構建計劃中有三個 master ,每個 master 都是有指定槽位的。意思就是存入的 key 經過 crc16 hash 算法之後得到的值,在哪個範圍內,就存儲到那個 redis 主從上面去,這就是 redis 的分片集群模式。

Redis集群搭建及選舉原理

至此集群搭建完畢

4.集群操作

以集群方式連接 redis 客戶端通過 cluster info 查看集群信息,通過 cluster nodes 查看節點信息

src/redis-cli -a 密碼 -c 集群方式連接

我們設置 set abc 123 一個值 會看見客戶點會計算 abc 的 slot 是 7638 , 然後重定向到對應的主從的 master 上面去寫數據

現在我看下 java 客戶端的 jedis 裡面的 key 值計算 redis.clients.util.JedisClusterCRC16#getSlot(java.lang.String) :

最後計算結果就會落到 0-16383 之間去。

當 Redis Cluster 的客戶端來連接集群時,它也會得到一份集群的槽位配置信息並將其緩存在客戶端本地。這樣當客戶 端要查找某個 key 時,可以直接定位到目標節點。同時因為槽位的信息可能會存在客戶端與伺服器不一致的情況,還需 要糾正機制來實現槽位信息的校驗調整。

集中式集群和分片式集群

Redis 節點之間使用的是 gossip 協議進行通信,每個節點之間都會互相通信。

gossip 協議包含多種消息,包括 ping , pong , meet , fail 等等。

ping :每個節點都會頻繁給其他節點發送 ping ,其中包含自己的狀態還有自己維護的集群元數據,互相通過 ping 交換元數據;

pong: 返回 ping 和 meet ,包含自己的狀態和其他信息,也可以用於信息廣播和更新;

fail: 某個節點判斷另一個節點 fail 之後,就發送 fail 給其他節點,通知其他節點,指定的節點宕機了。

meet :某個節點發送 meet 給新加入的節點,讓新節點加入集群中,然後新節點就會開始與其他節點進行通信,不需要發送形成網絡的所需的所有 CLUSTER MEET 命令。發送 CLUSTER MEET 消息以便每個節點能夠達到其他每個節點只需通 過一條已知的節點鏈就夠了。由於在心跳包中會交換 gossip 信息,將會創建節點間缺失的連結。

gossip 協議的優點在於元數據的更新比較分散,不是集中在一個地方,更新請求會陸陸續續,打到所有節點上去更新, 有一定的延時,降低了壓力;缺點在於元數據更新有延時可能導致集群的一些操作會有一些滯後。

就是自己提供服務的埠號 +10000 ,比如 6379 ,那麼用於節點間通信 的就是 16379 埠。 每個節點每隔一段時間都會往另外幾個節點發送 ping 消息,同時其他幾點接收到 ping 消息之後返回 pong 消息。

還有就是集中式的,比如 ZK 集群

集中式的有點在於數據的更新和讀取,時效性非常好,一旦元數據出現變更立即就會更新到集中式( master )的存儲中,其他節點讀取的 時候立即就可以立即感知到;不足在於所有的元數據的更新壓力全部集中在一個地方,可能導致元數據的存儲壓力。

Redis 集群選舉機制

當 slave發現自己的master變為FAIL狀態時,便嘗試 發起選舉 ,以期成為新的 master。由於掛掉的master可能會有 多個 slave,從而存在多個slave競爭成為master節點的過程, 其過程如下:

1.slave發現自己的master變為FAIL

2.將自己記錄的集群currentEpoch(選舉輪次標記)加1,並廣播信息給集群中其他節點

3.其他節點收到該信息,只有master響應,判斷請求者的合法性,並發送結果

4.嘗試選舉的slave收集master返回的結果,收到 超過半數 master的統一 後變成新 Master

5.廣播Pong消息通知其他集群節點。

如果這次選舉不成功,比如三個小的主從 A,B,C組成的集群,A的master掛了,A的兩個小弟發起選舉,結果B的master投給A的小弟A1,C的master投給了A的小弟A2,這樣就會發起第二次選舉,選舉輪次標記+1繼續上面的流程。事實上從節點並不是在主節點一進入 FAIL 狀態就馬上嘗試發起選舉,而是有一定延遲,一定的延遲確保我們等待FAIL狀態在集群中傳播,slave如果立即嘗試選舉,其它masters或許尚未意識到FAIL狀態,可能會拒絕投票。 同時下面公式裡面的隨機數,也可以有效避免slave同時發起選舉,導致的平票情況。

•延遲計算公式:

DELAY = 500ms + random(0 ~ 500ms) + SLAVE_RANK * 1000ms

•SLAVE_RANK表示此slave已經從master複製數據的總量的rank。Rank越小代表已複製的數據越新。這種方式下,持有最新數據的slave將會首先發起選舉(理論上)。

前面說到這種分片的集群模式的集群可以部分提供服務, 當 redis.conf的配置cluster-require-full-coverage為no時, 表示當一個小主從整體掛掉的時候集群也可以用,也是說 0-16383個槽位中,落在該主從對應的slots上面的key是用不了的,但是如果key落在其他的範圍是仍然可用的。

文章來源: https://twgreatdaily.com/zh-tw/eItW8nABiuFnsJQVeB-S.html