Redis技術知識總結之五——Redis集羣模式

接上篇《Redis技術知識總結之四——Redis內存優化》

五. Redis 集羣模式

參考地址:
《redis三種模式對比》

Redis 集羣模式有三種:主從模式(Redis 2.8 版本之前)、哨兵模式(Redis 3.0 之前)、集羣模式(Redis 3.0 之後)。

5.1 主從模式

同 Mysql 主從複製的原因一樣,Redis 雖然讀取寫入的速度都特別快,但是也會產生讀壓力特別大的情況。爲了分擔讀壓力,Redis 支持主從複製,Redis 的主從結構可以採用一主多從,或者級聯結構,Redis 主從複製可以根據是否是全量分爲全量同步和增量同步。下圖爲級聯結構。
Redis主從模式級聯
Redis 全量複製一般發生在 Slave 初始化階段,這是 Slave 需要將 Master 上的所有數據都複製一份。具體步驟如下:

  1. Slave 服務器連接 Master 服務器,發送 SYNC 指令;
  2. Master 服務器接收到 SYNC 指令後,開始執行 BGSAVE 指令,生成 RDB 文件,並使用緩衝區記錄生成 RDB 文件的這段時間裏執行的所有寫命令
  3. Master 服務器 BGSAVE 執行完畢,想所有 Slave 服務器發送快照文件,並在發送期間繼續記錄被執行的寫命令
  4. Slave 服務器收到快照文件後,丟棄所有舊數據,載入收到的快照;
  5. Master 服務器快照發送完畢後,開始向 Slave 服務器發送緩衝區的寫命令;
  6. Slave 服務器完成對快照的載入,開始接受發來的寫命令請求,並執行來自 Master 緩衝區的寫命令。
  • 優點:
    • 用比較簡便的方式實現了讀寫分離,解決了備份問題,提高了服務器的性能;
  • 缺點:
    • 所有 Master, Slave 節點都是用 IP 和端口配置的,如果有節點故障下線,不能主動通知其他節點,只能手動修改配置的方式修復;
    • 如果 Master 節點故障,無法做到自動選舉 Master 節點,需要手動修復;
    • 無法動態擴容;

5.2 哨兵模式

哨兵 (Sentinal) 的作用是監控 Redis 服務器的狀態,可以實現在 Master 節點下線時,將其他 Slave 節點升級爲 Master 節點的功能。多個哨兵可以監控同一個 Redis 節點,哨兵與哨兵之間也可以相互監視。

5.2.1 哨兵的工作原理

哨兵進程啓動後,會讀取配置文件內容,查找到 Master 服務器的 IP 與端口,與 Master 服務器建立兩條連接。此外,只要給哨兵提供多個 Master 服務器的信息,就能實現一個哨兵監控多個 Master 服務器。
與 Master 服務器建立連接後,哨兵會按照一定頻率執行三個操作:

  1. 定期向 Master 節點發送 INFO 命令;
    • 用於發現 Master 及其 Slave 節點信息,實現節點加入的自動發現;
  2. 定期向 Master 和其 Slave 節點的哨兵頻道發送自己的信息;
    • 向 Master, Slave 共享自己的信息,用來讓其他哨兵通過這些信息發現自己,這樣就可以接收到其他哨兵給自己發的 PING 信息;此外,其他哨兵可以通過該信息判斷 master 版本,如果當前哨兵的版本更高,則進行更新;
  3. 定期向 Master, Slave 和其他哨兵發送 PING 信息,監控它們是否已經停止服務;
    • 如果 PING 的節點超時沒有回覆,則哨兵認爲該節點主觀下線
    • 如果被哨兵認爲主觀下線的節點是 Master 節點,則會向其他哨兵進行詢問,是否它們認爲該 Master 節點主觀下線。如果有半數以上的哨兵認爲 Master 節點主觀下線,則哨兵會認爲該 Master 節點客觀下線,並開始執行選舉。

認爲 Master 節點客觀下線後,故障恢復的操作需要一個領頭的哨兵執行。選舉採用 RAFT 算法:

  1. 發現 master 下線的哨兵節點(我們稱他爲 A),向每個哨兵發送命令,要求對方選自己爲領頭哨兵;
  2. 如果目標哨兵節點沒有選過其他人,則會同意選舉 A 爲領頭哨兵;
  3. 如果有超過一半的哨兵同意選舉 A 爲領頭,則 A 當選;
  4. 如果有多個哨兵節點同時參選領頭,此時有可能存在一輪投票無競選者勝出,此時每個參選的節點等待一個隨機時間後再次發起參選請求,進行下一輪投票精選,直至選舉出領頭哨兵;

選出領頭哨兵後,領頭者開始對進行故障恢復,從出現故障的 master 的從數據庫中挑選一個來當選新的 master,選擇規則如下:

  1. 所有在線的 slave 中選擇優先級最高的,優先級可以通過 slave-priority 配置;
  2. 如果有多個最高優先級的 slave,則選取複製偏移量最大(即複製越完整)的當選;
  3. 如果以上條件都一樣,選取 id 最小的 slave;

