redis 之主從同步(兩個緩沖區尤為重要)


當啟動多個服務器時,通過replicaof(redis 5.0之前使用slaveof)命令形成主庫和從庫之間的關系

首先介紹一下名詞 命令傳播:即在主服務器數據庫狀態被修改,導致主從服務器數據庫狀態出現不一致時,讓主從服務器的數據庫狀態重新回到一致狀態。一旦主從庫完成了全量復制,它們之間就會一直維護一個網絡連接,主庫會通過這個連接將后續陸續收到的命令操作再同步給從庫,這個過程也稱為基於長連接的命令傳播,可以避免頻繁建立連接的開銷。

這里就要提到一些命令:在早期版本中,會使用sync進行主從數據庫間數據同步,但是sync采用的是每次全量同步,即每次與數據庫狀態不一致時,主服務器都會生成完整rdb文件傳輸給從服務器,

這樣帶來的影響時,因為主服務器會執行bgsave ,創建子進程生成rdb文件,這個操作會耗費主服務器大量的cpu,內存和磁盤資源,主服務器同時需要將生成的rdb文件傳遞給從服務器,這個發送操作同樣

會耗費主從服務器大量的網絡帶寬和流量,接收到rdb文件的從服務器需要載入主服務器發來的rdb我呢間,並且在載入期間,從服務器會因為阻塞而沒有辦法處理命令請求。

在新版本中采用了psync來進行主從同步,首先,主從庫間建立連接、協商同步的過程,主要是為全量復制做准備。在這一步,從庫和主庫建立起連接,並告訴主庫即將進行同步,主庫確認回復后,

主從庫間就可以開始同步了。

下面介紹psync的命令參數:

下面所述皆為第一次進行同步時的情況:

從庫給主庫發送 psync 命令,表示要進行數據同步,主庫根據這個命令的參數來啟動復制。psync 命令包含了主庫的 runID 和復制進度 offset 兩個參數。

runID,是每個 Redis 實例啟動時都會自動生成的一個隨機 ID,用來唯一標記這個實例。

當從庫和主庫第一次復制時,因為不知道主庫的 runID,所以將 runID 設為“?”。

offset,此時設為 -1,表示第一次復制。主庫收到 psync 命令后,會用 FULLRESYNC 響應命令帶上兩個參數:主庫 runID 和主庫目前的復制進度 offset,返回給從庫。從庫收到響應后,會記錄下這兩個參數。

FULLRESYNC 響應表示第一次復制采用的全量復制,也就是說,主庫會把當前所有的數據都復制給從庫。
在主從服務器進行同步的過程中,主庫不會被阻塞,同樣可以接受請求否則,Redis 的服務就被中斷了。但是,這些請求中的寫操作並沒有記錄到剛剛生成的 RDB 文件中。為了保證主從庫的數據一致性,主庫會在內存中用專門的 replication buffer,記錄 RDB 文件生成后收到的所有寫操作。  (注意這里所說的同步是第一次,這里所說的緩沖區與下面要介紹的緩沖區並不是一樣的,下面將要介紹,如果進行第一次同步后,主從服務器網絡中斷后,又重新進行恢復后(對於中間產生的數據造成主從庫狀態不一致)的應對策略)

最后主庫會把執行過程中replication_buffer緩沖區中的的寫命令,再發送給從庫。具體的操作是,當主庫完成 RDB 文件發送后,就會把此時 replication buffer 中的修改操作發給從庫,從庫再重新執行這些操作

到此在第一次進行全量復制時可能出現的各種討論已經介紹完畢。

下面就要討論,命令傳播階段出現的主從庫狀態不一致,和主從庫間網絡中斷時出現的一些問題。

從 Redis 2.8 開始,網絡斷了之后,主從庫會采用增量復制的方式繼續同步。增量復制只會把主從庫網絡斷連期間主庫收到的命令,同步給從庫。

這里就會用到三個增量復制的實現細節:
主服務器的復制偏移量:replication_offset

主服務器的復制積壓緩沖區:replication_backlog

服務器的運行id

 

對於復制偏移量:執行復制的雙方,主從服務器都會維護一個復制偏移量,主服務器每次向從服務器傳播n個字節的數據時,就將自己的膚質偏移量的值加上N,從服務器每次收到主服務器傳播來的N個字節數據時,就將自己的復制偏移量的值加上N。

當主從庫斷連后,主庫會把斷連期間收到的寫操作命令,寫入 replication buffer,同時也會把這些操作命令也寫入 repl_backlog_buffer 這個緩沖區。

即同時主服務器進行命令傳播期間(從服務器完成全量復制后,主服務器接受到寫命令,會同時將命令傳播到從服務器),不僅將寫命令發送給所有服務器,還會將寫命令寫入復制積壓緩沖區。

主服務器的復制積壓緩沖區會保存着一部分最近傳輸的命令。

所以如果網絡中斷后,主從庫的連接恢復之后,從庫首先會給主庫發送 psync 命令,並把自己當前的 slave_repl_offset 發給主庫,主庫會判斷自己的 master_repl_offset 和 slave_repl_offset 之間的差距。

在網絡斷連階段,主庫可能會收到新的寫操作命令,所以,一般來說,master_repl_offset 會大於 slave_repl_offset。此時,主庫只用把 master_repl_offset 和 slave_repl_offset 之間的命令操作同步給從庫就行。

 

 

比較容易弄混的一個地方 replication_buffer 與 replication_backlog_buffer 之間的區別

首先來說一下復制緩沖區。

作用:主節點開始和一個從節點進行全量同步時,會為從節點創建一個輸出緩沖區,這個緩沖區就是復制緩沖區。當主節點向從節點發送 RDB 文件時,如果又接收到了寫命令操作,就會把它們暫存在復制緩沖區中。等 RDB 文件傳輸完成,並且在從節點加載完成后,主節點再把復制緩沖區中的寫命令發給從節點,進行同步。對主從同步的影響:如果主庫傳輸 RDB 文件以及從庫加載 RDB 文件耗時長,同時主庫接收的寫命令操作較多,就會導致復制緩沖區被寫滿而溢出。一旦溢出,主庫就會關閉和從庫的網絡連接,重新開始全量同步。所以,我們可以通過調整 client-output-buffer-limit slave 這個配置項,來增加復制緩沖區的大小,以免復制緩沖區溢出。

再來看看復制積壓緩沖區。

作用:主節點和從節點進行常規同步時,會把寫命令也暫存在復制積壓緩沖區中。如果從節點和主節點間發生了網絡斷連,等從節點再次連接后,可以從復制積壓緩沖區中同步尚未復制的命令操作。對主從同步的影響:如果從節點和主節點間的網絡斷連時間過長,復制積壓緩沖區可能被新寫入的命令覆蓋。此時,從節點就沒有辦法和主節點進行增量復制了,而是只能進行全量復制。針對這個問題,應對的方法是調大復制積壓緩沖區的大小

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM