Redis 主從復制

概述

主從復制,是指將一臺Redis服務(wù)器的數(shù)據(jù),復制到其他的Redis服務(wù)器。前者稱為主節(jié)點(master),后者稱為從節(jié)點(slave);數(shù)據(jù)的復制是單向的,只能由主節(jié)點到從節(jié)點。默認情況下,每臺Redis服務(wù)器都是主節(jié)點;且一個主節(jié)點可以有多個從節(jié)點(或沒有從節(jié)點),但一個從節(jié)點只能有一個主節(jié)點。

主從復制的作用主要包括:

  • 數(shù)據(jù)冗余
    主從復制實現(xiàn)了數(shù)據(jù)的熱備份,是持久化之外的一種數(shù)據(jù)冗余方式。

  • 故障恢復
    當主節(jié)點出現(xiàn)問題時,可以由從節(jié)點提供服務(wù),實現(xiàn)快速的故障恢復;實際上是一種服務(wù)的冗余。

  • 負載均衡:在主從復制的基礎(chǔ)上,配合讀寫分離,可以由主節(jié)點提供寫服務(wù),由從節(jié)點提供讀服務(wù)(即寫Redis數(shù)據(jù)時應(yīng)用連接主節(jié)點,讀Redis數(shù)據(jù)時應(yīng)用連接從節(jié)點),分擔服務(wù)器負載;尤其是在寫少讀多的場景下,通過多個從節(jié)點分擔讀負載,可以大大提高Redis服務(wù)器的并發(fā)量。

  • 高可用基石:除了上述作用以外,主從復制還是哨兵和集群能夠?qū)嵤┑幕A(chǔ),因此說主從復制是Redis高可用的基礎(chǔ)。

主從復制的流程

建立連接階段

image.png

數(shù)據(jù)同步階段

主從節(jié)點之間的連接建立以后,便可以開始進行數(shù)據(jù)同步,該階段可以理解為從節(jié)點數(shù)據(jù)的初始化。具體執(zhí)行的方式是:從節(jié)點向主節(jié)點發(fā)送psync命令(Redis2.8以前是sync命令),開始同步。

數(shù)據(jù)同步階段是主從復制最核心的階段,根據(jù)主從節(jié)點當前狀態(tài)的不同,可以分為全量復制部分復制。

  • 全量復制:用于初次復制或其他無法進行部分復制的情況,將主節(jié)點中的所有數(shù)據(jù)都發(fā)送給從節(jié)點,是一個非常重型的操作。
  • 部分復制:用于網(wǎng)絡(luò)中斷等情況后的復制,只將中斷期間主節(jié)點執(zhí)行的寫命令發(fā)送給從節(jié)點,與全量復制相比更加高效。需要注意的是,如果網(wǎng)絡(luò)中斷時間過長,導致主節(jié)點沒有能夠完整地保存中斷期間執(zhí)行的寫命令,則無法進行部分復制,仍使用全量復制。

需要注意的是,在數(shù)據(jù)同步階段之前,從節(jié)點是主節(jié)點的客戶端,主節(jié)點不是從節(jié)點的客戶端;而到了這一階段及以后,主從節(jié)點互為客戶端。原因在于:在此之前,主節(jié)點只需要響應(yīng)從節(jié)點的請求即可,不需要主動發(fā)請求,而在數(shù)據(jù)同步階段和后面的命令傳播階段,主節(jié)點需要主動向從節(jié)點發(fā)送請求(如推送緩沖區(qū)中的寫命令),才能完成復制。

全量 or 部分

由于全量復制在主節(jié)點數(shù)據(jù)量較大時效率太低,因此Redis2.8開始提供部分復制,用于處理網(wǎng)絡(luò)中斷時的數(shù)據(jù)同步。部分復制的實現(xiàn),依賴于三個重要的概念:

  • 復制偏移量
    主節(jié)點和從節(jié)點分別維護一個復制偏移量(offset),代表的是主節(jié)點向從節(jié)點傳遞的字節(jié)數(shù);主節(jié)點每次向從節(jié)點傳播N個字節(jié)數(shù)據(jù)時,主節(jié)點的offset增加N;從節(jié)點每次收到主節(jié)點傳來的N個字節(jié)數(shù)據(jù)時,從節(jié)點的offset增加N。

  • 復制積壓緩沖區(qū)
    復制積壓緩沖區(qū)是由主節(jié)點維護的、固定長度的、先進先出(FIFO)隊列,默認大小1MB;當主節(jié)點開始有從節(jié)點時創(chuàng)建,其作用是備份主節(jié)點最近發(fā)送給從節(jié)點的數(shù)據(jù)。注意,無論主節(jié)點有一個還是多個從節(jié)點,都只需要一個復制積壓緩沖區(qū)。

  • 服務(wù)器運行id
    每個Redis節(jié)點(無論主從),在啟動時都會自動生成一個隨機ID(每次啟動都不一樣),由40個隨機的十六進制字符組成;runid用來唯一識別一個Redis節(jié)點。

