哨兵模式
哨兵模式是redis高可用
的實現方式之一
使用一個或者多個哨兵(Sentinel)實例組成的系統,對redis節點進行監控,在主節點出現故障的情況下,能將從節點中的一個升級為主節點,進行故障轉義,保證系統的可用性。

哨兵們是怎么感知整個系統中的所有節點(主節點/從節點/哨兵節點)的
- 首先主節點的信息是配置在哨兵(Sentinel)的配置文件中
- 哨兵節點會和配置的主節點建立起兩條連接
命令連接
和訂閱連接
- 哨兵會通過
命令連接
每10s發送一次INFO
命令,通過INFO命令
,主節點會返回自己的run_id和自己的從節點信息
- 哨兵會對這些從節點也建立兩條連接
命令連接
和訂閱連接
- 哨兵通過
命令連接
向從節點發送INFO
命令,獲取到他的一些信息
a. run_id
b. role
c. 從服務器的復制偏移量 offset
d. 等 - 因為哨兵對與集群中的其他節點(主從節點)當前都有兩條連接,
命令連接
和訂閱連接
a. 通過命令連接
向服務器的_sentinel:hello
頻道發送一條消息,內容包括自己的ip端口、run_id、配置紀元(后續投票的時候會用到)等
b. 通過訂閱連接
對服務器的_sentinel:hello
頻道做了監聽,所以所有的向該頻道發送的哨兵的消息都能被接受到
c. 解析監聽到的消息,進行分析提取,就可以知道還有那些別的哨兵服務節點也在監聽這些主從節點了,更新結構體將這些哨兵節點記錄下來
d. 向觀察到的其他的哨兵節點建立命令連接
----沒有訂閱連接
哨兵模式下的故障遷移
主觀下線
哨兵(Sentinel)節點會每秒一次的頻率向建立了命令連接的實例發送PING命令,如果在down-after-milliseconds
毫秒內沒有做出有效響應包括(PONG/LOADING/MASTERDOWN)以外的響應,哨兵就會將該實例在本結構體中的狀態標記為SRI_S_DOWN
主觀下線
客觀下線
當一個哨兵節點發現主節點處於主觀下線狀態是,會向其他的哨兵節點發出詢問,該節點是不是已經主觀下線了。如果超過配置參數quorum
個節點認為是主觀下線時,該哨兵節點就會將自己維護的結構體中該主節點標記為SRI_O_DOWN
客觀下線
詢問命令SENTINEL is-master-down-by-addr <ip> <port> <current_epoch> <run_id>
參數 | 意義 |
---|---|
ip/port | 當前認為下線的主節點的ip和端口 |
current_epoch | 配置紀元 |
run_id | *標識僅用於詢問是否下線 有值標識該哨兵節點希望對方將自己設置為leader 詢問時用*,選舉時用run_id |
leader選舉
在認為主節點客觀下線
的情況下,哨兵節點節點間會發起一次選舉,命令還是上面的命令SENTINEL is-master-down-by-addr <ip> <port> <current_epoch> <run_id>
,只是run_id
這次會將自己的run_id
帶進去,希望接受者將自己設置為主節點。如果超過半數以上的節點返回將該節點標記為leader的情況下,會有該leader對故障進行遷移
故障遷移
- 在從節點中挑選出新的主節點
a. 通訊正常
b. 優先級排序
c. 優先級相同是選擇offset最大的 - 將該節點設置成新的主節點
SLAVEOF no one
,並確保在后續的INGO命令時,該節點返回狀態為master - 將其他的從節點設置成從新的主節點復制,
SLAVEOF命令
- 將舊的主節點變成新的主節點的從節點
優缺點
- 優點
高可用,在主節點故障時能實現故障的轉移 - 缺點:好像沒辦法做到水平拓展,如果內容很大的情況下
集群模式
官方提供的分布式方案(槽指派/重新分片/故障轉移)
集群內的節點,都會有個數據結構存儲整個集群內的節點信息
//整體 struct clusterState{ clusterNode *mySelf; .... dict *nodes; //集群內的所有節點 } // 單個節點 struct clusterNode { char name[]; char ip[]; int port; clusterLink *link; //保存節點間,連接的信息 int flags; //狀態標記 } //節點間連接的信息 struct clusterLink{ mstime_t ctime; //創建時間 int fd; //tcp套接字描述符 sds sndbuf; // 輸出緩存區 sds rcvbuf; //輸入緩存區 struct clusterNode *node; }

槽指派
redis集群可以被分為16384個槽,只有這些槽全被指派了處理的節點的情況下,集群的狀態才能是上線狀態(ok)
操作redis集群的時候,將key作為參數,就可以計算出對應的處理槽上,所以存儲等操作都應該在該槽對應的節點上。通過這種方式,可以完美的實現集群存儲的水平拓展。
def slot_number(key): return CRC16(key) & 16383 //得到的結果就是槽的序號
槽指派的信息是怎么存儲的
struct clusterState{ clusterNode *slots[16384] } struct clusterNode{ unsigned char slots[16384/8] }
通過上面兩個結構體中的定義可以看出,槽指派的信息是分了兩種方式,保存在結構體里面。


分兩種存儲的好處
1. 如果需要判斷某一個節點負責的槽,只需要獲取方式二中的數組做判斷就可以
2.如果找某個槽是哪個節點負責,只需要獲取方式一的列表,一查就知道
重新分片
將已經指派給節點的槽,重新執行新的節點。

故障轉移
發現故障節點
- 集群內的節點會向其他節點發送PING命令,檢查是否在線
- 如果未能在規定時間內做出PONG響應,則會把對應的節點標記為疑似下線
- 集群中一半以上
負責處理槽的主節點
都將主節點X標記為疑似下線的話,那么這個主節點X就會被認為是已下線
- 向集群廣播主節點X
已下線
,大家收到消息后都會把自己維護的結構體里的主節點X標記為已下線
從節點選舉
- 當從節點發現自己復制的主節點已下線了,會向集群里面廣播一條消息,要求所有有投票權的節點給自己投票(
所有負責處理槽的主節點都有投票權
) - 主節點會向第一個給他發選舉消息的從節點回復支持
- 當支持數量超過N/2+1的情況下,該從節點當選新的主節點
故障的遷移
- 新當選的從節點執行
SLAVEOF no one
,修改成主節點 - 新的主節點會撤銷所有已下線的老的主節點的槽指派,指派給自己
- 新的主節點向集群發送命令,通知其他節點自己已經變成主節點了,負責哪些槽指派
- 新的主節點開始處理自己負責的槽的命令
集群模式和哨兵模式的區別
- 哨兵模式監控權交給了哨兵系統,集群模式中是工作節點自己做監控
- 哨兵模式發起選舉是選舉一個leader哨兵節點來處理故障轉移,集群模式是在從節點中選舉一個新的主節點,來處理故障的轉移
轉自:https://www.jianshu.com/p/d6d2325a5ec7