Redis:06-集羣:複製

Redis提供了複製(replication)功能,可以實現當一臺數據庫中的數據更新後,自動將更新的數據同步到其他數據庫上。

配置

在複製的概念中,數據庫分爲兩類,一類是主數據庫(master),另一類是從數據庫(slave)。主數據庫可以進行讀寫操作,當寫操作導致數據變化是會自動將數據同步給從數據庫。而從數據庫一般是隻讀的,並接受主數據庫同步過來的數據。一個主數據庫可以擁有多個從數據庫,而一個從數據庫只能擁有一個主數據庫。

在Redis中使用複製功能非常容易,只需要在從數據庫的配置文件中加入“slaveof 主數據庫地址 主數據庫端口” 即可,主數據庫無需進行任何配置。

使用 info replication 可以查看 主從信息,如下:

//to do

除了在配置文件設置slaveof 參數,還可以命令行參數或運行時使用 slaveof 命令修改。

redis 啓動時命令行參數

redis-server -port 6380 --slaveof 127.0.0.1 6379

使用 slaveof 命令

slaveof 127.0.0.1 6379

原理

瞭解Redis複製的原理對日後運維有很大的幫助,包括如何規劃節點,如何處理節點故障等。

當一個從數據庫啓動後,會向主數據庫發送sync命令。同時主數據庫接收到sync命令後會開始在後臺保存快照(即rdb持久化的過程),並將保存快照期間接收到的命令緩存起來。當快照完成後,Redis會將快照文件和所有緩存的命令發送給從數據庫。從數據庫收到後,會載入快照文件並執行收到的緩存的命令。以上過程稱爲複製初始化,複製初始化結束後,主數據庫每當收到寫命令就會將命令同步給從數據庫,從而保證主數據庫數據一致。

當主從數據庫之間的連接斷開重連後,Redis2.6以及之前的版本會重新進行復制初始化(即主數據庫重新保存快照並傳送給從數據庫),即使從數據庫可以僅有幾條命令沒有收到,主數據庫也必須要將數據庫裏的所有數據重新傳送給從數據庫。這使得主從數據庫斷線重連後的數據恢復過程效率很低下。Redis2.8版的一個重要改進就是斷線重連能夠支持有條件的增量數據傳輸,當從數據庫重新連接上主數據庫後,主數據庫只需要將斷線期間執行的命令傳送給從數據庫,從而大大提高Redis複製的實用性。

讀寫分離

通過複製可以實現讀寫分離,以提高服務器的負載能力。在一些場景中(如電商網站),讀的頻率大於寫,當單機的Redis無法應付大量的讀請求時(尤其是較耗資源的請求,如sort命令等)可以通過複製功能建立多個從數據庫節點,主數據庫只進行寫操作,而從數據庫負責讀操作。

從數據庫持久化

另一個相對耗時的操作時持久化,爲了提高性能,可以通過複製功能建立一個額(或若干個)從數據庫,並在從數據庫中啓用持久,同時在主數據庫禁用持久化。當從數據庫崩潰重啓後主數據庫會自動將數據同步過來,所以無需擔心數據丟失。

當主數據庫崩潰時,情況就稍顯複雜了。手工通過從數據庫數據恢復主數據庫數據時,需要嚴格按照以下兩步進行。

  1. 在從數據庫中使用slaveof no one 命令將從數據庫提升成主數據庫繼續服務。
  2. 啓動之前崩潰的主數據庫,然後使用slaveof 命令將其設置成新的主數據庫的從數據庫,即可將數據同步回來。

注意: 當開啓複製且主數據庫關閉持久化功能時,一定不要使用supervisor以及類似的進程管理工具另主數據庫崩潰後自動重啓。同樣當主數據庫所在的服務器因故關閉時,也要避免直接重新啓動,這是因爲當主數據庫重新啓動後,因爲沒有開啓持久化功能,所以數據庫中所有數據都被清空,這時從數據庫依然會從主數據庫中接收數據,使得所有從數據庫也被清空,導致從數據庫的持久化失去意義。

