鍍金池/ 教程/ 大數(shù)據(jù)/ 復(fù)制
使用 Redis 實現(xiàn) Twitter(上)
集群(下)
使用 Redis 實現(xiàn) Twitter(下)
使用 Redis 作為 LRU 緩存
高可用(上)
高可用客戶端指引
集群(中)
高可用(下)
持久化
Redis 介紹
集中插入
集群(上)
從入門到精通(上)
從入門到精通(下)
從入門到精通(中)
分片
數(shù)據(jù)類型初探
復(fù)制

復(fù)制

Redis 的復(fù)制 (replication) 是一種使用和配置起來非常簡單的主從(master-slave)復(fù)制,允許 Redis 從服務(wù)器成為主服務(wù)器的精確副本。以下是關(guān)于 Redis 復(fù)制的一些重要方面:

  • Redis 采用異步復(fù)制。從 Redis 2.8 開始,從服務(wù)器會周期性地報告從復(fù)制流中處理的數(shù)據(jù)量。 一個主服務(wù)器可以擁有多個從服務(wù)器。
  • 從服務(wù)器可以接受其他從服務(wù)器的連接。除了連接多個從服務(wù)器到同一個主服務(wù)器,從服務(wù)器也可以連接到其他的從服務(wù)器,形成圖狀結(jié)構(gòu)。
  • Redis 的復(fù)制在主服務(wù)器上是非阻塞的。這意味著,當(dāng)一個或多個從服務(wù)器執(zhí)行初始化同步(initial synchronization)時,主服務(wù)器能繼續(xù)處理請求。
  • Redis 的復(fù)制在從服務(wù)器上也是非阻塞的。當(dāng)從服務(wù)器正在執(zhí)行初始化同步時,假如你在
  • redis.conf 中進行了相應(yīng)配置,也能夠繼續(xù)使用舊版本的數(shù)據(jù)集處理請求。另外,你還可以配置當(dāng)復(fù)制流宕(dowm)掉的時候,從服務(wù)器返回給客戶端一個錯誤。然而,初始化同步結(jié)束后,舊的數(shù)據(jù)集需要被刪除,新的數(shù)據(jù)集需要被載入。在這個簡短的窗口期內(nèi),從服務(wù)器會阻塞到來的連接。
  • 復(fù)制可以用來支持可伸縮性,用多個從服務(wù)器處理只讀查詢(例如,繁重的 SORT 操作可以分配到從服務(wù)器上),也可以僅僅作為數(shù)據(jù)冗余。
  • 可以使用復(fù)制來避免主服務(wù)器將全部數(shù)據(jù)集寫到磁盤的開銷:只需要配置你的主服務(wù)器的 redis.conf 來防止保存(所有的” 保存” 指令),然后連接一個不斷復(fù)制的從服務(wù)器。但是,這種設(shè)置下要確保主服務(wù)器不會自動重啟(閱讀下一節(jié)獲取更多信息)。

主服務(wù)器關(guān)閉持久化時的安全性(Safety of replication)

當(dāng)使用了 Redis 的復(fù)制時,強烈建議在主服務(wù)器上開啟持久化,或者,當(dāng)不可能開啟持久化時,例如由于關(guān)注延遲,實例應(yīng)該被配置為避免自動重啟。

為了更好的理解為什么關(guān)閉了持久化的主服務(wù)器被配置為自動重啟是很危險的,查看下面的失敗模型,數(shù)據(jù)從主服務(wù)器以及其所有從服務(wù)器上被清除:

  • 我們設(shè)置節(jié)點 A 作為主服務(wù)器,關(guān)閉了持久化,節(jié)點 B 和節(jié)點 C 從節(jié)點 A 復(fù)制。
  • A 崩潰了,但是它擁有某個自動重啟系統(tǒng),重啟了這個進程。但是,由于持久化是被關(guān)閉的,這個節(jié)點以空的數(shù)據(jù)集重啟。
  • 節(jié)點 B 和節(jié)點 C 從空的 A 復(fù)制,于是它們完全銷毀了他們的數(shù)據(jù)拷貝。

