10丨 Redis主从同步与故障切换,有哪些坑
1. 主從數據不一致
??主從數據不一致,就是指客戶端從從庫中讀取到的值和主庫中的最新值并不一致。舉個例子,假設主從庫之前保存的用戶年齡值是 19,但是主庫接收到了修改命令,已經把這個數據更新為 20 了,但是,從庫中的值仍然是 19。那么,如果客戶端從從庫中讀取用戶年齡值,就會讀到舊值。
??那為啥會出現這個坑呢?其實這是因為主從庫間的命令復制是異步進行的。
??具體來說,在主從庫命令傳播階段,主庫收到新的寫命令后,會發送給從庫。但是,主庫并不會等到從庫實際執行完命令后,再把結果返回給客戶端,而是主庫自己在本地執行完命令后,就會向客戶端返回結果了。如果從庫還沒有執行主庫同步過來的命令,主從庫間的數據就不一致了。
??從庫會滯后執行同步命令的原因
?? 一方面主從庫間的網絡可能會有傳輸延遲,所以從庫不能及時地收到主庫發送的命令,從庫上執行同步命令的時間就會被延后。
??另一方面,即使從庫及時收到了主庫的命令,
但是,也可能會因為正在處理其它復雜度高的命令(例如集合操作命令)而阻塞。此時,從庫需要處理完當前的命令,才能執行主庫發送的命令操作,這就會造成主從數據不一致。而在主庫命令被滯后處理的這段時間內,主庫本身可能又執行了新的寫操作。這樣一來,主從庫間的數據不一致程度就會進一步加劇。
??那么,我們該怎么應對呢?我給你提供兩種方法。
??首先,在硬件環境配置方面,我們要盡量保證主從庫間的網絡連接狀況良好。例如,我們要避免把主從庫部署在不同的機房,或者是避免把網絡通信密集的應用(例如數據分析應用)和 Redis 主從庫部署在一起。
??另外,我們還可以開發一個外部程序來監控主從庫間的復制進度。
??因為 Redis 的 INFO replication 命令可以查看主庫接收寫命令的進度信息(master_repl_offset)和從庫復制寫命令的進度信息(slave_repl_offset),所以,我們就可以開發一個監控程序,先用 INFO replication 命令查到主、從庫的進度,然后,我們用 master_repl_offset 減去 slave_repl_offset,這樣就能得到從庫和主庫間的復制進度差值了。
2. 讀取過期數據
??我們在使用 Redis 主從集群時,有時會讀到過期數據。例如,數據 X 的過期時間是202010240900,但是客戶端在 202010240910 時,仍然可以從從庫中讀到數據 X。一個數據過期后,應該是被刪除的,客戶端不能再讀取到該數據,但是,Redis 為什么還能在從庫中讀到過期的數據呢?
??Redis 同時使用了兩種策略來刪除過期的數據,分別是惰性刪除策略和定期刪除策略。
- 先說惰性刪除策略。當一個數據的過期時間到了以后,并不會立即刪除數據,而是等到再有請求來讀寫這個數據時,對數據進行檢查,如果發現數據已經過期了,再刪除這個數據。
- 定期刪除策略是指,Redis 每隔一段時間(默認 100ms),就會隨機選出一定數量的數據,檢查它們是否過期,并把其中過期的數據刪除,這樣就可以及時釋放一些內存。
這跟 Redis 用于設置過期時間的命令有關系,有些命令給數據設置的過期時間在從庫上可能會被延后,導致應該過期的數據又在從庫上被讀取到了,我來給你具體解釋下。我先給你介紹下這些命令。設置數據過期時間的命令一共有 4 個,我們可以把它們分成兩類:
- EXPIRE 和 PEXPIRE:它們給數據設置的是從命令執行時開始計算的存活時間;
- EXPIREAT 和 PEXPIREAT:它們會直接把數據的過期時間設置為具體的一個時間點。
3. 不合理配置項導致的服務掛掉
這里涉及到的配置項有兩個,分別是protected-mode 和 cluster-node-timeout。
1. protected-mode 配置項
??這個配置項的作用是限定哨兵實例能否被其他服務器訪問。當這個配置項設置為 yes 時,哨兵實例只能在部署的服務器本地進行訪問。當設置為 no 時,其他服務器也可以訪問這個哨兵實例。
??正因為這樣,如果 protected-mode 被設置為 yes,而其余哨兵實例部署在其它服務器,那么,這些哨兵實例間就無法通信。當主庫故障時,哨兵無法判斷主庫下線,也無法進行主從切換,最終 Redis 服務不可用。
??所以,我們在應用主從集群時,要注意將 protected-mode 配置項設置為 no,并且將bind 配置項設置為其它哨兵實例的 IP 地址。這樣一來,只有在 bind 中設置了 IP 地址的哨兵,才可以訪問當前實例,既保證了實例間能夠通信進行主從切換,也保證了哨兵的安全性。
??我們來看一個簡單的小例子。如果設置了下面的配置項,那么,部署在 192.168.10.3/4/5這三臺服務器上的哨兵實例就可以相互通信,執行主從切換。
2. cluster-node-timeout 配置項
這個配置項設置了 Redis Cluster 中實例響應心跳消息的超時時間。
當我們在 Redis Cluster 集群中為每個實例配置了“一主一從”
模式時,如果主實例發生故障,從實例會切換為主實例,受網絡延遲和切換操作執行的影響,切換時間可能較長,就會導致實例的心跳超時(超出 cluster-node-timeout)。實例超時后,就會被 Redis Cluster 判斷為異常。而 Redis Cluster 正常運行的條件就是,有半數以上的實例都能正常運行。所以,如果執行主從切換的實例超過半數,而主從切換時間又過長的話,就可能有半數以上的實例心跳超時,從而可能導致整個集群掛掉。所以,我建議你將 cluster-node-timeout 調大些(例如 10 到 20 秒)。
小結
為了方便你掌握,我把這些坑的成因和解決方法匯總在下面的這張表中
總結
以上是生活随笔為你收集整理的10丨 Redis主从同步与故障切换,有哪些坑的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 09丨缓存异常:如何解决缓存和数据库的数
- 下一篇: 03 | 事务隔离:为什么你改了我还看不