NoSQL之Redis---主從複製

[不忘初心]

前文,我們簡要翻譯了Redis集羣的內容,在搭建集羣的過程中,我們經常使用的功能就是主從複製,冗餘備份。本文我們就來介紹這部分的內容。好了,馬上開始我們的正文部分吧。

---------------------------------------------------------------------------------------------------------------------------------------

       Redis的複製功能是非常簡單易用的,配置爲主從複製功能之後允許Redis的slave服務器複製出與master完全一致的服務器。以下是一些關於Redis複製功能的幾個重要方面:

  • Redis使用異步複製。從2.8版本開始 ,slave服務器將以1s的頻率想master服務器報告複製流的處理進度。
  • 一個master服務器可以擁有多個slaves服務器。
  • slave服務器也能鏈接到其他slave服務器。除了鏈接到master服務器之外,slave服務器也能夠和多個slave一起構成圖狀結構。
  • Redis的複製功能不會阻塞master服務器。話句話說,master服務器能夠在向一個或者多個slave進行初始化複製時也能夠持續的接受服務請求。
  • 複製功能也不會阻塞slave服務器。當slave在進行初始化複製時,slave也能夠處理老版本的數據服務,前提是你在Redis.conf文件中進行了相應的配置。另外,你也可以配置slave在與master斷開時,讓其返回錯誤。然而,在異步的初始化之後,舊數據必須被刪除,並且新數據必須被加載到slave中。此時,slave將會被阻塞直到複製完成。
  • 複製功能也可以被用於提升擴展性,使得,多個slave提供只讀服務(如,繁重的SORT命令操作可以交給複述節點進行)。或者將複製功能單純的用於數據冗餘(datar redundancy)。
  • 使用複製功能來使得master節點避免執行持久化操作。只需要關閉主服務器的持久化功能,然後由從服務器去執行持久化操作即可。特別的:在這種配置之下,請確保master服務器不會自動重啓。

在master節點關閉持久化功能時,複製的安全性

       當在設置中開啓Redis複製功能時,強烈建議的做法是在master節點中開啓持久化功能,或者絕對不可能發生的是:因爲延遲問題,將Redis實例被配置爲避免自動重啓。
       爲了更好的理解爲什麼將關閉持久化功能的master節點配置爲自動重啓是非常危險的,我們看看下面在數據從master節點與其對應的所有slave節點移除時發生的失敗類型:
  • 假設A節點是master節點,B,C節點是其對應的副本。
  • A發生崩潰時,(配置爲自動重啓),重新啓動了進程。然而因爲持久化功能是關閉的,所以重啓之後,該節點內的數據爲空。
  • 節點B,C將會從A進行復制,這時A中的數據集是空的,因此,這時,B,C將會徹底刪除他們之前備份的數據。
       爲了高可用性,引入了Redis的哨兵(sentinel),關閉了master節點上的持久化,並且兩者都配置爲自動重啓,這種做法也是非常危險的。舉個例子:master節點可能非常快的就完成了重啓,以至於sentienl都沒有感知到失敗的發生,接下來就會發生和上面例子一樣的結果。
       在任何時間,數據的安全都是非常重要的,因此,在使用複製功能時,master節點如果沒有持久化功能,自動重啓的功能是必須被禁止的。

複製功能的運行原理

       當你建立一個slave節點時,slave節點都會將master節點發送一個SYNC命令。無論是首次鏈接還是重新連接。
       當maste節點接受到SYNC命令時,master節點將會開始後臺保存功能,並且開始緩存所有接收到的將會修改數據集的新命令。當後臺保存任務完成時,master節點將數據文件傳送給slave節點,slave節點將會把數據文件保存到本地磁盤,並且加載到內存中。緊接着,master節點將會把之前還存下的所有命令也傳輸給slave節點。這項功能將會按照指令流來完成並且是一個與Redis協議本身相同的格式。
       你可以通過telnet命令來親自驗證這個同步過程。首先,連接上一個正在處理命令請求的Redis服務器,然後發送SYNC命令,之後,你將看到大量的數據轉移以及master節點上接收到的每一條命令將會被再次運行在telnet的會話中。
       當master節點與slave節點斷開時,slave節點能夠自動的重寫鏈接到master節點上。如果master節點接收到多個同時進行復制請求時,master節點也只需要執行一次SYNC命令,就可以處理到所有的slave服務器的同步請求。
       當master節點與slave節點斷線重連之後,一個完整的SYNC命令將會被執行。在2.8版本之後,slave節點將會根據主服務器的情況來選擇是完整同步還是部分同步。

部分重新同步

       從2.8版本開始,master節點和slave節點通常情況下能夠在斷線重連的情況下進行斷點續傳的複製功能,而不需要進行完整複製過程。
這個特性需要master服務器在內存中創建一個複製流緩衝區。並且,master和slave需要都記錄下一個複製偏移量和一個master節點ID,當網絡連接斷開時,slave節點將會重新連接,並且向master服務器請求繼續執行原來的複製進程。
如果master節點ID與slave節點記錄的ID保持一致,並且slave記錄的複製偏移量指定的數據在master節點中仍然存在,那麼複製流將會從斷點繼續傳輸。
       如果上面條件哪怕只有一條不滿足的話,那就開始一個完整的複製過程。
       Redis2.8版本的部分重新同步的特性會用到一個新增的PSYNC命令,而之前的版本只有SYNC命令。不過,只要服務器版本高於2.8,其將會自動的選擇使用PSYNC還是SYNC。

無磁盤複製

       通常情況下,一個完成的再同步複製請求需要創建一個RDB文件,並且把這個RDB文件從磁盤中加載到slave節點中。
       如果是在一個非常慢的磁盤上進行,這對於master節點是一個壓力非常大的操作。從2.8.18版本開始,實驗性的支持了無磁盤的複製。在該配置下,子進程能夠直接通過網絡連接發送RDB給slave,而不磁盤作爲中間存儲。

