Redis複製過程詳解

cdrcsy發表於2024-07-08
主從複製簡介
  主從複製是為了達成高可用,即使有其中一臺伺服器當機,其他伺服器依然可以繼續提供服務,實現Redis的高可用。
  一個主節點可以有多個從節點(或沒有從節點),但一個從節點只能有一個主節點。
主從複製的作用
  讀寫分離:主節點寫,從節點讀,提高伺服器的讀寫負載能力
  資料冗餘︰主從複製實現了資料的熱備份,一種資料冗餘方式。
  故障恢復︰當主節點出現問題時,從節點可以升級為主節點繼續提供服務。提供故障恢復的能力。
  高可用的基石則是叢集高可用。
一、複製過程
階段一:建立連線
  步驟1:設定master的地址和埠,儲存master資訊
  步驟2:建立socket連線
  步驟3:傳送ping命令(定時器任務)
  步驟4:身份驗證
  步驟5:傳送slave埠資訊
至此,主從連線成功!
master和slave詳細連線流程
  slave:1.傳送指令:slaveof ip port
  master:2.接收到指令,響應從節點PONG。
  slave:3.儲存master的IP與埠
  slave:4.根據儲存的資訊建立連線master的socket
  slave:5.週期性傳送命令:ping
  master:6.響應pong
  slave:7.傳送指令:auth password
  master:8.驗證授權
  slave:9.傳送指令:replconf listening-port <port-number>
  master:10.儲存slave的埠號
階段二:資料同步
在slave初次連線master後,複製master中的所有資料到slave
  步驟1:請求同步資料
  步驟2:建立RDB同步資料
  步驟3:恢復RDB同步資料
  步驟4:請求部分同步資料
  步驟5:恢復部分同步資料
至此,資料同步工作完成!
master和slave詳細同步流程
  slave:1.傳送指令:psync2
  master:2.執行bgsave
  master:3.第一個slave連線時,建立命令緩衝區
  master:4.生成RDB檔案,透過socket傳送給slave
  slave:5.接收RDB,清空資料,執行RDB檔案恢復過程。
  slave:6.傳送命令告知RDB恢復已經完成
  master:7.傳送複製緩衝區資訊
  slave:8.接收資訊,執行bgrewriteaof,恢復資料
其中1-5屬於全量複製,6-8屬於部分複製
資料同步階段master說明
  1:如果master資料量巨大,資料同步階段應避開流量高峰期,避免造成master阻塞,影響業務正常執行。
  2:複製緩衝區大小設定不合理,會導致資料溢位,如進行全量複製週期太長,進行部分複製時發現資料已經存在丟失的情況,必須進行第二次全量複製,致使slave陷入死迴圈狀態。 repl-backlog-size 20mb
  3:master單機記憶體佔用主機記憶體的比例不應過大,建議使用50%-70%的記憶體,留下30%-50%的記憶體用於執行bgsave命令和建立複製緩衝區
資料同步階段slave說明
  1:為避免slave進行全量複製、部分複製時伺服器響應阻塞或資料不同步,建議關閉此期間的對外服務。slave-serve-stale-data no, 從伺服器將阻塞所有請求,有客戶端請求時返回“SYNC with master in progress”; yes則slave可以相應請求。
  2:多個slave同時對master請求資料同步,master傳送的RDB檔案增多,會對頻寬造成巨大沖擊,建議在業務低峰期執行。
  3:slave過多時,建議調整拓撲結構,由一主多從結構變為樹狀結構,可能導致深度越高的slave與最頂層master間資料同步延遲較大,資料一致性變差,一般情況下不建議配置。
階段三:命令傳播
當master資料庫狀態被修改後,主從伺服器資料庫狀態是不一致,master將同步rdb階段接收到的資料變更命令傳送給slave,slave接收命令後執行命令。
命令傳播階段出現了斷網現象:
  網路閃斷閃連:忽略
  短時間網路中斷:部分複製
  長時間網路中斷:全量複製
部分複製的三個核心要素
  伺服器的執行id(runid)
  主伺服器的複製積壓緩衝區
  主從伺服器的複製偏移量
透過offset區分不同的slave當前資料傳播的差異
master記錄已傳送的資訊對應的offset
slave記錄已接收的資訊對應的offset
2、主從節點各自複製偏移量
  參與複製的主從節點都會維護自身的複製偏移量。
  主節點在處理完寫入命令後,會把命令的位元組長度做累加記錄,統計資訊在 info replication 中的 masterreploffset 指標中。
  從節點每秒鐘上報自身的的複製偏移量給主節點,因此主節點也會儲存從節點的複製偏移量。
  從節點在接收到主節點傳送的命令後,也會累加自身的偏移量,統計資訊在 info replication 中。
  透過對比主從節點的複製偏移量,可以判斷主從節點資料是否一致。
3、主節點複製積壓緩衝區
  複製積壓緩衝區是一個儲存在主節點的一個固定長度的先進先出的佇列,預設大小 1MB。
  這個佇列在 slave 連線時建立。這時主節點響應寫命令時,不但會把命令傳送給從節點,也會寫入複製緩衝區。
  他的作用就是用於部分複製和複製命令丟失的資料補救。透過 info replication 可以看到相關資訊。
4、主節點執行ID
  每個 redis 啟動的時候,都會生成一個 40 位的執行 ID。
  執行 ID 的主要作用是用來識別 Redis 節點。如果使用 ip+port 的方式,那麼如果主節點重啟修改了 RDB/AOF 資料,從節點再基於偏移量進行復制將是不安全的。所以,當執行 id 變化後,從節點將進行全量複製。也就是說,redis 重啟後,預設從節點會進行全量複製。
5、如果在重啟時不改變執行ID呢?
  可以透過 debug reload 命令重新載入 RDB 並保持執行 ID 不變,從而有效的避免不必要的全量複製。
  缺點是:debug reload 命令會阻塞當前 Redis 節點主執行緒,因此對於大資料量的主節點或者無法容忍阻塞的節點,需要謹慎使用。一般透過故障轉移機制可以解決這個問題。
  從節點傳送 psync 命令給主節點,runId 就是目標主節點的 ID,如果沒有預設為 -1,offset 是從節點儲存的複製偏移量,如果是第一次複製則為 -1.主節點會根據 runid 和 offset 決定返回結果:
  如果回覆 +FULLRESYNC {runId} {offset} ,那麼從節點將觸發全量複製流程。
  如果回覆 +CONTINUE,從節點將觸發部分複製。
  如果回覆 +ERR,說明主節點不支援 2.8 的 psync 命令,將使用 sync 執行全量複製。
二、部分複製
當從節點正在複製主節點時,如果出現網路閃斷和其他異常,從節點會讓主節點補發丟失的命令資料,主節點只需要將複製緩衝區的資料傳送到從節點就能夠保證資料的一致性,相比較全量複製,成本小很多。
  當從節點出現網路中斷,超過了 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 秒,則判斷節點下線。
心跳階段注意事項:
  當slave多數掉線,或延遲過高時
  master為保障資料穩定性,將拒絕所有資訊同步
    min-slaves-to-write 2
    min-slaves-max-lag 8
  slave數量少於2個,或者所有slave的延遲都大於等於8秒時,強制關閉master寫功能,停止資料同步.
四、非同步複製
主節點不但負責資料讀寫,還負責把寫命令同步給從節點,寫命令的傳送過程是非同步完成,也就是說主節點處理完寫命令後立即返回客戶度,並不等待從節點複製完成。
五、常見問題
1、頻繁的全量複製
一旦master重啟,runid將發生變化,會導致全部slave的全量複製操作
最佳化調整方案:
  1:master內部建立master_replid變數,使用runid相同的策略生成,長度41位,併傳送給所有slave
  2:在master關閉時執行命令shutdown save,進行RDB持久化,將runid與offset儲存到RDB檔案中
repl-id repl-offset 透過redis-check-rdb命令可以檢視該資訊
  3:master重啟後載入RDB檔案,恢復資料,重啟後,將RDB檔案中儲存的repl-id與repl-offset載入到記憶體中
master_repl_id=repl master_repl_offset =repl-offset 透過info命令可以檢視該資訊
2、頻繁的全量複製
網路環境不佳,出現網路中斷,slave不提供服務。原因複製緩衝區過小,斷網後slave的offset越界,觸發全量複製
解決辦法:
  評估rdb資料量大小,評估傳輸slave的大致時間h。
  評估日常redis寫入量x/s,x*h = 大致的量,為了保險,建議設定成2倍該大小。
3、頻繁的網路中斷
master的CPU佔用過高或slave頻繁斷開連線
問題原因:
  slave每1秒傳送REPLCONF ACK命令到master,當slave接到了慢查詢時(keys * ,hgetall等),會大量佔用CPU效能。master每1秒呼叫複製定時函式replicationCron(),比對slave發現長時間沒有進行響應
解決方案:
  透過設定合理的超時時間,repl-timeout seconds
  最佳化慢查詢。
4、頻繁的網路中斷
slave與master連線斷開
問題原因:
  master傳送ping指令頻度較低
  master設定超時時間較短
  ping指令在網路中存在丟包
解決方案:
提高ping指令傳送的頻度,repl-ping-slave-period seconds,超時時間repl-time的時間至少是ping指令頻度的5到10倍,否則slave很容易判定超時。
5、資料不一致
多個slave獲取相同資料不同步
問題原因:
  網路資訊不同步,資料傳送有延遲
解決方案:
  最佳化主從間的網路環境,通常放置在同一個機房部署,如使用雲等雲伺服器時要注意此現象
  監控主從節點延遲(透過offset)判斷,如果slave延遲過大,暫時遮蔽程式對該slave的資料訪問slave-serve-stale-data yes|no
  開啟後僅響應info、slaveof等少數命令。注意如果開啟,則客戶端會受到錯誤。

相關文章