當(dāng) Redis Sentinel 被用于高可用時,主服務(wù)器關(guān)閉了持久化,并開啟了進程重啟也是很危險的。例如,主務(wù)器非??焖俚闹貑?,以至于 Sentinel 沒有檢測到失敗,于是上面描述的失敗模型就發(fā)生了。

任何時刻數(shù)據(jù)安全都是很重要的,要禁止主服務(wù)器配置為關(guān)閉持久化并自動重啟。

Redis 復(fù)制如何工作(How works)

當(dāng)你建立一個從服務(wù)器,連接時就會發(fā)送一個 SYNC 命令。不管是第一次連接上還是重連接上。

然后主服務(wù)器開始在后臺保存,并且開始緩沖所有新收到的會修改數(shù)據(jù)集的命令。當(dāng)后臺保存完成以后,主服務(wù)器傳輸數(shù)據(jù)庫文件給從服務(wù)器,從服務(wù)器將其保存到磁盤上,然后加載到內(nèi)存中。然后主服務(wù)器開始發(fā)送緩沖的命令給從服務(wù)器。這是通過命令流完成的,和 Redis 的協(xié)議是一樣的格式。

你可以用 telnet 試試。連上一臺正在工作的 Redis 的端口,然后發(fā)送 SYNC 命令。你會看到大量的傳輸,還有主服務(wù)器收到的每條命令被重新發(fā)送給了 telnet 會話。

當(dāng)主從鏈路由于某些原因斷開時,從服務(wù)器可以自動重連。如果主服務(wù)器收到多個并發(fā)的從服務(wù)器的同步請求,只會執(zhí)行一個后臺保存來服務(wù)所有從服務(wù)器。

當(dāng)主服務(wù)器和從服務(wù)器斷開后重連上,總是執(zhí)行一次完整重同步(full resynchronization)。然而,從 Redis 2.8 以后,可以選擇執(zhí)行部分重同步(partial resynchronization)。

部分重同步(partial resynchronization)

從 Redis 2.8 開始,在復(fù)制鏈接斷開后,主服務(wù)器和從服務(wù)器通常可以繼續(xù)復(fù)制過程,而不需要一次完整的重同步。

這是通過在主服務(wù)器上創(chuàng)建一個復(fù)制流的內(nèi)存緩沖區(qū)(in-memory backlog)實現(xiàn)的。主服務(wù)器和所有從服務(wù)器都記錄一個復(fù)制偏移量(offset)和一個主服務(wù)器運行 ID(run id),當(dāng)鏈接斷掉時,從服務(wù)器會重連接,并且請求主服務(wù)器繼續(xù)復(fù)制。假設(shè)主服務(wù)器的運行 ID 還是一樣的,并且指定的偏移量在復(fù)制緩沖區(qū)中可用,復(fù)制會從中斷的點繼續(xù)。如果這兩個條件之一不滿足,將會執(zhí)行完整重同步(2.8 版之前的正常行為)。

新的部分重同步特性使用的是內(nèi)部 PSYNC 命令,老的實現(xiàn)采用的是 SYNC 命令。注意,Redis 2.8 的從服務(wù)器可以檢測主服務(wù)器是否不支持 PSYNC,然后使用 SYNC 代替。

無盤復(fù)制(Diskless replication)

通常,一次完整的重同步需要在磁盤上創(chuàng)建一個 RDB 文件,然后從磁盤重新加載同一個 RDB 來服務(wù)從服務(wù)器。

由于低速的磁盤,這對主服務(wù)器來說是很大壓力的操作。Redis 2.8.18 版本是第一個對無盤復(fù)制提供試驗性支持的版本。在這種設(shè)置下,子進程直接通過線路(wire)發(fā)送 RDB 文件給從服務(wù)器,而不需要使用磁盤作為中間存儲。

配置(Configuration)

配置復(fù)制簡直小菜一碟:只需要添加下面一行到從服務(wù)器配置文件:

