Redis系列(四):天天用着Redis集羣,主從同步該知道吧?集羣工作原理是否需要了解下?...

  

作者:z小趙

★ 

一枚用心堅持寫原創的“無趣”程序猿,在自身受益的同時也讓朋友們在技術上有所提升。

前言

插播一個小插曲,本來文章已經寫好準備發佈了,手賤清理了緩存導致文本內容全部丟失,以至於重新寫稿。藉此提醒廣大粉絲朋友,平時一定要養成備份的好習慣,謹防出現博主這種愚蠢的行爲。

上篇文章講解了緩存剔除的流程,以及 RDB 文件和 AOF 文件的原理介紹,本文我們來講講數據複製和集羣工作的原理。

目錄

  • 主從數據同步原理分析。

  • Redis 集羣工作原理剖析。

  • 集羣槽指派機制。

  • 集羣服務自動檢測 & 故障轉移恢復操作。

主從數據同步原理分析

主從數據同步分爲兩種同步情況,分爲完整重同步部分重同步兩種。

完整重同步流程

完整重同步是指:在從服務器第一次啓動時,其內部沒有任何數據的時候,通過向從服務器發送 slaveof master_ip port 命令,通知從服務器向指定的主服務器發起完整的數據備份請求。具體流程如下:

  1. 客戶端向從服務器發送數據同步請求,從服務器接收到命令後,便通過指定的主服務器 ip 和 port 向主服務器發送 PSYNC 請求數據同步。

  2. 主服務器接收到 PSYNC 後,判斷是要求進行全量數據同步,此時主服務器生成當前服務器對應的 RDB 文件,然後將其返回給從服務器。

  3. 在從服務器進行數據完整重同步的過程中,主服務器接收到的寫請求在自己的服務器中完成命令操作之後,同時將寫命令也發送到從服務器中。

  4. 從服務器接收到 RDB 文件後,開始解析 RDB 文件,對 RDB 文件解析完成和主服務器寫命令的操作之後,也就意味着數據完成完整重同步流程。

以上整個流程便是數據完整重同步的具體執行流程,額外需要注意的一點是,完整重同步其實就是將主服務器的整個完整數據進行一次完整的備份。

部分重同步

部分重同步是指:從服務器在複製了一部分數據後發生了斷線重連後繼續複製的情形。在從服務器由於網絡等原因導致數據同步終止,當網絡恢復後,從服務器繼續向主服務器進行數據同步操作。Redis 通過偏移量的機制來實現數據部分重同步操作,即主服務器和從服務器都維護着一個執行命令的偏移量,同時在主服務器內部維護着一個複製積壓緩衝區(複製積壓緩衝區是可以調節大小的,默認大小 1M,通過修改 repl-backlog-size 配置進行修改),該緩衝區中緩存着部分寫命令和寫命令對應的偏移量。當從服務器斷線重連後,從服務器在發送數據同步請求的時候會帶着從服務器當前同步的偏移量,如果從服務器發送的偏移量在複製積壓緩衝區中存在,則從複製積壓緩衝區中對應的偏移量位置繼續複製往後位置的命令,如果從服務器發送的偏移量和主服務器維護的偏移量相等,則表示主從數據是一致的。部分重同步流程如下圖所示:

部分重同步機制的優勢:

  1. 相比於全量重同步,減少了數據同步量

  2. 由於部分重同步數據量小,可以更快速的達到主從數據一致的目的

  3. 由於數據同步量少,從而節省了帶寬資源,同時也節省了主服務器生成 RDB 文件而產生的 CPU 浪費情況

Redis 集羣工作原理剖析

Redis 集羣在生產環境中通常是由多個節點服務器所組成,那麼多個節點是如何建立起連接的呢?起初 Redis 集羣是由各個節點各自爲一個集羣的,通過執行 CLUSTER MEET 目標機IP 目標機端口 命令,使得兩臺機器建立連接,從而構成集羣。舉個例子,假設現在有 3 個節點要組成一個 Redis 集羣。

  1. 起初,Redis 有 3 個節點且各自爲一個僞集羣,其如下圖:

  1. 通過客戶端向節點 2 發送 CLUSTER MEET 節點1IP 節點1端口 命令,此時節點 2 加入了節點 1 所在的集羣,其如下圖:

  1. 同理,通過客戶端向節點 3 發送 CLUSTER MEET 節點1IP 節點1端口 命令,此時節點 3 加入了節點 1 所在的集羣,在節點 1 和節點 3 建連完成後,節點 2 也會和節點 3 完成相同的操作,最終形成了 3 個節點互聯的集羣,其如下圖所示:

