Redis系列(一):Redis架構演進

Redis的架構是逐步演進的,從最初的單實例,到目前集羣模式,我們可以看下整個演進過程,

主從複製

單個Redis實例的能力有限,在Redis的大多數使用場景下,都是讀請求多於寫請求,因此通過增加實例作爲只讀的從節點,不僅可以擴展Redis處理讀請求的能力,還能做到數據冗餘。
通過SLAVEOF,Redis可以指定一個實例爲slave,同步另一個實例(master)的數據。同步過程如下,

SYNC

SYNC的過程
SYNC的過程,

  1. 當slave初次複製或者斷線後重複製,向master發送SYNC命令
  2. master接到SYNC命令,執行BGSAVE,在後臺生成一個RDB文件,同時把這段時間的寫命令存儲在緩衝區中
  3. BGSAVE執行完成,master把生成的RDB文件發送給slave。slave接收到RDB文件後進行載入
  4. master把緩衝區中的寫命令發送給slave,salve執行寫命令確保數據與master保存一致

注:在進行主從複製的過程中,不會影響master繼續對外提供服務,因爲BGSAVE並不會阻塞實例(和SAVE不同),這裏可能會有疑問的是如果再生成RDB文件時,外部服務對master發送了寫命令,是否會影響RDB文件的生成。答案是不會,Redis採用了COW來進行寫時複製,感興趣的可以詳細瞭解下(有時間我也會單獨寫一篇文章介紹下COW)。

問題:

  • 每次複製都是全量複製,效率很低。主要是斷線重連,slave可能只是確保一小部分數據,不得不全量複製。

PSYNC

爲了解決SYNC的效率問題,Redis 2.8開始提供了PSYNC。

PSYNC1

PSYNC,從字面上也可以看出,支持部分複製(partial resynchronization)。它的實現思路通過offset和緩存一部分log來實現部分複製。

  • replication offset。master和slave分別會維護一個複製偏移量,如果master和slave的offset相等,意味着master與slave處於一致狀態
  • replication backlog。master會維護一個固定長度、FIFO的複製積壓緩衝區,用於保存寫命令
  • run id。用於標識不同的redis實例
    採用PSYNC後主從複製的流程如下,
    PSYNC流程
  • 在slave第一次同步master、run id不同(master已經換了)或者落後master太多時,採用全量同步,和SYNC流程相同
  • slave發送的offset的數據仍然在master的複製緩衝區中,採用部分重同步,把偏移量後的所有數據同步給slave。

問題:

  • 更換master後,run id 不同,所有的slave都會執行全量同步

PSYNC2

Redis 4.0優化了PSYNC,優化了PSYNC1中的問題, 採用 Replication ID 和offset來實現部分同步。
master和slave都會維護一個複製緩存區,master和它所有的slave保持同一個Replication ID

高可用

主從複製解決了數據冗餘的問題,但是在master掛掉後,切換master需要人工介入。爲此,Redis 2.8推出了Sentinel,提供高可用的解決方案。
Sentinel可以監視多個master,在master進入下線狀態時,自動把一個slave升級爲master來繼續對外提供服務。爲了避免Sentinel的單點問題,Sentinel一般是集羣部署。
每個Sentinel要監視哪些master實例初始是由Sentinel的配置文件決定的,

# sentinel monitor <master-name> <ip> <redis-port> <quorum>
# sentinel auth-pass <master-name> <password>
# sentinel down-after-milliseconds <master-name> <milliseconds>
# sentinel parallel-syncs <master-name> <numreplicas>

Sentinel在啓動的時候,會根據配置文件來初始化要監視的master列表。每當Sentinel 接收到一個新的配置, 或者當Leader Sentinel 爲主服務器創建一個新的配置時, 這個配置會與配置紀元一起被保存到磁盤裏面。
Redis2.8.4開始提供增加、刪除master的API。

# 添加要監控的master
SENTINEL MONITOR <name> <ip> <port> <quorum>
# 刪除正在監控的master
SENTINEL REMOVE <name>

Sentinel與Redis實例之間的關係
Sentinel會保存它監視的所有master實例的信息,Sentinel與master實例會建立一個命令連接和一個訂閱連接,用過命令連接,Sentinel定時向master發送INFO命令,來獲取master的信息(包括master有哪些slave),然後通過訂閱通道廣播給其他的Sentinel實例。最終所有的Sentinel最終都可以互相知道哪些Sentinel監視哪些master。

服務監測

每個Sentinel默認會每秒向它連接的實例(包括master、slave、其他的Sentinel)發送PING命令,根據實例是否正常回復來判斷實例是否在線。

# sentinel down-after-milliseconds <master-name> <milliseconds>
#
# Number of milliseconds the master (or any attached replica or sentinel
) should
# be unreachable (as in, not acceptable reply to PING, continuously, for
 the
# specified period) in order to consider it in S_DOWN state (Subjectivel
y
# Down).
#
# Default is 30 seconds.
sentinel down-after-milliseconds mymaster 30000

down-after-milliseconds 用來判斷實例進入主觀下線(S_DOWN)狀態的時長。
當Sentinel認爲master1處於主觀下線狀態,就會詢問其他Sentinel,是不是也認爲master1也處於主觀下線狀態。當超過一定數量的Sentinel也認爲master1處於主觀下線,那麼master1就會被判定爲客觀下線(O_DOWN),然後開始執行故障轉移。

故障轉移

故障轉移前,Sentinel會先選出一個leader來執行操作。
哨兵選舉流程
參與選舉的是所有監視master1的Sentinel實例,每次進行選舉,不論是否成功,選舉輪次(epoch)都會加一。在一次選舉過程中,每個Sentinel都只會投給一個Sentinel,不會更改。一次選舉的流程如下,

  • 所有的Sentinel都向其他Sentinel發送命令,希望對方投票給自己
  • Sentinel確定自己的選票是先到先得,先收到誰的請求,就把票投給誰
  • Sentinel在收到回覆後,統計選票,如果某個Sentinel獲得了半數以上Sentinel的投票,那麼這個Sentinel就成爲了leader。

切換Master

Leader Sentinel從被下線的master的所有slave實例中挑選一個,將其轉爲master,其餘的slave改Follow新的master。如果後續舊master上線,Sentinel會把它轉爲新master的slave。
從候選的slave中挑選master,首先slave必須是仍然在線的、與Sentinel保持連接(最近5s正確回覆Sentinel的INFO命令)、與master斷開連接沒有很久,然後把符合條件中的slave按照優先級(配置文件中的replica-priority)排序 -> 複製偏移量最大 -> run id最小。
在這裏插入圖片描述

RedisCluster

Sentinel只是高可用的解決方案,並不能提供擴展能力(寫能力、存儲能力)。Redis在3.0後開始提供對集羣的支持。
// todo

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章