1. 程式人生 > 資料庫 >redis 哨兵和 叢集

redis 哨兵和 叢集

哨兵模式

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

 

哨兵們是怎麼感知整個系統中的所有節點(主節點/從節點/哨兵節點)的

  1. 首先主節點的資訊是配置在哨兵(Sentinel)的配置檔案中
  2. 哨兵節點會和配置的主節點建立起兩條連線命令連線訂閱連線
  3. 哨兵會通過命令連線每10s傳送一次INFO命令,通過INFO命令,主節點會返回自己的run_id和自己的從節點資訊
  4. 哨兵會對這些從節點也建立兩條連線命令連線訂閱連線
  5. 哨兵通過命令連線向從節點發送INFO
    命令,獲取到他的一些資訊
    a. run_id
    b. role
    c. 從伺服器的複製偏移量 offset
    d. 等
  6. 因為哨兵對與叢集中的其他節點(主從節點)當前都有兩條連線,命令連線訂閱連線
    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對故障進行遷移

故障遷移

  1. 在從節點中挑選出新的主節點
    a. 通訊正常
    b. 優先順序排序
    c. 優先順序相同是選擇offset最大的
  2. 將該節點設定成新的主節點 SLAVEOF no one,並確保在後續的INGO命令時,該節點返回狀態為master
  3. 將其他的從節點設定成從新的主節點複製, SLAVEOF命令
  4. 將舊的主節點變成新的主節點的從節點

優缺點

  • 優點
    高可用,在主節點故障時能實現故障的轉移
  • 缺點:好像沒辦法做到水平拓展,如果內容很大的情況下

叢集模式

官方提供的分散式方案(槽指派/重新分片/故障轉移)
叢集內的節點,都會有個資料結構儲存整個叢集內的節點資訊

//整體
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.如果找某個槽是哪個節點負責,只需要獲取方式一的列表,一查就知道

重新分片

將已經指派給節點的槽,重新執行新的節點。

 

故障轉移

發現故障節點

  1. 叢集內的節點會向其他節點發送PING命令,檢查是否線上
  2. 如果未能在規定時間內做出PONG響應,則會把對應的節點標記為疑似下線
  3. 叢集中一半以上負責處理槽的主節點都將主節點X標記為疑似下線的話,那麼這個主節點X就會被認為是已下線
  4. 向叢集廣播主節點X已下線,大家收到訊息後都會把自己維護的結構體裡的主節點X標記為已下線

從節點選舉

  1. 當從節點發現自己複製的主節點已下線了,會向叢集裡面廣播一條訊息,要求所有有投票權的節點給自己投票(所有負責處理槽的主節點都有投票權)
  2. 主節點會向第一個給他發選舉訊息的從節點回復支援
  3. 當支援數量超過N/2+1的情況下,該從節點當選新的主節點

故障的遷移

  1. 新當選的從節點執行 SLAVEOF no one,修改成主節點
  2. 新的主節點會撤銷所有已下線的老的主節點的槽指派,指派給自己
  3. 新的主節點向叢集傳送命令,通知其他節點自己已經變成主節點了,負責哪些槽指派
  4. 新的主節點開始處理自己負責的槽的命令

叢集模式和哨兵模式的區別

  1. 哨兵模式監控權交給了哨兵系統,叢集模式中是工作節點自己做監控
  2. 哨兵模式發起選舉是選舉一個leader哨兵節點來處理故障轉移,叢集模式是在從節點中選舉一個新的主節點,來處理故障的轉移