Redis如何高效可靠地实现主从复制?终于有人讲明白了
導讀:本文內容主要包括Redis主從復制功能的概述、作用和方案實施。
?
作者:李樂 來源:大數據DT(ID:bigdatadt)?
?
Redis支持主從復制功能,用戶可以通過執行slaveof命令或者在配置文件中設置slaveof選項來開啟復制功能。例如,現在有兩臺服務器—127.0.0.1:6379和127.0.0.1:7000,向服務器127.0.0.1:6379發送下面命令:
?
127.0.0.1:6379>slaveof?127.0.0.1?7000 OK?
此時服務器127.0.0.1:6379會成為服務器127.0.0.1:7000的從服務器(slaver),服務器127.0.0.1:7000會成為服務器127.0.0.1:6379的主服務器(master);通過復制功能,從服務器127.0.0.1:6379的數據可以和主服務器127.0.0.1:7000的數據保持同步。
?
為什么需要主從復制功能呢?
?
簡單來說,主從復制功能主要有以下兩點作用。
?
讀寫分離,單臺服務器能支撐的QPS是有上限的,我們可以部署一臺主服務器、多臺從服務器,主服務器只處理寫請求,從服務器通過復制功能同步主服務器數據,只處理讀請求,以此提升Redis服務能力;另外我們還可以通過復制功能來讓主服務器免于執行持久化操作:只要關閉主服務器的持久化功能,然后由從服務器去執行持久化操作即可。
數據容災,任何服務器都有宕機的可能,我們同樣可以通過主從復制功能提升Redis服務的可靠性;由于從服務器與主服務器數據保持同步,一旦主服務器宕機,可以立即將請求切換到從服務器,從而避免Redis服務中斷。
?
對于本例來說slaveof命令的主要流程如下。
?
從服務器127.0.0.1:6379向主服務器127.0.0.1:7000發送sync命令,請求同步數據。
主服務器127.0.0.1:7000接收到sync命令請求,開始執行bgsave命令持久化數據到RDB文件,并且在持久化數據期間會將所有新執行的寫入命令都保存到一個緩沖區。
當持久化數據執行完畢后,主服務器127.0.0.1:7000將該RDB文件發送給從服務器127.0.0.1:6379,從服務器接收該RDB文件,并將文件中的數據加載到內存。
主服務器127.0.0.1:7000將緩沖區中的命令請求發送給從服務器127.0.0.1:6379。
每當主服務器127.0.0.1:7000接收到寫命令請求時,都會將該命令請求按照Redis協議格式發送給從服務器127.0.0.1:6379,從服務器接收并處理主服務器發送過來的命令請求。
?
上述流程已經可以完成主從復制基本功能了,Redis 2.8以前就是這樣實現的,但是注意到步驟2中存在持久化操作(bgsave),而這是一個非常耗費資源的操作。
?
?
舉一個簡單的例子。
?
主服務器和從服務器之間是通過TCP長連接交互數據的,假設某個時刻主從服務器之間的網絡連接發生故障且時間比較短,在此期間主服務器只執行了很少的寫命令請求。
?
待主從服務器之間的網絡連接恢復后,從服務器會重新連接到主服務器,并發送sync命令請求同步數據。這時候主服務器還需要執行持久化操作嗎?顯然是可以避免的,只要主服務器能夠緩存連接故障期間執行的寫命令即可。
?
Redis 2.8提出了新的主從復制解決方案。從服務器會記錄已經從主服務器接收到的數據量(復制偏移量);而主服務器會維護一個復制緩沖區,記錄自己已執行且待發送給從服務器的命令請求,同時還需要記錄復制緩沖區第一個字節的復制偏移量。從服務器請求同步主服務器的命令也改為了psync。
?
當從服務器連接到主服務器時,會向主服務器發送psync命令請求同步數據,同時告訴主服務器自己已經接收到的復制偏移量,主服務器判斷該復制偏移量是否還包含在復制緩沖區;如果包含,則不需要執行持久化操作,直接向從服務器發送復制緩沖區中命令請求即可,這稱為部分重同步;如果不包含,則需要執行持久化操作,同時將所有新執行的寫命令緩存在復制緩沖區中,并重置復制緩沖區第一個字節的復制偏移量,這稱為完整重同步。
?
詳情可參照Redis源碼,方法masterTryPartialResynchronization用于判斷是否可以執行部分重同步;方法replicationFeedSlaves用于向所有從服務器廣播命令。
?
void?replicationFeedSlaves(list?*slaves,?int?dictid,?robj?**argv,?int?argc){if?(server.repl_backlog)?{//將當前命令請求添加到復制緩沖區}while((ln?=?listNext(&li)))?{//向所有從服務器同步命令請求} }?
另外,從服務器也會通過命令“REPLCONF ACK < reploff >”定時向主服務器匯報自己的復制偏移量;據此,主服務器一來可以檢測從服務器是否有效,二來可以重新廣播丟失的命令請求。
?
另外需要注意的是,每臺Redis服務器都有一個運行ID,從服務器每次發送psync請求同步數據時,會攜帶自己需要同步主服務器的運行ID。
?
主服務器接收到psync命令時,需要判斷命令參數運行ID與自己的運行ID是否相等,只有相等才有可能執行部分重同步。而當從服務器首次請求主服務器同步數據時,從服務器顯然是不知道主服務器的運行ID,此時運行ID以“?”填充,同時復制偏移量初始化為-1。
?
從上面的分析我們可以得到psync命令格式為“psync <MASTER_RUN_ID> <OFFSET>”,主從復制初始化流程如圖1所示。
?
從圖1可以看到,當主服務器判斷可以執行部分重同步時向從服務器返回“+CON-TINUE”;需要執行完整重同步時向從服務器返回“+FULLRESYNC RUN_ID OFFSET”,其中RUN_ID為主服務器自己的運行ID,OFFSET為復制偏移量。
▲圖1 主從復制初始化流程圖
?
可以看到執行部分重同步的要求還是比較嚴格的:
?
RUN_ID必須相等;
復制偏移量必須包含在復制緩沖區中。
?
然而在生產環境中,經常會出現以下兩種情況:
?
-
從服務器重啟(復制信息丟失);
-
主服務器故障導致主從切換(從多個從服務器重新選舉出一臺機器作為主服務器,主服務器運行ID發生改變)。
?
這時顯然是無法執行部分重同步的,而這兩種情況又很常見,因此Redis 4.0針對主從復制又提出了兩點優化,提出了psync2協議。
?
-
方案1:持久化主從復制信息
?
Redis服務器關閉時,將主從復制信息(復制的主服務器RUN_ID與復制偏移量)作為輔助字段存儲在RDB文件中;Redis服務器啟動加載RDB文件時,恢復主從復制信息,重新同步主服務器時攜帶。持久化主從復制信息代碼如下:
?
if?(rdbSaveAuxFieldStrStr(rdb,"repl-id",server.replid)==?-1)?return?-1;if?(rdbSaveAuxFieldStrInt(rdb,"repl-offset",server.master_repl_offset)==?-1)?return?-1;?
-
方案2:存儲上一個主服務器復制信息
?
當主服務器發生故障,自己成為新的主服務器時,使用變量server.replid2和server.second_replid_offset存儲之前主服務器的運行ID與復制偏移量:
?
void?shiftReplicationId(void)?{memcpy(server.replid2,server.replid,sizeof(server.replid));server.second_replid_offset?=?server.master_repl_offset+1;changeReplicationId(); }?
另外判斷是否能執行部分重同步的條件也改變為:
?
if?(strcasecmp(master_replid,?server.replid)?&&(strcasecmp(master_replid,?server.replid2)?||psync_offset?>?server.second_replid_offset)) {goto?need_full_resync; }?
假設m為主服務器(運行ID為M_ID),A、B和C為三個從服務器;某一時刻主服務器m發生故障,從服務器A升級為主服務器(同時會記錄replid2=M_ID),從服務器B和C重新向主服務器A發送“psync M_ID psync_offset”請求;顯然根據上面條件,只要psync_offset滿足條件,就可以執行部分重同步。
?
關于作者:李樂,好未來PHP工程師,西安電子科技大學碩士,樂于鉆研技術與源碼研究,對Redis和Nginx有較深理解。合著書籍《Redis 5設計與源碼分析》。?
本文摘編自《Redis 5設計與源碼分析》,經出版方授權發布。?
延伸閱讀《Redis 5設計與源碼分析》 點擊上圖了解及購買 轉載請聯系微信:DoctorData?
推薦語:好未來、滴滴、百度等公司專家聯合撰寫,掌握Redis 5設計與命令實現,透徹掌握分布式緩存。深入理解Redis 5設計精髓。本書系統講解Redis 5設計、數據結構、底層命令實現,以及持久化、主從復制、集群的實現。?
?
有話要說??
Q:?關于Redis主從復制,你還有哪些疑問? 歡迎留言與大家分享?
猜你想看??
-
?
-
?
-
?
-
?
?
更多精彩??
在公眾號對話框輸入以下關鍵詞 查看更多優質內容!?
PPT?|?報告?|?讀書?|?書單?|?干貨? 大數據?|?揭秘?|?Python?|?可視化 AI?|?人工智能?|?5G?|?中臺 機器學習?|?深度學習?|?神經網絡 合伙人?|?1024?|?段子?|?數學?
據統計,99%的大咖都完成了這個神操作 ??
?
覺得不錯,請把這篇文章分享給你的朋友 轉載 / 投稿請聯系:baiyu@hzbook.com 更多精彩,請在后臺點擊“歷史文章”查看點擊閱讀原文,了解更多
總結
以上是生活随笔為你收集整理的Redis如何高效可靠地实现主从复制?终于有人讲明白了的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 什么是YARN?跟HBase和Spark
- 下一篇: 2.14情人节,程序员该如何绝地反击?