點擊上方“JavaEdge”,關注公衆號
1 重啓和故障轉移後的部分重同步
Redis 4.0 開始,當一個實例在故障轉移後被提升爲 master,它仍能與舊 master 的 Replica 進行部分重同步。爲此,Replica 會記住舊 master 的舊 replication ID 和複製偏移量,因此即使詢問舊的 replication ID,也可以將部分複製緩衝提供給連接的 Replica 。
但升級的 Replica 的新 replication ID 將不同,因爲它構成了數據集的不同歷史記錄。例如,master 可以返回可用,並且可以在一段時間內繼續接收寫命令,因此在被提升的 Replica 中使用相同的 replication ID 將違反 一對複製標識和偏移對只能標識單一數據集 規則。
Replica 在關機並重啓後,能夠在 RDB 文件中存儲所需信息,以便與 master 進行重同步。這在升級的情況下很有用。當需要時,最好使用 SHUTDOWN 命令執行 Replica 的保存和退出操作。
2 主從數據不一致
很顯然,這是由於主從網絡延時。
2.1 主多從少
部分重同步。可通過命令 PSYNC master_run_id offset 執行。
2.2 主少從多
全量複製,覆蓋。這種情況是因爲 Replica 是讀寫模式,因此:
關閉 Replica 的讀寫模式
或刪除 Replica 的數據,重新從 Master 全量複製
3 數據延遲
編寫外部程序監聽主從節點的複製偏移量,延遲較大時發出報警或通知客戶端,切換到 Master 或其他節點。
設置 Replica:
slave-serve-stale-data = no
除 INFO 和 SLAVOF 命令之外的任何請求都會返回一個錯誤“SYNC with master in progress”。
當 Replica 失去與Master 的連接時或仍在進行復制時,Replica 可以如下方式起作用:
若
replica-serve-stale-data
爲 yes(默認值),則 Replica 仍會回覆客戶端請求,可能帶有過期數據,或者說,若這是第一次同步,則數據集可能只是空的若將
replica-serve-stale-data
設爲no,則該 Replica 將對除以下信息以外的所有命令返回錯誤“SYNC with master in progress”:INFO,REPLICAOF,AUTH,PING,SHUTDOWN,REPLCONF,ROLE,CONFIG ,SUBSCRIBE,UNSUBSCRIBE,PSUBSCRIBE,PUNSUBSCRIBE,PUBLISH,PUBSUB,COMMAND,POST,HOST和LATENCY
4 髒數據
4.1 髒數據產因
4.1.1 Redis 刪除策略
因爲讀到了過期數據,而讀到過期數據就是 Redis 刪除策略所導致的:
惰性刪除
Master 每次讀取命令時都會檢查K是否超時,若超時,則執行 del 命令刪除K,之後異步把 del 命令同步給 Replica,即可保證數據複製的一致性。切記 Replica 永遠不會主動去刪除超時數據。
定時刪除
Redis 的 Master 在內部有定時任務,會循環採樣一定數量的K,當發現採樣K過期,會執行 del,之後再同步給每個 Replica。
主動刪除
當前已用內存超過 maxmemory 限定時,觸發主動清理策略。主動設置的前提是設置了 maxMemory 的值 注:如果數據大量超時,master 節點採樣速度跟不上過期的速度,而且 master 節點沒有讀取過期鍵的操作,那 slave 節點是無法收到 del 命令的,這時從節點上讀取的數據已經是超時的了。
4.1.2 從節點可寫
如果從節點(默認讀模式)是讀寫模式,可能誤寫入從節點的數據,後期就會成爲髒數據。
4.2 解決方案
4.2.1 忽略
比如 12306 查餘票、雙十一秒殺的庫存,你會發現經常就是前後不一致的數據。因爲你查詢時得到的數據,就是需要允許寫錯誤。
4.2.2 選擇性強制讀主
但是真正下單扣庫存時,你就必須確保數據的正確性 選擇強制讀 master,slave間接變爲備份服務器(某個業務)。
4.2.3 從節點只讀
防止 slave 寫入髒數據。
4.2.4 Redis自身優化
Redis3.2 版本解決了 Redis 刪除策略導致的過期數據,在此版本中 slave 讀數據前,會檢查K過期時間,以決定是否返回數據。
5 數據安全性
5.1 關閉主節點持久化
爲提升Redis性能,一般會關閉 Master 持久化的功能(這樣所有數據都會持久化在 slave),因爲主從同步時,Master 都會 bgsave rdb。但這樣也會帶來複制的安全性問題。
在使用 Redis 複製功能時的設置中,推薦在 master 和在 slave 中啓用持久化。當不可能啓用時,例如由於非常慢的磁盤性能而導致的延遲問題,應該禁用主節點自動重啓功能。
風險場景
關閉 Master 的持久化設置,Replica1 和 Replica2 從 Master 複製數據。Master 只有內存數據,沒有磁盤數據了。
當 Master 宕機,由於自動重啓機制重啓了,但重啓後由於持久化被關閉了,Master數據集爲空!
重啓後的 Master,發現 runId 發生變化,也會重新和從節點建立連接,兩個從節點會發起復制請求,從Master 複製數據,但 Master 此時數據集爲空,因此複製的結果是它們會銷燬自身之前的數據副本而變成空數據集。
5.1.1 解決方案
犧牲性能,開啓 Master 的持久化功能。
爲了性能,依舊選擇關閉,那就讓主節點不自動重啓,比如不要有Docker或腳本等自動重啓機制。
往期推薦
目前交流羣已有 800+人,旨在促進技術交流,可關注公衆號添加筆者微信邀請進羣
喜歡文章,點個“在看、點贊、分享”素質三連支持一下~
本文分享自微信公衆號 - JavaEdge(Java-Edge)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。