slaveof  192.168.1.1  6379  

當(dāng)然,你得把 192.168.1.1 6379 替換成你自己的主服務(wù)器 IP 地址(或主機名)和端口?;蛘撸憧梢哉{(diào)用 SLAVEOF 命令和主服務(wù)器主機,開始與從服務(wù)器的一次同步。

有很多參數(shù)可以用來調(diào)整執(zhí)行部分重同步主服務(wù)器的上的內(nèi)存復(fù)制緩沖區(qū)??梢钥纯?Redis 發(fā)布版本中自帶的樣例文件 redis.conf 以獲取更多的信息。

只讀從服務(wù)器(Read-only slave)

從 Redis 2.6 開始,從服務(wù)器支持默認開啟的只讀模式。這個行為由 redis.conf 文件中的 slave-read-only 選項控制,可以在運行時使用 CONFIG SET 來開啟和關(guān)閉。

只讀從服務(wù)器會拒絕所有寫命令,所以寫入數(shù)據(jù)到從服務(wù)器只會引起錯誤。這并不意味著,這個特性打算暴露從服務(wù)器實例到互聯(lián)網(wǎng),或者到網(wǎng)絡(luò)中不信任的客戶端,因為諸如 DEBUG 和 CONFIG 這樣的管理命令等仍可用。但是,可以通過在 redis.conf 中使用 rename-command 指令來禁止命令,從而改進只讀實例的安全性。

你可能很好奇,為什么需要能夠反轉(zhuǎn)只讀設(shè)置,使得從服務(wù)器實例能夠成為寫操作的目標(biāo)。盡管這些寫入的數(shù)據(jù)會在從服務(wù)器和主服務(wù)器重同步時,或者從服務(wù)器重啟時被丟棄,還是有一些存儲一些短暫的數(shù)據(jù)到可寫的從服務(wù)器的合理場景。例如,客戶端可以存儲一些主服務(wù)器的可達性信息來調(diào)整故障轉(zhuǎn)移(failover)策略。

認證主服務(wù)器(Authenticate to a master)

如果你的主服務(wù)器通過 requirepass 而有一個密碼,很容易配置從服務(wù)器在所有同步操作中使用這個密碼。

要做到這個,在一個運行的實例上,使用 redis-cli 并鍵入:

config  set  masterauth  <password>  

要永久設(shè)置這個,添加這個倒你的配置文件中:

masterauth  <password>  

N 個副本才能寫(Allow writes only with N attached replicas)

從 Redis 2.8 開始,可以設(shè)置 Redis 主服務(wù)器在當(dāng)前至少擁有 N 個從服務(wù)器的連接的情況下,才能接受寫請求。

然而,由于 Redis 使用異步復(fù)制,不能保證從服務(wù)器真正收到了一個給定的寫請求,于是總是有一個數(shù)據(jù)丟失的窗口期。

下面是這個特性是如何運作的:

  • Redis 從服務(wù)器每秒種 ping 主服務(wù)器,上報處理完的復(fù)制流的數(shù)據(jù)量。
  • Redis 主服務(wù)器記錄上一次從每一個從服務(wù)收到 ping 的時間。
  • 用戶可以配置最小從服務(wù)器數(shù)量,每臺從服務(wù)器擁有一個不大于最大秒數(shù)的滯后(lag)。

如果有至少 N 個小于 M 秒滯后的從服務(wù)器,寫請求才會被接受。

你可能會認為這個像 CAP 理論中較寬松版本的”C”,不能保證指定寫的一致性,但是至少數(shù)據(jù)丟失的時間窗口被限制在一個指定的秒數(shù)內(nèi)。

如果條件不滿足,主服務(wù)器會返回一個錯誤,并且不會接受寫請求。

這個特性有兩個配置參數(shù):

min-slaves-to-write  <number of slaves>  
min-slaves-max-lag  <number of seconds>  

請查看隨 Redis 源碼發(fā)布版本自帶的 redis.conf 文件獲取更多信息。