挑選出需要繼任的 slave 後,領頭哨兵向該節點發送命令,使其升格爲 master,然後再向其他 slave 發送命令接受新的 master,最後更新數據。此外,已經停止的舊的 master 更新爲新的 master 的從數據庫,使其恢復服務後以 slave 的身份繼續運行

優點:

  1. Master 狀態監測
  2. 如果 Master 異常,則會進行 Master-slave 轉換,將其中一個 Slave 作爲 Master,將之前的 Master 作爲 Slave;
  3. Master-Slave 切換後,master_redis.conf、slave_redis.conf 和sentinel.conf 的內容都會發生改變,即 master_redis.conf 中會多一行 slaveof 的配置,sentinel.conf 的監控目標會隨之調換;

缺點:

  1. 如果是從節點下線了,sentinel 是不會對其進行故障轉移的,連接從節點的客戶端也無法獲取到新的可用從節點;
  2. 無法實現動態擴容;

5.3 集羣模式

5.3.1 Redis 集羣結構

Redis 集羣模式如下圖所示,每一個藍色的圈都代表着一個 redis 的服務器節點,它們任何兩個節點之間都是相互連通的,每一個節點都存有這個集羣所有主節點以及從節點的信息。客戶端可以與任何一個節點相連接,然後就可以訪問集羣中的任何一個節點。對其進行存取和其他操作。
Redis集羣架構圖

一般集羣建議搭建三主三從架構,三主提供服務,三從提供備份功能。

5.3.2 集羣投票機制

Redis 節點之間通過互相的 ping-pong 判斷是否節點可以連接上。如果有一半以上的節點去 ping 一個節點的時候沒有迴應,集羣就認爲這個節點宕機了,然後去連接它的備用節點。這就是 Redis 的投票機制,具體原理如下圖所示:
Redis集羣投票機制

投票過程是集羣中所有 master 參與,如果半數以上 master 節點與某個 master 節點通信超時 (cluster-node-timeout),認爲該 master 節點掛掉。
整個集羣不可用的判斷條件:

  1. 如果集羣任意 master 掛掉,且當前 master 沒有 slave,這樣該 master 無法轉移,則集羣進入 FAIL 狀態;
    • 也可以理解成集羣的 slot 映射 [0-16383] 不完整時進入 FAIL 狀態;
  2. 如果集羣超過半數以上 master 掛掉,無論是否有 slave,集羣進入 FAIL 狀態.

5.3.3 Redis 集羣插槽分配

在集羣模式下,通過 cluster info 命令可以查看集羣的信息,包括每個 Redis 節點的 ID、IP+端口、身份 (master/slave)、連接數量、分配插槽 (slot) 信息。
以執行命令 set abc 123 爲例,Redis 將數據存到集羣中的步驟如下:

  1. 客戶端發送命令set abc 123,某個 Redis 節點接收到命令;
  2. 通過方法 key(“abc”) 計算出 slot 值,根據 slot 值找到對應的 Redis 節點;
    • “abc” 的 slot 值爲 7638;
  3. 重定向到該 Redis 節點,執行命令;

注:插槽與 key 的關係:
key 的有效部分使用 CRC16 算法,計算出 Hash 值,然後對 16384 取餘獲得 slot 值。有效部分指:

  1. key 值中有大括號 {} 的情況:例如 key={hello}_grq 中的 “hello”;
  2. 如果沒有大括號,則整個 key 都是有效部分;

5.3.4 Redis slot 重分配

Redis 集羣提供了 16384 個 slot,通過 Ruby 腳本 redis-trib.rb 實現 slot 平均分配給 N 個 master 節點。如果有一部分 slot 沒有指定到節點,那麼分配在這部分 slot 上的 key 值將不能使用。
但如果向集羣中加入新的 master 節點,或者將某個 master 節點刪除,則需要通過執行 redis-trib.rb 腳本實現 slot 的重分配。

5.3.4.1 新增節點

新增節點後,實現 slot 重分配的步驟如下:

  1. 執行 ruby 腳本 redis-trib.rb add-node {待添加節點 IP + 端口}
    • 添加成功後,新添加的節點沒有被分配 slot;
  2. 執行 redis-trib reshard + {待分配目的節點} 腳本命令,執行重分配操作;命令執行過程中,輸入要移動的 slot 數、待分配目的節點 ID,以及從哪裏分配節點(如果寫 “all”,則將所有 master 節點的部分 slot 共同分配給該節點);
  3. 執行完畢;

5.3.4.2 刪除節點

刪除節點實現 slot 重分配步驟如下:

  1. 用 ruby 腳本將待刪除節點的 slot 分配給其他 master 節點;
  2. 執行 ruby 腳本命令 redis-trib.rb del-node {待刪除節點 IP + 端口} {待刪除節點 ID}
  3. 執行完畢;

5.3.5 Redis 集羣注意事項

  1. 多件命令操作(如 MGET, MSET),如果每一個 Key 都位於同一個節點,則可以正常支持,否則會提示錯誤;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章