前言 關係資料庫通常會使用一個主伺服器向多個從伺服器發送更新,並使用從伺服器來處理所有的讀請求,Redis採用了同樣方法來實現自己的複製特性。 簡單總結起來就是:在接收到主伺服器發送的數據初始副本之後,客戶端每次主伺服器進行寫命令時,從伺服器都會實時地得到更新。部署好主從伺服器之後,客戶端可以向任意 ...
前言
關係資料庫通常會使用一個主伺服器向多個從伺服器發送更新,並使用從伺服器來處理所有的讀請求,Redis採用了同樣方法來實現自己的複製特性。
簡單總結起來就是:在接收到主伺服器發送的數據初始副本之後,客戶端每次主伺服器進行寫命令時,從伺服器都會實時地得到更新。部署好主從伺服器之後,客戶端可以向任意的從伺服器發送讀請求。
本文主要介紹Redis實現數據同步複製簡單過程、新舊版本之間的對比、以及一些需要註意的細節,主要參考資料《Redis實戰》與《Redis設計與實現》(有需要的同學可以私信或者評論)
一、舊版複製功能
Redis 2.8以前採用的複製都為舊版複製,主要使用SYNC命令同步複製,SYNC存在很大的缺陷嚴重消耗主伺服器的資源以及大量的網路連接資源。Redis 2.8之後採用PSYNC命令替代SYNC,解決完善這些缺陷,但在介紹新版複製功能之前,必須先介紹舊版複製過程,這樣才能更好地形成對比。
1、複製功能的兩種模式
同時複製過程分為同步sync與命令傳播(command propagate),兩個過程配合執行才能實現Redis複製。
1)同步操作:
通過從伺服器發送到SYNC命令給主伺服器-------->主伺服器生成RDB文件併發送給從伺服器,同時發送保存所有寫命令給從伺服器------>從伺服器清空之前數據並執行解釋RDB文件------->保持數據一致(還需要命令傳播過程才能保持一致)
2)命令傳播操作:
主伺服器的資料庫狀態被修改(主伺服器執行寫命令,修改資料庫),導致主從伺服器資料庫不一致時,通過發送讓主從伺服器不一致的命令(主伺服器接收到的新寫命令)給從伺服器並執行,讓主從伺服器的資料庫重新回到一致狀態。
比如初次同步完成後,主從伺服器資料庫中都已經存在k1-k5的鍵,處於數據一致的狀態
之後,主伺服器客戶端發送DEL刪除命令,刪除k3鍵,導致主從伺服器數據不一致
為了讓主從伺服器數據再次回到一致狀態,主伺服器向從伺服器發送DEL命令,緊接著從伺服器接收並執行。即可回到一致狀態
2、配置選項前提
1)主從複製的前提不用多說,就是先正確配置redis主從伺服器,主要通過slaveof ip port選項配置或者SLAVEOF 命令。
2)保證主伺服器的RDB+AOF配置正確,特別是RDB中dbfilename選項與AOF中的dir選項,兩個文件路徑對於Redis是可寫的
3、主從複製過程
文字簡單總結描述:
1)slave會建立和master的連接,然後發送sync命令;
2)master都會啟動一個後臺進程執行BGSAVE命令,將數據快快照保存到文件中,同時master主進程會開始收集新的寫命令並緩存起來;
3)後臺進程完成寫文件後,master發送文件給slave,slave將文件保存到磁碟上,然後載入到記憶體恢複數據庫快照到slave上。
4)緊接著master就會把緩存命令轉發給slave,後續的master收到的寫命令也通過跟slave連接發送給slave;
5)如果master同時接收到多個slave發來的同步連接請求,只會啟動一個進程來寫資料庫鏡像,然後發送給所有slave。
也可以參考以下表,其中步驟1-4可以認為是sync同步操作,而步驟5即為命令傳播模式
註意事項
1)從伺服器在同步時,會清空所有數據,伺服器在與主伺服器進行初連接時,資料庫中的所有數據都將丟失,替換成主伺服器發送的數據。
2)Redis不支持主主複製
3)主從複製不會阻塞master(不會阻塞master處理客戶端請求),相反slave在初次同步數據時會阻塞不能處理客戶端請求。
4)當多個從伺服器嘗試連接同一個主伺服器的時候,就會出現以下兩種情況:
一是:步驟3還未執行,所有從伺服器都會接收到相同的快照文件和相同緩衝區寫命令。
二是:步驟3正在執行或者已經執行完畢,當主伺服器與較早的從伺服器完成以上全部步驟之後,主伺服器會新連接的從伺服器重新依次執行1-5步驟。
在大部分情況下,Redis會儘可能去減少複製所需要的工作,但是從伺服器連接的時機不湊巧的話,只好多做一些外額外工作。
5)多個從伺服器連接主伺服器時候,同步數據可能會占用很大一部分的帶寬,可能會導致其他請求難以到達主伺服器。
4、SYNC命令的缺陷
主要是主從伺服器斷線後重覆制,即處於命令傳播階段的主從伺服器由於網路斷開,從伺服器一直嘗試連接主伺服器連接成功後,繼續複製主伺服器。如下過程在主從伺服器斷開後重新連接期間,主伺服器繼續執行三個SET命令,導致從伺服器連接後發送L SYNC命令,重新進行了“全量”複製過程,RDB文件中包含k1-k10089全部的鍵。
其中可以明顯看出重新連接主伺服器之後,SYNC命令創建包含k1-k10089的RDB文件。而事實上只需要再同步斷線後的k10087-k10089即可。SYNC的“全同步”對於從服務來說是不必要的。
SYNC命令非常消耗資源,原因有三點:
1)主伺服器執行BGSAVE命令生成RDB文件,這個生成過程會大量消耗主伺服器資源(CPU、記憶體和磁碟I/O資源)
2)主伺服器需要將自己生成的RBD發送給從從伺服器,這個發送操作會消耗主從伺服器大量的網路資源(帶寬與流量)
3)接收到RDB文件你的從伺服器需要載入RDB文件,載入期間從伺服器會因為阻塞而導致沒辦法處理命令請求。
二、新版複製功能
為瞭解決舊版本中斷線情況下SYNC低效問題,在Redis 2.8之後使用PSYNC命令代替SYNC命令執行複製同步操作,自然PSYNC具備完整重同步和部分重同步模式
1)完整重同步:跟舊版複製基本是一致的,可以理解為“全量”複製。
2)部分重同步:在命令傳播階段,斷線重覆制只需要發送主伺服器在斷開期間執行的寫命給從伺服器即可,可以理解為“增量”複製。
斷開連接後發送+CONTINUE回覆,表示使用PSYNC部分重同步,只需要同步k10087-10089即可,不需要生成RDB文件
相關流程圖如下: