面試官:熟悉Redis,那聊聊Redis主從複製?我畫了13張圖講明白了 怎麼做備份 定義 全量同步 增量複製 總結

怎麼實現高可用呢? 最重要的一點就是冗餘數據啊,redis 是通過主從複製來實現數據的冗餘存儲,這樣在主redis down調用之後,切換到從就可以了,這樣就實現了故障轉移,保證了高可用了,今天我們主要來講主從複製,至於主down掉之後,怎麼切換到從,我們會在下篇再聊。

怎麼做備份

我想在再看redis 主從複製之前,有必要看下下面這三個基礎概念。

備份分爲冷備熱備,如果再深入一些還有多活

  • 熱備:由主庫或者說是主數據中心承擔業務流量,同時會實時的備份數據到從庫或者從的數據中心。如下圖。
  • 冷備:由主庫或者主數據中心承擔業務流量,備份數據會定時或者離線手動的執行腳本同步數據到一個從庫或者從數據中心,如下圖。
  • 雙活:由兩個數據中心承擔業務流量,數據中心互爲主備,一般主數據中心會承擔大部分流量,另一數據中心會承擔小部分流量,如下圖。

注意:這裏直接說明了定義,至於出現故障後,怎麼做手動或者自動的故障轉移,本篇這不講解,後面講redis 哨兵的時候,會細講。上面的圖只是能讓我們加深對備份概念的理解。

那麼redis屬於哪種備份呢? 相信你讀完肯定就會明白了。

定義

主從複製,是指將一臺Redis服務器的數據,複製到其他的Redis服務器。前者稱爲主節點(master),後者稱爲從節點(slave),數據的複製是單向的,只能由主節點到從節點。一個主節點可以有多個從節點,但一個從節點只能有一個主節點。

看圖:

這裏我們不會講或者講解redis 主從的安裝步驟,這個網上的博文和官網都會有,相信大家都會一步步地配置成功。

我們主要會講解:

  • 主從複製從開始到現在都經歷了什麼,同步的是什麼,數據還是文件?
  • 在主從過程中,如果網絡中斷了,怎麼辦?
  • 同步的過程中,哪些因素會增加主庫的壓力?

全量同步

當我們配置好主從同步的時候,由於之前沒有進行過任何同步,所以首先會進行一次全量數據同步到從庫。

主從建立連接

當設置完主從同步配置後,第一步就是主從之間要建立連接,主要之間要相互認識一下,建立信任,才能開始進行同步。

執行slaveof 後,發生了什麼,看圖說話:

此時Slave從庫會主動和Master主庫進行通信,發送psync 命令,該命令會捎帶兩個參數過去給Master,第一個參數是主庫ID(runID),redis 在啓動的時候,都會爲自己生成一個ID,第二個是Slave 需要從Master哪裏開始複製數據,也就是Slave複製Maser數據的偏移量offset。

Slave第一次和Master進行通信,由於一開始不知道Master的ID,所以傳遞了?
由於是第一次複製,傳遞-1 表示第一次要進行全量複製。

接着Master接收到了Slave傳遞過來的命令以及相應的參數,一看是? 和 -1 ,那麼就知道這個Slave要進行全量的複製,Master會給Slave 發送一個fullresync 命令,告訴Slave接下來要開始全量複製,並帶上自己的ID,Slave 接收到這兩個參數後會保存起來。 看圖說話:

發送rdb文件

Master接着就會執行bgsave 生成子進程,完成rdb文件的生成,生成完rdb文件後,會發送rdb文件給Slave,Slave會接收rdb文件,在進行接收之前,會先清空Slave自己的數據庫數據【這個過程是阻塞的】,清空完成後,開始接收rdb文件,接收完成之後,就加載rdb文件到內存中。

這裏還有一個問題,就是在接收rdb文件的時候,Master可能會有新的寫操作過來,由於rdb是某一時刻的內存快照,所以之後的數據,是無法這裏進行傳輸的,這裏redis採用了一個緩衝區來解決,在發送rdb開始,新的寫請求數據都會放到這個緩衝區一份,等待rdb傳輸完成之後,Master接着就會傳輸這個緩衝區的數據到Slave,Slave開始接收,接收完成,主從數據保持一致了,看圖說話:

rdb文件的傳輸:

緩衝區的傳輸:

後續命令的傳輸:

其實這個緩衝區的在redis中叫做replication buffer ,redis 會爲每一個連接Master的Slave生成一個這樣的緩衝區,因爲每個Slave開始同步的時刻,可能是不一樣的,那同步的進度肯定就不一樣了,所以要分別設置一個replication buffer。

只要一個Slave和Master 建立好連接,對應的Slave緩衝區就會建立,如果斷開連接,那麼這個緩衝區就會釋放。

在開始執行bgsave 生成rdb,後續的所有寫請求都會保存到這個緩衝區,也就是replication buffer中,也就是後面所有的寫請求都會通過這個緩衝區發送給Slave。

看圖說話:

如上圖所示,每個Slave對應一個緩衝區,也就是replication buffer。

增量複製

其實上面整個過程完成之後,全量複製就完成了,只要連接不中斷,那麼會持續進行主從的複製,那麼你有沒有想過,如果網關抖動了或者中斷了,主從連接斷開了,redis 會怎麼處理呢?重新走全量複製嗎?

網絡中斷了,怎麼辦?

如果網絡發生中斷,在redis2.8之前會再走一次全量生成rdb進行復制傳輸的,這個是很耗費資源和性能的操作。redis2.8以後,對這個過程做了優化,採用增量複製的機制,來減少數據的傳出,達到了快速複製的目的,下面主要來講解增量複製的過程。

還記得全量複製的時候,會返回給Slave一個偏移量嗎?其實Slave在接收數據之後,會增加這個偏移量來記錄當前接收Master多少數據了。如果Master和Slave的偏移量是1000 ,傳遞30字節給Slave,那麼此時Master和Slave的偏移量應該是1030.

如果網絡發生了中斷,就會重試和Master重新連接,連接之後,會發送自己的offset給Master,Master會根據Slave發送的偏移量來決定是給Slave做增量複製還是做全量複製。

知道了大概的過程,那麼在網絡中斷之後,恢復連接之前,中斷這段時間內的數據,肯定是同步不過去了,那麼數據存儲在哪裏了呢?

只要開始進行主從複製了,那麼新的寫請求在寫入replication buffer的同時,也都會寫入到一個叫做repl_backlog_buffer 的緩衝區內,這是一個環形緩衝區,會記錄Master接收新的寫請求數據的偏移量和新寫命令,這樣Slave再重新連接之後,就可以從這裏接着發送命令給Slave了。

看下replication buffer 和 repl_backlog_buffer(環形緩衝區)的位置圖,加深印象:

注意連接沒有斷開的時候,這兩個緩衝區是同時存在,如果連接斷開,那麼對應Slave的replication buffer緩衝區就會被刪除

其實就是環形的每段記錄着當前數據和偏移量,隨着當前寫入的offset不斷增大,因爲這是一個環形的緩衝區,就會發生覆蓋之前的數據

環形緩衝區,repl_backlog_buffer 記錄是當前Master 接收到新寫請求的累計的offset值(master_repl_offset),表示是Master的進度,當發生網絡中斷時候,所有的Slave都會和Master的offset進行比較,所以它是所有Slave公用的。

增量複製的過程

  • Slave嘗試發送psync 帶上Master的runID和 自己的 offset (slave_repl_offset) 。
  • Master接收到psync 之後,進行判斷是進行增量複製還是進行全量複製。

可以進行增量複製,看圖:

如果接收到的runID 和Master runID 相同,同時repl_backlog_buffer緩衝區的offset會與Slave 發過來的offset進行比較,如果主從節點的差距沒有超過環形緩衝區的長度,或者沒有發生套圈,也就是不會發生覆蓋之前的數據,那麼Master會回覆Continue給Slave,告訴Slave可以進行增量複製了。

如果發現runID和現在Master不一致,或者 主從的offset差距超過的repl_backlog_buffer緩衝區的長度,那麼就會走全量複製了,這裏就不多說了。

  • Master發送offset之後的命令給Slave,看圖說話。

由於Slave發送過來的offset是998 ,現在Master的offset是1000,所以Master會把998-1000之間的命令繼續傳遞給Slave,這樣就做到增量傳輸了。

總結

到現在整個redis 主從複製的過程就講解完成了,現在來做下總結。

主從同步分爲兩個類型:

  • 全量同步

全量同步redis 會執行bgsave 來生成rdb文件,然後發送給從庫,從庫接收之前會先清空從庫的數據空,防止之前有數據造成數據的污染,接收完rdb文件之後,就會就加載rdb文件到內存,這是同步其實並沒有完成,在進行生成rdb文件的時候,還會有新的寫請求過來,此時這些寫請求會緩存在一個緩衝區內,這個緩衝區叫做replication buffer,當從庫加載完rdb之後,就會接收這個緩衝區的所有寫命令了,到此全量複製就結束了。

由於生產rdb是會阻塞主線程,這個過程很耗費資源,如果採用一個主多個從的方式,那麼勢必會增加主庫的壓力,可以選擇一個從,再從庫上再分裂出一個從或者多個從,來減少主庫的壓力。

如果想要快速的生成rdb文件 ,應該減少redis設置內存的大小,這樣生成rdb文件就會很快,減少阻塞的時間。

  • 增量同步

如果主從斷開連接了,redis 主庫會判斷是進行全量複製還是增量複製,主庫會根據從庫發送過來的runID和從庫複製進行offset,如果runID和主庫的ID相同,並且主從的offset差距沒有超過repl_backlog_buffer緩衝區的長度,就會複製offset之間的repl_backlog_buffer的命令給Slave。

兩個緩衝區:

  • replication buffer

replication buffer 是在從庫和主庫建立連接成功後創建的,在主從斷開後,這個緩衝區也會被主庫進行刪除,主從庫之間複製命令的傳輸,都會經過這個buffer,而且這個buffer是每個從庫獨有的。

  • repl_backlog_buffer

開始進行命令傳輸之前,就會建立好這個buffer,這個buffer記錄當前Master接收到的新的寫操作命令offset和命令本身,是所有Slave公用的buffer,Slave 發送psync之後,會和Master的offset進行比較,來決定是否進行增量複製。

注意點:

1、redis 實例的內存大小不要設置太大,這樣能夠縮短生成rdb文件的時間,同時也能縮短全量複製的時間,減少帶寬的佔用。
2、如果從庫和主庫斷開連接超時很長,那麼repl_backlog_buffer緩衝區內的數據很可能就會被覆蓋了,進而會退化爲全量複製了,此時可以設置repl_backlog_size 這個參數設置大些。
3、replication buffer,這個緩衝區也要留意,如果從庫接收得很慢,這個緩衝區會滿,redis可能就會OOM了,如果這個buffer滿了redis 會怎麼處理,redis提供了
client-output-buffer-limit參數限制這個buffer的大小,如果滿了,主庫會和從斷開連接,刪除buffer,如果從再來請求鏈接,可能會造成惡性循環。


今天的分享就到這裏了,碼字畫圖不易,期待你的點贊、關注、轉發,謝謝。

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