Redis主從復制原理和復制方式那點事!
通過學習我們知道通過持久化技術讓服務器重啟的情況下盡可能少或者不會丟失數據。
但是問題在于持久化的數據在單一的服務器上,萬一服務器的硬盤出現了故障,那就可能數據就真的沒了!
而在Redis中主從復制,是指將一臺Redis服務器的數據,復制到其他的Redis服務器(數據備份了)。被復制的服務器稱為主服務器(master),對主服務器進行復制操作的為從服務器(slave)。
?? 要注意的是數據的復制是單向的,只能由主節點到從節點!
主從服務器庫之間采用的是讀寫分離的方式
? 讀操作:主庫、從庫都可以接收讀操作
? 寫操作:首先到主庫執行寫,然后,主庫將寫操作同步給從庫
圖片
主從復制的好處
? 數據冗余 :實現數據的熱備份
? 故障恢復 :避免單點故障帶來的服務不可用,可以由從節點提供服務,實現快速的故障恢復
? 讀寫分離 :在主從復制的基礎上,配合讀寫分離,可以由主節點提供寫服務,由從節點提供讀服務,可分擔服務器負載;尤其是在寫少讀多的場景下,通過多個從節點分擔讀負載,可以大大提高Redis服務器的并發量
? 高可用基礎 :是哨兵機制和集群實現的基礎
圖片
今天小許將分享Redis高可用知識點之【Redis主從復制】,可能你在其他地方看過,相信你跟著小許思路,能幫你重新回憶一遍、不會的同學好好學一波!
內容比較多,在地鐵上看文章的你可以先關注、收藏一下,用電腦看舒服!
圖片
實現原理
進行復制之前我們要確定的是誰是主和從服務器,我們將在從從服務器上使用 slaveof命令形成主從關系,命令如下:
redis 5.0之前使用 salveof 命令(salveof <master IP 地址> <master 端口號>)
redis 5.0之后使用 replicaof 命令(replicaof <master IP 地址> <master 端口號>)
文章后續將用 master 表示主服務器 , slave 表示從服務器。
Redis服務器執行上述命令的成為了從服務器slave,我們看下進行復制涉及了哪些流程,然后一個個看看每個流程具體干了什么,了解Master和Slave復制的實現!
圖片
設置master 地址和端口
在準備成為slave的Redis服務器上執行下面命令:
127.0.0.1:12345> SLAVEOF 127.0.0.1 6379
OK
salve服務器執行salveof命令【異步命令】的目的是,將給定的master服務器IP地址127.0.0.1和端口6379,保存到從服務器的masterhost屬性和masterport屬性里面。
redisServer 結構體的字段太多了,這里只展示復制是master的一部分,還有slave的部分屬性就不展示了!
//salve的服務器結構體值
struct redisServer{
//...
/* Replication (slave) */
// 驗證信息
char *masterauth;
// 命令執行成功后值 127.0.0.1
char *masterhost;
// 6379
int masterport;
//...
};
建立socket連接
slave將根據命令(slave或replicaof)設置的IP地址和端口,創建連向master的套接字(socket)連接。
socket連接到master之后,會注冊一個文件事件【syncWithMaster】,接收后續RDB文件、實時寫命令,當然在連接建立之后,master也會創建相應的客戶端狀態啦!
圖片
發送 ping 命令
slave成為mater的客戶端之后先發送PING命令,主要作用如下:
1. 檢查salve和master的套接字讀寫狀態
2. 檢查master是否能正常處理命令
slave收到PONG回復后才會繼續執行后續步驟!
身份驗證
客戶端如果開啟了密碼保護的話,在每次連接 Redis 服務器之后,就要使用 AUTH 命令解鎖,解鎖之后才能使用其他 Redis 命令。
也就是說如果slave設置了 masterauth 屬性,那么將會向master發送一條AUTH命令進行身份驗證,目的是檢驗給定的密碼 password 和master配置文件中requirepass 項的值是否相符。
向master發送監聽端口
slave身份驗證之后,發送執行以下命令向mater發送監聽端口信息
REPLCONF listening-port <salve監聽端口號>
master接收到到命令后,會記錄在主服務器對應的客戶端狀態 salve_listening_port屬性中
圖片
我們可以在master上執行“info replication”命令可以看到從服務器的port
圖片
同步
slave會向master發送一個 psync 命令來進行數據同步,并且數據同步將分為全量同步和部分同步。
命令持續復制
在完成同步之后,master -- slave 會進入到命令傳播階段、這個階段master將寫命令發送給slave,slave接收并執行增量的命令同步實現主從一致。
畫個圖總結一下實現原理的流程吧:
圖片
?? 怎么判斷slave是第一次進行主從復制呢?
Redis核心結構server的cached_master保存了master節點的信息,只有進行過主從復制才會賦值,否則為空。
復制方式
Redis復制的方式可分為全量復制和增量復制,不過在第一次全量復制之后,master和slave雙方之間就會維護一個 TCP 長連接,后續master可以通過這個連接繼續將新寫操作命令同步給slave。
全量復制
全量復制意思是master當前全部數據進行復制同步到slave。
全量復制可分為三個階段,我們先看下圖有個整體印象,然后再看每個階段都干了啥!
圖片
?? 階段一 建立鏈接、協商同步
這部分流程我們在【實現原理】章節講比較明白了,這個階段建立連接,并告訴master需要進行同步,等確認后就可以為后續的全量復制做準備。
具體來說就是在 slave給master發送 psync 命令,表示要進行數據同步,master會根據這個命令的參數來啟動復制!
?? psync ? -1,命令參數 ‘?’和 ‘-1’是什么意思?
這兩個參數分別表示 master 的唯一表示 runID 和復制進度 offset ,因為是第一次復制,此時是不知道master的runID的,所以設置‘ ?’,而 -1 表示第一次復制。
注:每個 Redis 實例啟動時都會自動生成的一個隨機 ID,這個就是runID
master在收到 psync 命令之后會用 FULLRESYNC 響應命令帶上兩個參數:master 的runID 和的復制進度 offset,這個時候 salve 就可以記下這兩個參數值了。
FULLRESYNC : 意思是完全重新同步,就是會把當前master的所有數據復制同步給salve
???? 階段是二 master同步數據給從slave
master 收到 psync 命令后,會執行bgsave命令, fork 出一個子進程,子進程中將所有的數據按特定編碼存儲到 RDB(Redis Database) 文件中。
RDB生成完成之后就會把文件發送給salve,從庫接收到RDB文件后,先清空當前數據庫數據,然后才會加載RDB文件。
?? salve在加載RDB前清除數據的目的是什么?
salve 在執行replicaof 或 slaveof 命令開始復制前,可能保存了其他數據,清除是為了避免之前數據的影響
?? master在執行bgsave期間新寫的命令并沒有生成到RDB中,數據丟失了嗎?
生成RDB的是fork出的子進程做的,此時主進程還是可以正常處理寫入命令的,此時為了保證主從的數據一致性master 會用專門的 replication buffer 來記錄 RDB 文件生成、加載RDB文件期間收到的所有寫操作。
?????? 階段三 master發送新寫操作命令給slave
master會把階段二期間記錄在 replication buffer 的寫命令,發送給salve,通過這種方式來實現主從的同步一致性。
?? 在什么情況下會進行全量同步呢?
1. slave連接上master第一次復制的時候
2. 從節點發送 psync {runid} {offset} 時,runid 與當前主節點的 runid 不匹配則進行全量復制
3. 從節點所需要同步數據的偏移量 offset 不在復制積壓緩沖區中
命令傳播
master在完成第一次同步后,就會基于長連接進行后續命令傳播,master通過這個連接將寫命令傳播給slave,salve執行得到的寫命令,從而保正主從數據的同步。
圖片
增量復制
我們知道在第一次全量復制后,主從之間使用長連接進行命令傳播,但是如果網絡出現問題,出現閃斷(斷了一會又恢復了)那麻煩了,用戶可能從salve讀到舊數據。
這種情況下Redis 2.8開始會采用增量復制的方式繼續同步,如下圖流程:
圖片
問題的關鍵在于如何知道哪些數據作為增量發送給slave,在分析之前我們先了解幾個概念:
? 復制偏移量 (replication offset)
? 復制積壓緩沖區 (replication backlog)
? 服務器運行ID (runID)
?? 復制偏移量 ( replication offset)
主從節點都維護這一個復制偏移量,它代表著當前節點接受數據的字節數,注意這里表示的是【字節數】
圖片
上圖中master和slave的offset一開始是相等的,可以理解為數據一致,但是master此時增加了6個字節數據,此時需要向salve傳播長度為6字節的數據,從而保持主從數據的一致,offset一致。
? 想要知道主從是否一致,通過對比offset,也能知道
???? 復制積壓緩沖區 ( replication backlog buffer )
復制積壓緩沖區是由master維護的一個固定長度的環形緩沖區、是先進先出(FIFO)隊列,默認大小為 1MB。
圖片
在命令傳播階段,除了發送命令給salve之外,還會寫入到復制積壓緩沖區,此時salve還會做一個重要的事情,發送 REPLCONF ACK 命令給master,傳遞 replication_offset(slave當前的復制偏移量),這個命令有三個作用:
? 檢測主從服務器的網絡狀態
? 輔助實現 min-slaves 選項
? 檢測命令丟失
?????? 服務器運行ID (runID)
不論主從都會有自己的運行ID,在Redis服務器啟動時會自動生成,由40個隨機16進制字符組成,第一次復制master會發送這個ID給到slave,而斷線重連時slave會帶上這個ID發送給master!
了解這些知識后,我們再理一理,在網絡短暫斷開后,salve重新連上master時,salve會通過 psync 命令將自己的復制偏移量 offset 發送給master,而master根據自己的offset 和 slave的offset 之間的差距,然后來決定對salve執行哪種同步操作。
? 判斷出salve要讀取的數據還在 replication_backlog_buffer 里,那么主服務器將采用增量同步的方式;
? 判斷出讀取的數據已經不存在 replication_backlog_buffer 里 (比如被覆蓋掉了),那么主服務器將采用全量同步的方式
?? replication_backlog_buffer 大小只有1M,數據被覆蓋的概率挺大,該如何配置避免呢?
replication_backlog_buffer 最小的大小可以這樣估算
repl_backlog_buffer = second * write_size_per_second
? second 為salve斷線后重新連接上master所需的平均 時間(以秒計算)。
? write_size_per_second 則是master平均每秒產生的寫命令數據量大小
這個配置我們看情況去定,這個參數在配置文件中如下,我們可以去修改它
repl-backlog-size 1mb
主從復制配置
配置方式
進行配置主從復制還是比較簡單的,可以用 兩種方式:
1. 在從服務器中添加配置 slaveof 選項,不過在5.0版本中使用了replicaof 代替了slaveof,雖然 slaveof可以繼續使用,建議使用 replicaof
2. 直接使用 slaveof 命令
# redis.conf文件進行主從配置
# replicaof <masterip> <masterport>
replicaof 192.168.127.20 6379
配置好 redis.conf之后,我們分別啟動主從服務器,可以用戶命令 info replication 查看復制信息
AUTH設置密碼
如果需要在 slave對master的建立連接是進行驗證,可以在master中配置requirepass選項設置密碼
那么需要在從服務器salve中使用該密碼,可以使用命令config set masterauth ,或者在配置文件中設置masterauth
總結
進行主從復制之前需要master和slave進行連接,只有連接成功之后才能進行后續的復制動作。
在主從服務器發送 pysnc 進行第一次同步的時候,采用的是全量復制,而在同步完成之后,主從服務器都會維護著一個長連接,主服務器在接收到新的寫操作命令后,通過這個連接發送給從服務器,從而保持數據的一致性。
如果遇到網絡閃斷情況,此時就進行增量復制,不過需要確定復制積壓緩沖區是否覆蓋等情況才決定是進行全量還是增量復制。