天天看點

深入了解redis複制原理

深入了解redis複制原理

1.複制過程

2.資料間的同步

3.全量複制

4.部分複制

5.心跳

6.異步複制

從節點執行 slaveof 指令。

從節點隻是儲存了 slaveof 指令中主節點的資訊,并沒有立即發起複制。

從節點内部的定時任務發現有主節點的資訊,開始使用 socket 連接配接主節點。

連接配接建立成功後,發送 ping 指令,希望得到 pong 指令響應,否則會進行重連。

如果主節點設定了權限,那麼就需要進行權限驗證,如果驗證失敗,複制終止。

權限驗證通過後,進行資料同步,這是耗時最長的操作,主節點将把所有的資料全部發送給從節點。

當主節點把目前的資料同步給從節點後,便完成了複制的建立流程。接下來,主節點就會持續的把寫指令發送給從節點,保證主從資料一緻性。

上面說的複制過程,其中有一個步驟是“同步資料集”,這個就是現在講的“資料間的同步”。

redis 同步有 2 個指令:sync 和 psync,前者是 redis 2.8 之前的同步指令,後者是 redis 2.8 為了優化 sync 新設計的指令。我們會重點關注 2.8 的 psync 指令。

psync 指令需要 3 個元件支援:

主從節點各自複制偏移量

主節點複制積壓緩沖區

主節點運作 ID

主從節點各自複制偏移量:

參與複制的主從節點都會維護自身的複制偏移量。

主節點在處理完寫入指令後,會把指令的位元組長度做累加記錄,統計資訊在 info replication 中的 masterreploffset 名額中。

從節點每秒鐘上報自身的的複制偏移量給主節點,是以主節點也會儲存從節點的複制偏移量。

從節點在接收到主節點發送的指令後,也會累加自身的偏移量,統計資訊在 info replication 中。

通過對比主從節點的複制偏移量,可以判斷主從節點資料是否一緻。

主節點複制積壓緩沖區:

複制積壓緩沖區是一個儲存在主節點的一個固定長度的先進先出的隊列,預設大小 1MB。

這個隊列在 slave 連接配接是建立。這時主節點響應寫指令時,不但會把指令發送給從節點,也會寫入複制緩沖區。

他的作用就是用于部分複制和複制指令丢失的資料補救。通過 info replication 可以看到相關資訊。

主節點運作 ID:

每個 redis 啟動的時候,都會生成一個 40 位的運作 ID。

運作 ID 的主要作用是用來識别 Redis 節點。如果使用 ip+port 的方式,那麼如果主節點重新開機修改了 RDB/AOF 資料,從節點再基于偏移量進行複制将是不安全的。是以,當運作 id 變化後,從節點将進行全量複制。也就是說,redis 重新開機後,預設從節點會進行全量複制。

如果在重新開機時不改變運作 ID 呢?

可以通過 debug reload 指令重新加載 RDB 并保持運作 ID 不變,進而有效的避免不必要的全量複制。

缺點是:debug reload 指令會阻塞目前 Redis 節點主線程,是以對于大資料量的主節點或者無法容忍阻塞的節點,需要謹慎使用。一般通過故障轉移機制可以解決這個問題。

psync 指令的使用方式:

  指令格式為 psync{runId}{offset}

  runId:從節點所複制主節點的運作 id

  offset:目前從節點已複制的資料偏移量

psync 執行流程:

流程說明:

從節點發送 psync 指令給主節點,runId 就是目标主節點的 ID,如果沒有預設為 -1,offset 是從節點儲存的複制偏移量,如果是第一次複制則為 -1.

主節點會根據 runid 和 offset 決定傳回結果:

如果回複 +FULLRESYNC {runId} {offset} ,那麼從節點将觸發全量複制流程。

如果回複 +CONTINUE,從節點将觸發部分複制。

如果回複 +ERR,說明主節點不支援 2.8 的 psync 指令,将使用 sync 執行全量複制。

到這裡,資料之間的同步就講的差不多了,篇幅還是比較長的。主要是針對 psync 指令相關之間的介紹。

全量複制是 Redis 最早支援的複制方式,也是主從第一次建立複制時必須經曆的的階段。觸發全量複制的指令是 sync 和 psync。之前說過,這兩個指令的分水嶺版本是 2.8,redis 2.8 之前使用 sync 隻能執行全量不同,2.8 之後同時支援全量同步和部分同步。

流程如下:

發送 psync 指令(spync ? -1)

主節點根據指令傳回 FULLRESYNC

從節點記錄主節點 ID 和 offset

主節點 bgsave 并儲存 RDB 到本地

主節點發送 RBD 檔案到從節點

從節點收到 RDB 檔案并加載到記憶體中

主節點在從節點接受資料的期間,将新資料儲存到“複制用戶端緩沖區”,當從節點加載 RDB 完畢,再發送過去。(如果從節點花費時間過長,将導緻緩沖區溢出,最後全量同步失敗)

從節點清空資料後加載 RDB 檔案,如果 RDB 檔案很大,這一步操作仍然耗時,如果此時用戶端通路,将導緻資料不一緻,可以使用配置slave-server-stale-data 關閉.

從節點成功加載完 RBD 後,如果開啟了 AOF,會立刻做 bgrewriteaof。

以上加粗的部分是整個全量同步耗時的地方。

注意:

如過 RDB 檔案大于 6GB,并且是千兆網卡,Redis 的預設逾時機制(60 秒),會導緻全量複制失敗。可以通過調大 repl-timeout 參數來解決此問題。

Redis 雖然支援無盤複制,即直接通過網絡發送給從節點,但功能不是很完善,生産環境慎用。

當從節點正在複制主節點時,如果出現網絡閃斷和其他異常,從節點會讓主節點補發丢失的指令資料,主節點隻需要将複制緩沖區的資料發送到從節點就能夠保證資料的一緻性,相比較全量複制,成本小很多。

當從節點出現網絡中斷,超過了 repl-timeout 時間,主節點就會中斷複制連接配接。

主節點會将請求的資料寫入到“複制積壓緩沖區”,預設 1MB。

當從節點恢複,重新連接配接上主節點,從節點會将 offset 和主節點 id 發送到主節點。

主節點校驗後,如果偏移量的數後的資料在緩沖區中,就發送 cuntinue 響應 —— 表示可以進行部分複制。

主節點将緩沖區的資料發送到從節點,保證主從複制進行正常狀态。

主從節點在建立複制後,他們之間維護着長連接配接并彼此發送心跳指令。

心跳的關鍵機制如下:

中從都有心跳檢測機制,各自模拟成對方的用戶端進行通信,通過 client list 指令檢視複制相關用戶端資訊,主節點的連接配接狀态為 flags = M,從節點的連接配接狀态是 flags = S。

主節點預設每隔 10 秒對從節點發送 ping 指令,可修改配置 repl-ping-slave-period 控制發送頻率。

從節點在主線程每隔一秒發送 replconf ack{offset} 指令,給主節點上報自身目前的複制偏移量。

主節點收到 replconf 資訊後,判斷從節點逾時時間,如果超過 repl-timeout 60 秒,則判斷節點下線。

為了降低主從延遲,一般把 redis 主從節點部署在相同的機房/同城機房,避免網絡延遲帶來的網絡分區造成的心跳中斷等情況。

主節點不但負責資料讀寫,還負責把寫指令同步給從節點,寫指令的發送過程是異步完成,也就是說主節點處理完寫指令後立即傳回客戶度,并不等待從節點複制完成。

異步複制的步驟很簡單,如下:

主節點接受處理指令。

主節點處理完後傳回響應結果 。

對于修改指令,異步發送給從節點,從節點在主線程中執行複制的指令。

總結

本文主要分析了 Redis 的複制原理,包括複制過程,資料之間的同步,全量複制的流程,部分複制的流程,心跳設計,異步複制流程。其中,可以看出,RDB 資料之間的同步非常耗時。是以,Redis 在 2.8 版本退出了類似增量複制的 psync 指令,當 Redis 主從直接發生了網絡中斷,不會進行全量複制,而是将資料放到緩沖區(預設 1MB)裡,在通過主從之間各自維護複制 offset 來判斷緩存區的資料是否溢出,如果沒有溢出,隻需要發送緩沖區資料即可,成本很小,反之,則要進行全量複制,是以,控制緩沖區大小非常的重要。

原文位址

https://www.cnblogs.com/luao/p/10682830.html

繼續閱讀