配置

配置一個slave服務器是非常簡單,只需要在配置文件中增加一下的這一張就行:
slaveof 127.0.0.1 6379
當然,你需要將代碼中的IP與端口,替換成你自己的master服務器的IP與端口。另外的一種方法就是:使用SLAVEOF命令,輸入master服務器的IP和端口,然後,master節點就會開始同步。
127.0.0.1:6379> SLAVEOF 127.0.0.1 6379
OK
這裏也有一些專門爲master節點執行部分重新同步的過程中調整內存中的複製存儲的參數。
無磁盤複製功能可以使用repl-diskless-sync參數開啓。爲了在第一個slave節點到達之後等待更多slave節點到達,延遲傳輸動作,可以被repl-diskless-sync-delay參數控制。更多內容請在redis.conf文件的分佈式配置中查看。

只讀slave服務器

       從2.6版本開始,slave節點只讀模式,並且也是默認的。這個模式也是可以被redis.conf文件中的slave-read-only控制的,也可以通過CONFIG SET命令來設置。
       只讀模式下的slave節點將會拒絕一切寫命令,因此,也不會出現因爲錯誤操作在slave中寫入數據的可能。但是,這不是說,我們可以將一個slave節點暴露給互聯網或者不信任的網絡客戶端,因爲,管理類的命令如DEBUG,CONFIG命令仍然是可以使用的。但是,我們可以禁用redis.conf文件中的rename-command命令,來提升只讀slave節點的安全性。
       你可能會好奇,爲什麼可能出現重新覆蓋只讀配置和slave節點會成爲寫操作的目標。儘管這些寫操作在slave節點與master節點再同步或者slave重新啓動時將會被丟棄,但是,在可寫的slave節點中,這裏仍有對所存儲的一些臨時數據進行合法的使用。然而,在將來,這可能將會被移除。

slave節點的授權配置

如果master節點通過requirepass設置了訪問密碼,在配置slave節點中也需要配置相應的password,這樣才能進行所有的同步操作。
對於一個正在運行的slave可以使用下面的命令:
config set masterauth <password>
要永久的設置這個密碼,那麼可以將它加入到配置文件中:
masterauth <password>

master服務器只有在只要N個slave服務器的條件下,才執行寫操作

       從 Redis 2.8 開始, 爲了保證數據的安全性, 可以通過配置, 讓主服務器只在有至少 N 個當前已連接從服務器的情況下, 才執行寫命令。
不過, 因爲 Redis 使用異步複製, 所以主服務器發送的寫數據並不一定會被從服務器接收到, 因此, 數據丟失的可能性仍然是存在的。
以下是這個特性的運作原理:
  • slave服務器每秒ping一次master服務器,並且報告複製流的處理情況。
  • master服務器將會記錄各個slave服務器最後一次發送ping的時間。
  • 用戶可以配置網絡延遲的最大時間min-slaves-max-lag(M),以及執行寫操作所需的最少slave服務器數量min-slaves-to-write(N).
如果至少存在N個slave服務器,並且延遲都小於M秒,那麼寫操作將被接受。
       你可以將這個特性看作是CAP理論中的C的寬鬆條件,儘管不能保證寫操作的持久性,但起碼丟失數據的窗口會被嚴格限制在指定的描述中。
如果這些條件沒有被滿足,master節點將會返回一個錯誤,並且寫操作將會被拒絕。
以下是這個特性的兩個選項和所需參數:
  • min-slaves-to-write <number of slaves>
  • min-slaves-max-lag <number of seconds>
詳細的信息可以參考Redis源碼中附帶的redis.conf示例文件

對帶有超期時間key的複製策略

       Redis的超時配置允許key擁有生效的有限時間。該特性以來於Redis實例能夠計算有效時間,然而,Redis的slave節點準確的複製這些帶有超時時間的key,即使當這些key被lua腳本改變了。
       爲了實現這樣的特性,Redis不能依靠master與slave之間同步時間的能力,因爲,這個同步問題是無法解決的,並且將會導致競爭條件的產生和數據集的不一致問題,因此,Redis使用了下面三種策略實現讓帶有過期時間的key能夠被使用:
  1. slave不會將key過期,而是等待master節點將其過期。當master節點將一個key的時間過期之後,使用DEL命令,通知所有slave節點刪除該key。
  2. 然而,由於是master驅動過期時間的, 所以在某些時刻,slave仍然有可能保留了一些實際上已經過期的key,原因是master節點沒有及時的提供DEL命令。爲了處理slave節點使用其正確的時間來報告一個不存在的key,只向一些不違反數據一致性的讀操作提供,(因爲來自master節點的新命令將會到達)。通過這種方式,slave節點避免了返回一個實際上已經過期的,但未刪除的key。
  3. 在Lua腳本執行中,將不會執行key的超時設置。在Lua腳本執行過程中,概念上說master上的時間是停止的,因此,在一個給定的腳本執行期的完整時間內一個給定的key將會只能是存在或者不存在。這阻止了key在執行腳本過程中發生超時現象,並且在爲了發送相同的腳本到slave中也是十分必要的,其保證了對數據集產生相同的影響。
正如預期的那樣,一旦發生故障轉移,slave變爲master,其將開始獨立的判斷key的過期時間,而不是向之前的master詢問。
-------------------------------------------------------------------------------------------------------------------------------------
至此,NoSQL之Redis---主從複製

參考資料:
官方文檔:http://redis.io/topics/replication
其他資料:http://doc.redisfans.com/topic/cluster-tutorial.html



發佈了119 篇原創文章 · 獲贊 182 · 訪問量 59萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章