深度剖析 Redis 主從架構原理
Redis 的主從架構,其實就是利用多副本,將一份數據同時保存在多個實例上。單個實例出現故障后,一般都會過一段時間才能恢復,那么其他節點還是可以提供服務的。
1. 為什么需要主從架構
單點架構在Redis中可能會帶來以下問題:
- 單點故障:Redis單點故障會導致服務不可用,造成服務中斷或者服務雪崩。高并發情況下,如果Redis單點出現故障,所有請求都會受到影響,無法得到有效響應。
- 可用性問題:由于Redis單點架構沒有備份節點,因此無法在發生故障時快速轉移服務以保證系統的持續可用性。這意味著在單點故障發生時,服務可能需要較長時間才能恢復。
- 數據丟失風險:Redis是內存數據庫,雖然可以通過RDB和AOF文件進行數據持久化備份,但在單點架構中,如果Redis節點發生故障,數據恢復過程可能會耗時較長,且存在數據丟失的風險。
針對這些問題,可以采取主從架構來提高Redis的可用性和容錯性。通過在主節點上設置多個從節點,可以實現數據的復制和故障轉移,從而降低單點故障的影響,提高系統的穩定性和可用性。
2. 主從架構原理
主從架構,事件就是數據可以在多個實例上進行復制,當主節點出現故障時,從節點可以接管服務,從而實現快速故障轉移,保證服務的持續可用性。此外,主從架構還可以提高系統的并發能力,因為多個節點可以同時處理請求。這樣,在主節點故障時,從節點可以立即接管服務,避免了單點故障導致的服務中斷或雪崩效應。
3. 主從架構拓撲圖
在Redis中,主從架構的確實是一種主從庫模式,其中主節點負責處理寫操作并將數據同步到從節點,從節點則負責處理讀操作。這種主從庫模式可以根據節點之間的拓撲結構分為以下三種類型:
- 單主單從結構(Single Master-Single Slave):一個主節點,一個從節點,主節點可讀可寫,從節點只接收讀請求。常用于主節點出現故障時,從節點能夠快速頂上。
圖片
- 單主多從結構(Single Master-Multiple Slaves):一個主節點,多個從節點,對于讀命令較大的場景,可以把讀命令分攤到多個從節點。
圖片
- 樹狀主從結構:一個主節點,多個從節點,其中一個從節點作為中間層,既可以復制主節點,又可以當做其他從節點復制的主節點。有效降低主節點負載和需要傳送給從節點的數據量。
圖片
4. 主從數據同步原理
4.1.全量同步
主從第一次建立連接時,會執行全量同步,將master節點的所有數據都拷貝給slave節點,流程:
圖片
思考:master如何得知salve是第一次來連接呢?
有幾個概念,可以作為判斷依據:
- Replication Id:簡稱replid,是數據集的標記,id一致則說明是同一數據集。每一個master都有唯一的replid,slave則會繼承master節點的replid
- offset:偏移量,隨著記錄在repl_baklog中的數據增多而逐漸增大。slave完成同步時也會記錄當前同步的offset。如果slave的offset小于master的offset,說明slave數據落后于master,需要更新。
slave數據同步,必須向master聲明自己的replication id 和offset,master才可以判斷到底需要同步哪些數據。
slave原本也是一個master,有自己的replid和offset,當第一次變成slave,與master建立連接時,發送的replid和offset是自己的replid和offset。
master判斷發現slave發送來的replid與自己的不一致,說明這是一個全新的slave,就知道要做全量同步了
master會將自己的replid和offset都發送給這個slave,slave保存這些信息。以后slave的replid就與master一致了。
因此,master判斷一個節點是否是第一次同步的依據,就是看replid是否一致。
圖片
完整流程描述:
- slave節點請求增量同步
- master節點判斷replid,發現不一致,拒絕增量同步
- master將完整內存數據生成RDB,發送RDB到slave
- slave清空本地數據,加載master的RDB
- master將RDB期間的命令記錄在repl_baklog,并持續將log中的命令發送給slave
- slave執行接收到的命令,保持與master之間的同步
4.2.增量同步
全量同步需要先做RDB,然后將RDB文件通過網絡傳輸個slave,成本太高了。因此除了第一次做全量同步,其它大多數時候slave與master都是做增量同步。
思考:什么是增量同步?
增量同步是只更新slave與master存在差異的部分數據。
圖片
思考:master怎么知道slave與自己的數據差異在哪里呢?
5.repl_backlog原理
這就要說到全量同步時的repl_baklog文件了。
這個文件是一個固定大小的數組,只不過數組是環形,也就是說角標到達數組末尾后,會再次從0開始讀寫,這樣數組頭部的數據就會被覆蓋。
- repl_baklog中會記錄Redis處理過的命令日志及offset,包括master當前的offset,和slave已經拷貝到的offset:
圖片
slave與master的offset之間的差異,就是salve需要增量拷貝的數據了。
隨著不斷有數據寫入,master的offset逐漸變大,slave也不斷的拷貝,追趕master的offset:
圖片
直到數組被填滿:
圖片
此時,如果有新的數據寫入,就會覆蓋數組中的舊數據。不過,舊的數據只要是綠色的,說明是已經被同步到slave的數據,即便被覆蓋了也沒什么影響。因為未同步的僅僅是紅色部分。
但是,如果slave出現網絡阻塞,導致master的offset遠遠超過了slave的offset:
圖片
如果master繼續寫入新數據,其offset就會覆蓋舊的數據,直到將slave現在的offset也覆蓋:
圖片
棕色框中的紅色部分,就是尚未同步,但是卻已經被覆蓋的數據。此時如果slave恢復,需要同步,卻發現自己的offset都沒有了,無法完成增量同步了,只能做全量同步。
注意:repl_baklog大小有上限,寫滿后會覆蓋最早數據,如果slave斷開時間過久,導致尚未備份的數據被覆蓋,否則無法基于log做增量同步,只能再次全量同步。