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檔案
相關流程圖如下:
三、複製的實現
Redis不管是舊版還是新版,複製的實現都可以分為七個步驟,流程圖如下:
1、設定主服務的地址與埠
當客戶端向從伺服器傳送一下命令時或者在配置檔案中配置slaveof選項
127.0.0.1:12345> SLAVEOF 127.0.0.1 6379
從伺服器將向傳送SLAVEOF命令的客戶端返回OK,表示複製指令已經被接收,而實際上覆制工作是在OK返回之後進行。
2、建立套接字連線
從伺服器根據設定的套接字建立連向主伺服器的套接字連線
主伺服器接收從伺服器的套接字連線之後,為該套接字建立響應的客戶端狀態,並將此時的從伺服器看做是主伺服器的客戶端,也就是該從伺服器同時具備伺服器與客戶端兩個身份。
3、傳送PING命令
從伺服器成為主伺服器的客戶端之後,做的第一件事就是向主伺服器傳送PING命令。PING命令主要有兩種作用:
1) 雖然建立了套接字連線,但是還未使用過,通過傳送PING命令檢查套接字的讀寫狀態是否正常
2) 通過傳送PING命令檢查主伺服器能否正常處理命令請求
從伺服器在傳送PING命令之後將遇到以下三種情況的其中一種:
1) 主伺服器向從伺服器返回一個回覆,但是從伺服器卻不能在規定的會時間(timeout)內讀取命令回覆的內容,則表示當前主從伺服器之間的網路狀態連線不佳,不能基礎執行復制工作的後續步驟,這時從伺服器會斷開套接字連線重新建立。
2) 主伺服器向從伺服器返回一個錯誤,那麼表示主伺服器暫時沒有辦法處理從伺服器的命令請求,不能繼續執行復制工作的後續步驟,這時從伺服器會斷開套接字連線重新建立。
3) 如果從伺服器讀取到“PONG”回覆,那麼表示主從伺服器之間網路連線正常,並且主伺服器可以處理從伺服器傳送的命令請求。
4、身份驗證
從伺服器接收到主伺服器返回的“PONG”回覆,接下來就需要考慮身份驗證的事。
如果從伺服器設定了masterauth選項,那麼進行身份驗證
如果從伺服器沒有設定masterauth選項,那麼不進行身份驗證
從伺服器在身份驗證的時候可能遇到三種情況
1) 主服務沒有設定requirepass選項,並且從伺服器也沒有設定masterquth選項,那麼主伺服器繼續執行從伺服器命令,完成複製工作
2) 如果從伺服器通過AUTH命令傳送的密碼與主伺服器中requirepass密碼相同,那麼主伺服器將繼續執行從伺服器傳送的命令,複製工作繼續,與此相反,密碼不一致,則會返回invalid password錯誤
3) 如果從伺服器沒有設定masterauth選項,而主伺服器設定了requirepass選項,那麼主伺服器將返回一個NOAUTH錯誤。反之沒有設設定masterauth選項,而設定了requirepass選項,那麼會返回no password is set錯誤。
5、傳送埠資訊
在身份驗證步驟之後,從伺服器將執行命令REPLCONF listening-port <port>,向主伺服器傳送從伺服器的監聽埠號。
6、同步
就是上述所指的同步操作, 從伺服器向主伺服器傳送PSYNC命令,執行同步操作,值得注意的是只有從伺服器是主伺服器的客戶端,但是執行同步操作之後,主伺服器也會成為從伺服器的客戶端。
7、命令傳播
主從伺服器就會進入命令傳播階段,主伺服器只要將自己執行的寫命令傳送給從伺服器,而從伺服器只要一直執行並接收主伺服器發來的寫命令(上述已經介紹過,這裡不過多介紹)