判斷流程

image.jpeg

全量復制
image.png

1、主節(jié)點接收到全量同步的請求時,fork一個子進程進行bgsave,同時將接下來的寫操作保存至復制緩沖區(qū);
2、RDB保存完畢后,向從服務(wù)器發(fā)送;
3、從服務(wù)器清除當前的內(nèi)存數(shù)據(jù)
4、阻塞客戶端請求,拒絕服務(wù)
5、從RDB加載數(shù)據(jù),執(zhí)行這些寫命令,將數(shù)據(jù)庫狀態(tài)更新至主節(jié)點的最新狀態(tài)
6、若開啟了AOF,則會觸發(fā)bgrewriteaof的執(zhí)行,從而保證AOF文件更新至主節(jié)點的最新狀態(tài)

部分復制

在部分復制階段,從服務(wù)器只要拉取并執(zhí)行部分主服務(wù)的寫命令即可。

命令傳播階段

當從服務(wù)器完成了對主服務(wù)器的同步操作,就進入了命令傳播階段。在這個階段,主服務(wù)器會將自己的寫命令同步給從服務(wù)器,從而保持數(shù)據(jù)一致性

除了發(fā)送寫命令,主從節(jié)點還維持著心跳機制:PING和REPLCONF ACK。心跳機制對于主從復制的超時判斷、數(shù)據(jù)安全等有作用。

主 -> 從:PING

每隔指定的時間,主節(jié)點會向從節(jié)點發(fā)送PING命令,這個PING命令的作用,主要是為了讓從節(jié)點進行超時判斷。

PING發(fā)送的頻率由repl-ping-slave-period參數(shù)控制,單位是秒,默認值是10s。

從 -> 主:REPLCONF ACK

在命令傳播階段,從節(jié)點會向主節(jié)點發(fā)送REPLCONF ACK命令,頻率是每秒1次。

命令格式為:REPLCONF ACK {offset},其中offset指從節(jié)點保存的復制偏移量。

REPLCONF ACK命令的作用包括:

  • 實時監(jiān)測主從節(jié)點網(wǎng)絡(luò)狀態(tài)
    該命令會被主節(jié)點用于復制超時的判斷。此外,在主節(jié)點中使用info Replication,可以看到其從節(jié)點的狀態(tài)中的lag值,代表的是主節(jié)點上次收到該REPLCONF ACK命令的時間間隔,在正常情況下,該值應(yīng)該是0或1。
  • 檢測命令丟失
    從節(jié)點發(fā)送了自身的offset,主節(jié)點會與自己的offset對比,如果從節(jié)點數(shù)據(jù)缺失(如網(wǎng)絡(luò)丟包),主節(jié)點會推送缺失的數(shù)據(jù)(這里也會利用復制積壓緩沖區(qū))。注意,offset和復制積壓緩沖區(qū),不僅可以用于部分復制,也可以用于處理命令丟失等情形;區(qū)別在于前者是在斷線重連后進行的,而后者是在主從節(jié)點沒有斷線的情況下進行的。
  • 輔助保證從節(jié)點的數(shù)量和延遲
    Redis主節(jié)點中使用min-slaves-to-write和min-slaves-max-lag參數(shù),來保證主節(jié)點在不安全的情況下不會執(zhí)行寫命令;所謂不安全,是指從節(jié)點數(shù)量太少,或延遲過高。例如min-slaves-to-write和min-slaves-max-lag分別是3和10,含義是如果從節(jié)點數(shù)量小于3個,或所有從節(jié)點的延遲值都大于10s,則主節(jié)點拒絕執(zhí)行寫命令。而這里從節(jié)點延遲值的獲取,就是通過主節(jié)點接收到REPLCONF ACK命令的時間來判斷的。

問題