上述流程展示了一個集羣建連的過程,那麼兩個節點在建連的時候到底是怎麼實現的呢?舉個例子,以節點 1 和節點 2 建連爲例:

  1. 首先節點 1 會創建一個 Node 結構體,用於存儲節點 2 的信息,比如節點 2 的名字、IP、Port 等等信息。

  2. 然後節點 1 發送 CLUSTER MEET IP PORT 命令到節點 2。

  3. 節點 2 接收到節點 1 的命令後,在其節點上創建一個 Node 用於存儲節點 1 的信息。

  4. 節點 2 存儲完成節點 1 的信息後,向節點 1 發送 PONG 命令,表示自己已經成功接收到了節點 1 的信息。

  5. 節點 1 收到節點 2 返回的 PONG 命令後,然後節點 1 再向節點 2 發送 PING 命令,表示節點 1 知道節點 2 成功接收到節點 1 發送的消息了,至此兩個節點完成建連。

Redis 集羣槽指派流程

通過上面的流程明白了 Redis 集羣是如何構建起來的,現在有個問題是假設有一條寫命令發送到集羣中,那麼最終應該由那個節點實際執行呢?舉個例子,集羣由三個主節點組成,執行 set key1 value1 命令。Redis 集羣通過槽指派機制來決定寫命令應該被分配到那個節點。整個集羣對應的槽是由 16384 大小的二進制數組組成,集羣中每個主節點分配一部分槽,每條寫命令落到二級制數組中的某個位置,該位置被分配給了那個節點則對應的命令就由該節點去執行。槽指派對應的二進制數組如下圖所示:

舉個例子:假設節點 1 執行 0 - 4999,節點 2 執行 5000 - 9999,節點 3 執行 10000 - 16383, set key1 value1 命令通過 CRC16(key1) & 16383 = 8876,即認爲該命令最後落到二級制數組的 8876 位置,則該命令最終由節點 2 執行。在比如在節點 2 執行一條命令時,假設通過 CRC 計算後得到的值爲 889,則其應該有節點 1 執行,此時命令會發生一個轉向操作,將要執行的命令轉向到節點 1 上去執行,其具體工作原理如下:

集羣服務自動檢測 & 故障轉移恢復操作

通過上述文章介紹,我們基本明白了 Redis 集羣的基本工作原理,現在我們來看看集羣節點自動檢測,以及當節點發生故障時該如何進行故障轉移恢復。假設現在集羣由如下圖所示,其總共由 3 個主節點和 6 個從節點構成。

集羣中每個主節點都會定時發送信息到其他主節點,如果其他主節點在規定時間內響應了發送消息的主節點,則發送消息的主節點認爲響應了消息的這些主節點在正常工作,反之則認爲響應消息的主節點疑似下線,則發送消息的主節點在其節點上將其標記疑似下線;當集羣中超過半數的節點認爲某個主節點被標記爲疑似下線,則其中某個主節點將疑似下線節點標記爲下線狀態,並向集羣廣播一條下線消息,當下線節點對應的從節點接收到該消息時,則從從節點中選舉出一個節點作爲主節點繼續對外提供服務。

舉個例子:如下圖所示,假設節點 1 發送消息給節點 2 節點 3,然後節點 2 在規定時間內響應了節點 1 的信息,而節點 3 沒有響應,此時節點 1 將節點 3 標記爲疑似下線,然後節點 2 給節點 1 和節點 3 發送消息,節點 1 在規定時間內響應了節點 2,但是節點 3 沒有響應節點 3,此時節點 2 先將其標記沒疑似下線,同時發現節點 3 被標記的疑似下線個數超過集羣總數的一半,所以節點 2 便將節點 3 標記爲已下線狀態,並將該消息廣播給集羣中所有的節點,節點 3 對應的從節點 5 和從節點 6 接收到該消息後,停止從節點 3 複製數據且節點 5 被選舉爲新的主節點,從節點 6 轉而複製節點 5 的數據。

故障轉移圖

總結

本文首先講解了 Redis 主從複製的相關細節實現,然後接着講解了 Redis 集羣組成及相應的工作原理,最後講解了集羣自動檢查及故障原理的實現。

本來準備接着來講講集羣的搭建,礙於文章篇幅,準備在下篇文章來專門講述,本文乾貨滿滿,不懂的地方歡迎隨時交流溝通。下篇文章再見,拜拜。

系統研發工程師、z小趙
高併發設計 | 大數據 | 架構設計

往期推薦

Redis系列(三):緩存過期該如何剔除?RDB和AOF又是什麼?

Redis系列(二): 連集合底層實現原理都不知道,你敢說Redis用的很溜? 

Kafka:你必須要知道集羣內部工作原理的一些事!

消息是如何在服務端存儲與讀取的,你真的知道嗎? 

一文讀懂消費者背後的那點"貓膩"

感謝您的【在看】【轉發】支持

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