redis 復制 及其工作原理
在分布式系統中為解決單點問題,通常會把數據復制多個副本部署到其他機器,滿足故障恢復和負載均衡等需求,redis使用復制功能來保證了高可用
建立復制
復制的redis節點分為主節點(master)和從節點(slave),主從對應是一對多的關系,配置方式有三種
1. 在配置文件中加入 slaveof {masterHost} {masterport} 隨redis啟動生效
2. 在redis-server啟動命令後加入 --slaveof {masterHost} {masterPort} 生效
3. 直接使用命令 slaveof {masterHost} {masterPort} 也可用來切換新的主節點(切換後從節點會清空原來的所有數據)
info replication 可以查看復制節點的信息
slaveof no one 斷開復制,從節點晉升為主節點
傳輸延遲
主從節點一般部署在不同機器上,復制時的網絡延遲必須要考慮到,redis提供的參數repl-disable-tcp-nodelay 用於控制是否關閉TCP_NODELAY 默認為no 關閉
當關閉時:主節點產生的命令數據無論大小都會及時發送給從節點,這樣主從之間延遲會變小,但增加了網絡帶寬的消耗,適用於主從之間的網絡環境良好的情況,如同機房部署
當開啟時:主節點會合並較小的tcp數據包,從而節省帶寬,但是延遲會變大,適用於主從網絡環境復制或帶寬緊張的情況,如異地部署
原理
在從節點執行slaveof 後,過程如下
1.保存主節點信息
執行slaveof後從節點只保存主節點的地址信息後便直接返回,此時建立復制的流程還沒有開始
2.從節點內部通過每秒運行的定時任務維護復制相關的邏輯,當定時任務發現存在新的主節點後,會嘗試與該主節點建立網絡socket連接 (如果從節點無法建立連接,定時任務講無限期重試,直到成功)
3.發送ping命令,嘗試第一次與主節點通信,主要目的是檢測主從網絡socket是否可用和主節點當前是否可接受處理命令
如果沒有收到主節點的pong回復或者超時,從節點會斷開復制連接,下次定時任務時重試
4.權限驗證。如果主節點設置了requirepass 參數,則需要密碼驗證,從節點必須配置masterauth 參數保證與主節點相同的密碼才能通過驗證,驗證失敗,復制終止
5.同步數據集。主從復制連接正常通信後,對於首次建立的復制場景,主節點會把所有的數據全部發送給從節點,耗時最長
6.命令持續復制(異步)。有寫命令時,持續同步到從節點
數據同步
redis在2.8後采用復制命令psync進行數據同步 (psync {run_id} {offset})
全量復制: 一般用於首次復 制,當數據量較大時,會對主從節點和網絡造成很大開銷
部分復制:用於處理在主從復制中因網絡閃斷等原因造成的數據丟失場景,主節點會補發丟失的數據給從節點,可避免全量復制的過高開銷
部分復制時,psync 需要帶上
1.主從節點各自的復制偏移量 : master_repl_offset ,slave_repl_offset
2.主節點的復制積壓緩沖區
3.主節點運行id run_id ,如果只識別host 和port 那麽當主節點更換RDB文件時,從節點還使用原來的偏移量復制,會造成數據錯誤,,,因此每次主節點重啟時,都會進行全量復制,可使用redis-cli debug reload 每次重啟run_id 不變
全量復制流程
- 發送psync同步命令,第一次沒有主節點運行ID會默認為?,沒有復制偏移量默認為-1 。所以發送psync ? -1
- 主節點解析出命令為全量復制,回復 +FULLRESYNC響應,帶上run_id 和offset
- 從節點接收到主節點的回復後,保存run_id 和offset
- 主節點執行bgsave保存RDB文件到本地
- 主節點發送RDB文件給從節點,從節點把接收的RDB文件保存在本地,並直接作為從節點的數據文件(這一步涉及RDB文件的傳輸,如果RDB文件太大,會導致傳輸耗時,超過6G時,可能會導致傳輸時間超過repl-timeout的值,進而從節點會放棄接受RDB文件並清理已下載的臨時RDB文件,導致全量復制識別,建議可調整repl-timeout 的值,默認60秒)
- 對於從節點從開始接受RDB快照,到接受 完畢,主節點依然會有讀寫操作,此段時間內,主節點會把寫命令保存在復制積壓緩沖區,當從節點完成接收時,主節點再發送給從節點,保證了主從一致性
- 從節點接收完主節點的全部數據後會清空自身舊數據
- 清空舊數據後開始加載RDB文件(對於較大的RDB文件,此步驟也是很耗時)
- 從節點加載完RDB後,如果當前節點開啟了AOF持久化功能,他會立即做bgrewriteaof 操作,保證了全量復制後AOF立即可用
心跳
主從建立復制後,他們之間會維護一個長連接並彼此發送心跳命令
主對從:ping,從對主:replconf ack {offset}
1.主從彼此都有心跳檢測機制,可通過client list 查看復制的相關信息
2.主節點每個10秒發送ping命令,判斷從節點的存活性和連接狀態,可通過repl-ping-slave-period 控制發送頻率
3.從節點每隔1秒發送replconf ack {offset} 命令,給主節點上報自身當前復制偏移量 ,主節點根據此命令判斷從節點超時時間,通過info replication 中的 lag字段(表示與從節點最後一次通信延遲的秒數)正常延遲在0-1之間
關於在實際中可以遇到的問題
1.讀寫分離
主從復制除了做備份以為,最主要的就是用來做讀寫分離,降低單點的壓力
1.復制延遲
由於主從復制的異步特性,會導致一段時間內主從數據的不一致問題,這需要業務場景允許短時間數據延遲,對於零容忍延遲,可使用外部程序從主節點的復制積壓緩沖區中取數據,和mysql主從復制中延遲問題的解決方案差不多
2.讀到過期數據
當主節點存儲大量的過期數據時,如緩沖數據,redis內部需要維護過期數據的刪除策略
1.惰性刪除:主節點每次處理命令時,都會檢測鍵是否過期超時,如果超時則執行del刪除命令,之後的del命令也會發送給從節點,為確保主從數據一致性,從節點不會主動刪除過期數據
2.定時刪除:redis主節點在內部定時任務會采樣一定數據鍵,發現有過期數據鍵時,執行del鍵命令,在大量數據超時並且從節點沒有收到del命令時,在redis3.2版本後,從節點在讀取數據之前會檢測鍵是否過期,來決定是否發送數據
2.主從配置不一致
對於有關內存的命令必須主從一致,maxmemory,hash-max-ziplist-entries 等參數
3.規避全量復制
1.第一次復制:不可避免,建議低峰時操作
2.節點運行ID不匹配:如果主節點宕機重啟,會導致run_id 變化,引起全量復制,這種情況要在架構上避免,可使用故障轉移功能,在主節點發生故障後,從節點能晉升為主節點
3.復制及壓緩沖區不足:主節點網絡中斷後,此時主節點會把寫命令放入復制積壓緩沖區,如果時間長,復制積壓緩沖區內存不夠,導致從節點再次連接時嘗試部分復制,從復制積壓緩沖區找不到偏移量,此時會退化成全量復制,【需要根據網絡中斷時間, 和寫數據量分析出合理的復制積壓緩沖區大小,避免再次連接後找不到偏移量的問題】
4. 復制風暴問題
1.單主節點復制風暴
一個主機上掛載多個從節點情況,當主節點恢復後,導致多個從節點發起全量復制,主節點會創建RDB快照,發送給多個從節點,從而導致主節點的帶寬消耗嚴重變大,造成主從延遲變大,嚴重可能會斷開復制【可架構樹狀結構,減輕主節點的復制壓力】
2.單機器復制風暴
單臺機器部署多個redis【多個主從】實例,當這臺機器出現故障或者網絡延遲時,恢復正常後,會有大量從節點對這臺機器的主節點進行全量復制,導致當前機器帶寬消耗,IO消耗,【應該把主節點部署到多臺機器】。【避免恢復後,密集的復制】
redis 復制 及其工作原理