數(shù)據(jù)一致性問題
  • 數(shù)據(jù)延遲
    由于主從復制的命令傳播是異步的,延遲與數(shù)據(jù)的不一致不可避免。如果應(yīng)用對數(shù)據(jù)不一致的接受程度程度較低,可能的優(yōu)化措施包括:(1) 優(yōu)化主從節(jié)點之間的網(wǎng)絡(luò)環(huán)境(如在同機房部署);(2) 監(jiān)控主從節(jié)點延遲(通過offset)判斷,如果從節(jié)點延遲過大,通知應(yīng)用不再通過該從節(jié)點讀取數(shù)據(jù);(3) 使用集群同時擴展寫負載和讀負載等。
    在命令傳播階段以外的其他情況下,從節(jié)點的數(shù)據(jù)不一致可能更加嚴重,例如連接在數(shù)據(jù)同步階段,或從節(jié)點失去與主節(jié)點的連接時等。從節(jié)點的slave-serve-stale-data參數(shù)便與此有關(guān):它控制這種情況下從節(jié)點的表現(xiàn);如果為yes(默認值),則從節(jié)點仍能夠響應(yīng)客戶端的命令,如果為no,則從節(jié)點只能響應(yīng)info、slaveof等少數(shù)命令。該參數(shù)的設(shè)置與應(yīng)用對數(shù)據(jù)一致性的要求有關(guān);如果對數(shù)據(jù)一致性要求很高,則應(yīng)設(shè)置為no。

  • 數(shù)據(jù)過期
    在單機版Redis中,存在兩種刪除策略。
    惰性刪除:服務(wù)器不會主動刪除數(shù)據(jù),只有當客戶端查詢某個數(shù)據(jù)時,服務(wù)器判斷該數(shù)據(jù)是否過期,如果過期則刪除。
    定期刪除:服務(wù)器執(zhí)行定時任務(wù)刪除過期數(shù)據(jù),但是考慮到內(nèi)存和CPU的折中(刪除會釋放內(nèi)存,但是頻繁的刪除操作對CPU不友好),該刪除的頻率和執(zhí)行時間都受到了限制。
    在主從復制場景下,為了主從節(jié)點的數(shù)據(jù)一致性,從節(jié)點不會主動刪除數(shù)據(jù),而是由主節(jié)點控制從節(jié)點中過期數(shù)據(jù)的刪除。由于主節(jié)點的惰性刪除和定期刪除策略,都不能保證主節(jié)點及時對過期數(shù)據(jù)執(zhí)行刪除操作,因此,當客戶端通過Redis從節(jié)點讀取數(shù)據(jù)時,很容易讀取到已經(jīng)過期的數(shù)據(jù)。
    Redis 3.2中,從節(jié)點在讀取數(shù)據(jù)時,增加了對數(shù)據(jù)是否過期的判斷:如果該數(shù)據(jù)已過期,則不返回給客戶端;將Redis升級到3.2可以解決數(shù)據(jù)過期問題。

  • 故障切換
    在沒有使用哨兵的讀寫分離場景下,應(yīng)用針對讀和寫分別連接不同的Redis節(jié)點;當主節(jié)點或從節(jié)點出現(xiàn)問題而發(fā)生更改時,需要及時修改應(yīng)用程序讀寫Redis數(shù)據(jù)的連接;連接的切換可以手動進行,或者自己寫監(jiān)控程序進行切換,但前者響應(yīng)慢、容易出錯,后者實現(xiàn)復雜,成本都不算低。

連接超時

意義

  • 如果主節(jié)點判斷連接超時,其會釋放相應(yīng)從節(jié)點的連接,從而釋放各種資源,否則無效的從節(jié)點仍會占用主節(jié)點的各種資源(輸出緩沖區(qū)、帶寬、連接等);此外連接超時的判斷可以讓主節(jié)點更準確的知道當前有效從節(jié)點的個數(shù),有助于保證數(shù)據(jù)安全(配合前面講到的min-slaves-to-write等參數(shù))。
  • 如果從節(jié)點判斷連接超時,則可以及時重新建立連接,避免與主節(jié)點數(shù)據(jù)長期的不一致。