無硬盤複製

前面介紹的Redis複製的工作原理時介紹複製是基於RDB方式的持久化實現的,即主數據庫端在後臺保存RDB快照,從數據庫端則接收並載入快照文件。這樣的實現優點是可以顯著地簡化邏輯,複用已有的代碼,但是缺點也很明顯。

  1. 當主數據庫禁用RDB快照時(即刪除了所有的配置文件中的save語句),如果執行了複製初始化操作,Redis依然會生成RDB快照,所以下次啓動後主數據庫會以該快照恢復數據。因爲複製發生的時間不能確定,這使得恢復的數據可能是任何時間點的。
  2. 因爲複製初始化時需要在硬盤中創建RDB快照文件,所以如果硬盤性能很慢(如網絡硬盤)時這一過程會對性能產生影響。

因此從2.8.18版本開始,Redis引入了無硬盤複製選項,開啓該選項時,Redis在於從數據庫進行復制初始化時將不會講快照內容存儲到硬盤上,而是直接通過網絡發送給從數據庫,避免了硬盤的性能瓶頸。

在配置文件中使用如下配置來開啓(默認是不開啓的):

repl-diskless-sync yes

增量複製

前面複製的原理中提到當主從數據庫連接斷開後,從數據庫會發送sync命令來重新進行一次完整複製操作。這樣即使斷開期間數據庫的變化很小(甚至沒有),也需要將數據庫中的所有數據重新快照並傳送一次。這種實現方式顯然不太理想。Redis2.8版本最重要的更新之一就是實現了主從斷線重連的情況下的增量複製。

增量複製是基於如下3點實現的:

  1. 從數據庫會存儲主數據庫的運行ID(run id)。每個Redis運行實例均會擁有一個唯一的運行ID,每當實例重啓後,就會自動生成一個新的運行ID。
  2. 在複製同步階段,主數據庫每將一個命令傳遞給從數據庫時,都會同時把該命令存放到一個積壓隊列(backlog)中,並記錄下當前積壓隊列中存放的命令的偏移量。
  3. 同時,從數據庫接收到主數據庫傳來的命令時,會記錄下該命令的偏移量。

這3點是實現增量複製的基礎。當主從連接準備就緒後,從數據庫會發送一條sync命令來告訴主數據庫可以開始吧所有數據同步過來了。而2.8版本之後,不再發送sync命令,取而代之的是發送 psync 命令,格式爲 “psync 主數據庫的運行 ID 斷開前最新的命令偏移量”。主數據庫收到 psync命令後,會執行以下判斷來決定此次重連是否可以執行增量複製。

  1. 首先主數據庫會判斷從數據庫從數據庫傳來的運行ID是否和自己運行ID相同。這一步驟的意義子啊與確保從數據庫之前確實是和自己同步的,以免從數據庫拿到錯誤的數據。
  2. 然後判斷從數據庫最後同步成功的命令偏移量是否在積壓對了中給,如果在則可以執行增量複製,並將積壓隊列中相應的命令發送給從數據庫。

如果此次重連不滿足增量複製的條件,主數據庫會進行一次全部同步。

2.8版本的主數據庫也可以正常地和舊版本的從數據庫同步(通過接收sync命令),同樣2.8版本的從數據庫也可以與舊版本的主數據庫同步(通過發送sync命令)。唯一需要設置的就是積壓隊列的大小了。

積壓隊列本質上是一個固定長度的循環隊列,默認情況下積壓隊列的大小爲1MB,可以通過配置文件的 repl-backlog-size 選項來調整。與積壓隊列相關的另一個配置選項是 repl-backlog-ttl 即當所有從數據庫與主數據庫斷開連接後,經過多久時間可以釋放積壓隊列的內存空間,默認時間是1小說。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章