面試官:你們Redis故障過嗎,怎麼解決?


  點擊上方“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

INFOSLAVOF 命令之外的任何請求都會返回一個錯誤“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 中啓用持久化。當不可能啓用時,例如由於非常慢的磁盤性能而導致的延遲問題,應該禁用主節點自動重啓功能。

風險場景


  1. 關閉 Master 的持久化設置,Replica1 和 Replica2 從 Master 複製數據。Master 只有內存數據,沒有磁盤數據了。

  2. Master 宕機,由於自動重啓機制重啓了,但重啓後由於持久化被關閉了,Master數據集爲空!

  3. 重啓後的 Master,發現 runId 發生變化,也會重新和從節點建立連接,兩個從節點會發起復制請求,從Master 複製數據,但 Master 此時數據集爲空,因此複製的結果是它們會銷燬自身之前的數據副本而變成空數據集。 

5.1.1 解決方案


  • 犧牲性能,開啓 Master 的持久化功能。

  • 爲了性能,依舊選擇關閉,那就讓主節點不自動重啓,比如不要有Docker或腳本等自動重啓機制。


往期推薦


由於不知線程池的bug,某Java程序員叕被祭天

程序員因重複記錄日誌撐爆ELK被辭退!

擁抱Kubernetes,再見了Spring Cloud

JDK爲何自己先破壞雙親委派模型?




目前交流羣已有 800+人,旨在促進技術交流,可關注公衆號添加筆者微信邀請進羣


喜歡文章,點個“在看、點贊、分享”素質三連支持一下~

本文分享自微信公衆號 - JavaEdge(Java-Edge)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章