判斷機制
主從復制超時判斷的核心,在于repl-timeout參數(shù),該參數(shù)規(guī)定了超時時間的閾值(默認60s),對于主節(jié)點和從節(jié)點同時有效;主從節(jié)點觸發(fā)超時的條件分別如下:

  • 主節(jié)點:每秒1次調(diào)用復制定時函數(shù)replicationCron(),在其中判斷當前時間距離上次收到各個從節(jié)點REPLCONF ACK的時間,是否超過了repl-timeout值,如果超過了則釋放相應(yīng)從節(jié)點的連接。
  • 從節(jié)點:從節(jié)點對超時的判斷同樣是在復制定時函數(shù)中判斷,基本邏輯是:
    (1) 如果當前處于連接建立階段,且距離上次收到主節(jié)點的信息的時間已超過repl-timeout,則釋放與主節(jié)點的連接;
    (2) 如果當前處于數(shù)據(jù)同步階段,且收到主節(jié)點的RDB文件的時間超時,則停止數(shù)據(jù)同步,釋放連接;
    (3) 如果當前處于命令傳播階段,且距離上次收到主節(jié)點的PING命令或數(shù)據(jù)的時間已超過repl-timeout值,則釋放與主節(jié)點的連接。

問題
連接超時會使主從進入重連階段,若超時時間較短,而進入部分同步階段,此時從服務(wù)器阻塞;若超時時間較長,則進入全量同步階段,主服務(wù)器需要消耗大量的內(nèi)存和cpu時間用于bgsave,同時rdb的傳輸會占據(jù)主服務(wù)器的大部分帶寬,直接影響了主服務(wù)器的吞吐量。在加載RDB階段,從服務(wù)器會阻塞客戶端請求,拒絕服務(wù)。所以我們應(yīng)該盡量避免超時問題。

實際問題:

  • 數(shù)據(jù)同步階段
    在主從節(jié)點進行全量復制bgsave時,主節(jié)點需要首先fork子進程將當前數(shù)據(jù)保存到RDB文件中,然后再將RDB文件通過網(wǎng)絡(luò)傳輸?shù)綇墓?jié)點。如果RDB文件過大,主節(jié)點在fork子進程+保存RDB文件時耗時過多,可能會導致從節(jié)點長時間收不到數(shù)據(jù)而觸發(fā)超時;此時從節(jié)點會重連主節(jié)點,然后再次全量復制,再次超時,再次重連……這是個悲傷的循環(huán)。為了避免這種情況的發(fā)生,除了注意Redis單機數(shù)據(jù)量不要過大,另一方面就是適當增大repl-timeout值,具體的大小可以根據(jù)bgsave耗時來調(diào)整。
  • 命令傳播階段:在該階段主節(jié)點會向從節(jié)點發(fā)送PING命令,頻率由repl-ping-slave-period控制;該參數(shù)應(yīng)明顯小于repl-timeout值(后者至少是前者的幾倍)。否則,如果兩個參數(shù)相等或接近,網(wǎng)絡(luò)抖動導致個別PING命令丟失,此時恰巧主節(jié)點也沒有向從節(jié)點發(fā)送數(shù)據(jù),則從節(jié)點很容易判斷超時。
  • 慢查詢導致的阻塞:如果主節(jié)點或從節(jié)點執(zhí)行了一些慢查詢(如keys *或者對大數(shù)據(jù)的hgetall等),導致服務(wù)器阻塞;阻塞期間無法響應(yīng)復制連接中對方節(jié)點的請求,可能導致復制超時。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本篇就一下方面展開分析 如何使用主從復制? 主從復制的原理(重點是全量復制和部分復制、以及心跳機制) 實際應(yīng)用中需...
    lucode閱讀 1,059評論 0 5
  • 前言 redis的高可用涉及到持久化、主從復制(讀寫分離)、哨兵和集群。持久化主要是內(nèi)存數(shù)據(jù)到磁盤,是一個單機備份...
    熱血趁年華閱讀 302評論 0 0
  • 1. 拓撲結(jié)構(gòu) 本文搭建如下圖所示的redis拓撲結(jié)構(gòu),拓撲中共有3個哨兵,1和mater結(jié)點和2個slave結(jié)點...
    kylinxiang閱讀 5,479評論 1 7
  • 沒事的時候看到喜歡的都會照著畫一下,這張是穿山甲
    閑人J閱讀 209評論 0 3
  • 今天晚上在深圳下梅林山風書畫茶藝苑黃山廳,慶賀中國攝影教父級人物之一李泛老師開印攝影大作新著聚會。大家一起喝茶聊攝...
    增祥影媒閱讀 233評論 0 0

友情鏈接更多精彩內(nèi)容