Redis 主從複製與哨兵

Redis 可以使用從屬服務器來實現讀寫分離提高吞吐量或在主服務器故障時接替主服務器以提高可用性。

每個 Redis 服務器實例都可以配置多個 slave 節點,slave 服務器也可以擁有次級 slave 節點, 可以組織成複雜的樹狀結構(雖說生產環境下極少有人這麼做)。

配置主從複製

爲了嘗試配置主從複製,我們至少需要兩個 redis 服務器實例。最簡單的方法是在 redis 官網下載 redis-server 二進制可執行文件,分別放在 master 和 slave 目錄中。

在每個目錄中分別創建 redis.conf 配置文件。master 實例的配置文件採用默認即可, 在 slave 實例中進行主從複製配置:

# 和主服務器 6379 區分
port 6380

# 主服務器 ip 端口
slaveof 127.0.0.1 6379

# 如果主服務器配置了密碼請寫在這個配置項中
# masterauth <master-password>

##
## 接下來的選項保留默認配置即可,這裏僅做介紹
##

# 當與 master 斷開連接或正在進行同步時
# yes: 仍然正常響應客戶端請求,但可能返回過時數據
# no: 除 INFO 和 SLAVEOF 命令正常外,其它命令均返回 SYNC with master in progress 錯誤
slave-serve-stale-data yes

# 從服務器只讀
slave-read-only yes

使用redis-server redis.conf 命令分別啓動 redis-server 實例。 使用redis-cli -p 6380命令連接從服務器:

127.0.0.1:6380> info Replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:16
master_sync_in_progress:0
slave_repl_offset:3640
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:0b4e100aa9e9fda54aeba2bc110316d811ac2ff6
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:3640
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:3640
127.0.0.1:6380> get a
1
127.0.0.1:6380> set a 2
(error) READONLY You can't write against a read only slave.

SLAVEOF host port 可以動態改變從服務器所屬的 master 節點。SLAVEOF NO ONE 關閉複製功能,並從 slave 服務器轉變回 master 服務器,原來同步所得的數據集不會被丟棄。在當主服務器故障時,可以使用SLAVEOF NO ONE命令將 slave 服務器提升爲 master。

主從複製原理

SYNC

在 Redis 2.8 之前的版本里,Redis 僅支持全量複製不支持增量複製,這極大的影響了主從同步的性能。

Redis 2.8 之前的版本主從複製流程如下:

  1. slave 發送 SYNC 命令給 master
  2. master 執行 bgsave 命令生成 rdb 文件。於此同時,所有新的寫命令都將被寫入複製緩衝區內
  3. master 將 rdb 文件發送給 slave
  4. master 將緩衝區中的命令同步給 slave, 完成一次主從同步

PSYNC

Redis 2.8 開始使用 PSYNC 命令代替 SYNC 命令, PSYNC 具有全量複製和增量複製功能。

master 和 slave 節點均擁有一個 runid 作爲自己的唯一標識。

master 和 slave 會各自維護一個複製偏移量,在增量複製時標識同步進度。

master 會維護一個 FIFO 的複製緩衝區(replication backlog),默認大小 1mb。

# 複製緩衝區大小
repl-backlog-size 1mb

# 當 master 不再與任何 slave 保持連接時,複製緩衝區可能被清空
# repl-backlog-ttl 用於配置從斷開連接到清空緩衝區間隔的秒數
# 0 表示永不清除緩衝區
repl-backlog-ttl 3600

接下來我們可以開始說明 PSYNC 命令執行的流程:

  1. slave 向 master 請求同步
    1. 若 slave 未與任何 master 同步過或執行了 SLAVEOF NO ONE 命令,則向 master 發送 PSYNC ? -1命令要求進行全量同步。
    2. 否則,則向 master 發送 psync <runid> <offset>命令要求增量同步,其中 runid 是上次同步的主服務器的ID,offset 是同步偏移量
  2. master 響應同步請求
    1. 若 slave 請求增量同步且滿足:1. runid 與自身相同;2. 同步偏移量處於自身複製緩衝區內,則響應+continue將複製緩衝區內的數據同步到 slave
    2. 若 slave 請求增量同步但不同時滿足上述兩個條件或 slave 請求全量同步, 則響應+fullresync <runid> <offset> 執行全量同步,其中 runid 是自身ID, offset 是自身同步偏移量。
  3. 若自身版本過低不支持PSYNC命令則響應 error, slave 會嘗試使用 SYNC 命令進行同步。

哨兵

簡單的主從複製架構在 master 故障後會不可用,Redis 官方提供了哨兵(sentinel)機制自動實現主備切換保證高可用。

哨兵機制通過一組哨兵節點監控主從節點的運行狀態,並在主節點故障後選舉新的主節點。

哨兵節點定時執行3個任務:

  • 哨兵節點每隔10s向主從節點發送INFO命令以更新拓撲圖,自動感知新的 slave 節點。

  • 哨兵節點每隔1s向主從節點發送PING命令進行心跳檢測。

  • 哨兵節點每隔2s向__sentinel__:hello頻道發送自身哨兵節點信息和自身瞭解的 master 信息。所有哨兵節點均會訂閱該頻道,並以此更新哨兵集羣信息。

若哨兵節點發現 master 節點心跳響應超時,則認爲 master 主觀下線。此時,master 可能真的已經崩潰也可能僅僅是此哨兵節點與 master 之間出現網絡故障。

認爲 master 主觀下線的哨兵會向其它哨兵發送sentinel is-master-down-by addr詢問 master 是否下線。若半數以上的哨兵認爲 master 已經下線則認爲 master 客觀下線。

哨兵節點會選舉自己第一個收到的 is-master-down-by 命令的發送者爲哨兵領導者。若某一個節點得到過半投票則會成爲哨兵領導者,若沒有節點得到半數以上票則會進入下一輪投票。此選舉流程與 Paxos 算法類似。

哨兵領導者負責選擇一個slave節點提升爲新 master 節點, 選擇邏輯爲:

  1. 過濾掉不健康的 slave 節點
  2. 選擇 slave-priority 配置值最小的從節點。若有多個從節點 slave-priority 最小且相同則進入下一步
  3. 選擇複製偏移量最大的從節點,這意味着這個從節點上面的數據最完整。若仍有多個 slave 節點偏移量相同則進入下一步
  4. 選擇 runid 最小的從節點

新的 master 節點選出後會執行提升流程:

  1. 向新選出的 master 節點發出 SLAVEOF NO ONE 命令,提升爲新的 master 節點
  2. 向其它 slave 節點發出 SLAVEOF 命令跟隨新的 master 節點
  3. 在哨兵集羣中將下線的 master 節點更新爲下線的 slave 節點,在其回覆後命令其跟隨新的 master
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章