Redis 主從 Replication 的配置

beanlam發表於2015-04-20

本專欄與Redis相關的文章

Redis Sentinel機制與用法(一)
Redis Sentinel機制與用法(二)
Jedis的JedisSentinelPool原始碼分析
Jedis的Sharded原始碼分析
Redis 主從 Replication 的配置
詳解Redis SORT命令
JedisCommand介面說明

本文參考翻譯自《Redis Replication documentation》

概述

Redis的replication機制允許slave從master那裡通過網路傳輸拷貝到完整的資料備份。具有以下特點:

  • 非同步複製。從2.8版本開始,slave能不時地從master那裡獲取到資料。

  • 允許單個master配置多個slave

  • slave允許其它slave連線到自己。一個slave除了可以連線master外,它還可以連線其它的slave。形成一個圖狀的架構。

  • master在進行replication時是非阻塞的,這意味著在replication期間,master依然能夠處理客戶端的請求。

  • slave在replication期間也是非阻塞的,也可以接受來自客戶端的請求,但是它用的是之前的舊資料。可以通過配置來決定slave是否在進行replication時用舊資料響應客戶端的請求,如果配置為否,那麼slave將會返回一個錯誤訊息給客戶端。不過當新的資料接收完全後,必須將新資料與舊資料替換,即刪除舊資料,在替換資料的這個時間視窗內,slave將會拒絕客戶端的請求和連線。

  • 一般使用replication來可以實現擴充套件性,例如說,可以將多個slave配置為“只讀”,或者是純粹的資料冗餘備份。

  • 能夠通過replication來避免master每次持久化時都將整個資料集持久化到硬碟中。只需把master配置為不進行save操作(把配置檔案中save相關的配置項註釋掉即可),然後連線上一個slave,這個slave則被配置為不時地進行save操作的。不過需要注意的是,在這個用例中,必須確保master不會自動啟動。更多詳情請繼續往下讀。

Master持久化功能關閉時Replication的安全性

當有需要使用到replication機制時,一般都會強烈建議把master的持久化開關開啟。即使為了避免持久化帶來的延遲影響,不把持久化開關開啟,那麼也應該把master配置為不會自動啟動的。

為了更好地理解當一個不進行持久化的master如果允許自動啟動所帶來的危險性。可以看看下面這種失敗情形:

假設我們有一個redis節點A,設定為master,並且關閉持久化功能,另外兩個節點B和C是它的slave,並從A複製資料。

如果A節點崩潰了導致所有的資料都丟失了,它會有重啟系統來重啟程式。但是由於持久化功能被關閉了,所以即使它重啟了,它的資料集是空的。
而B和C依然會通過replication機制從A複製資料,所以B和C會從A那裡複製到一份空的資料集,並用這份空的資料集將自己本身的非空的資料集替換掉。於是就相當於丟失了所有的資料。

即使使用一些HA工具,比如說sentinel來監控master-slaves叢集,也會發生上述的情形,因為master可能崩潰後迅速恢復。速度太快而導致sentinel無法察覺到一個failure的發生。

當資料的安全很重要、持久化開關被關閉並且有replication發生的時候,那麼應該禁止例項的自啟動。

replication工作原理

如果你為master配置了一個slave,不管這個slave是否是第一次連線上Master,它都會傳送一個SYNC命令給master請求複製資料。

master收到SYNC命令後,會在後臺進行資料持久化,持久化期間,master會繼續接收客戶端的請求,它會把這些可能修改資料集的請求快取在記憶體中。當持久化進行完畢以後,master會把這份資料集傳送給slave,slave會把接收到的資料進行持久化,然後再載入到記憶體中。然後,master再將之前快取在記憶體中的命令傳送給slave。

當master與slave之間的連線由於某些原因而斷開時,slave能夠自動重連Master,如果master收到了多個slave併發連線請求,它只會進行一次持久化,而不是一個連線一次,然後再把這一份持久化的資料傳送給多個併發連線的slave。

當master和slave斷開重連後,一般都會對整份資料進行復制。但從redis2.8版本開始,支援部分複製。

資料部分複製

從2.8版本開始,slave與master能夠在網路連線斷開重連後只進行部分資料複製。

master會在其記憶體中建立一個複製流的等待佇列,master和它所有的slave都維護了複製的資料下標和master的程式id,因此,當網路連線斷開後,slave會請求master繼續進行未完成的複製,從所記錄的資料下標開始。如果程式id變化了,或者資料下標不可用,那麼將會進行一次全部資料的複製。

支援部分資料複製的命令是PSYNC

不需硬碟參與的Replication

一般情況下,一次複製需要將記憶體的資料寫到硬碟中,再將資料從硬碟讀進記憶體,再傳送給slave。

對於速度比較慢的硬碟,這個操作會給master帶來效能上的損失。Redis2.8版本開始,實驗性地加上了無硬碟複製的功能。這個功能能將資料從記憶體中直接傳送到slave,而不用經過硬碟的儲存。

不過這個功能目前處於實驗階段,還未正式釋出。

相關配置

與replication相關的配置比較簡單,只需要把下面一行加到slave的配置檔案中:

slaveof 192.168.1.1 6379

你只需要把ip地址和埠號改一下。當然,你也可以通過客戶端傳送SLAVEOF命令給slave。

部分資料複製有一些可調的配置引數,請參考redis.conf檔案。

無硬碟複製功能可以通過repl-diskless-sync來配置,另外一個配置項repl-diskless-sync-delay用來配置當收到第一個請求時,等待多個slave一起來請求之間的間隔時間。

只讀的slave

從redis2.6版本開始,slave支援只讀模式,而且是預設的。可以通過配置項slave-read-only來進行配置,並且支援客戶端使用CONFIG SET命令來動態修改配置。

只讀的slave會拒絕所有的寫請求,只讀的slave並不是為了防範不可信的客戶端,畢竟一些管理命令例如DEBUGCONFIG在只讀模式下還是可以使用的。如果確實要確保安全性,那麼可以在配置檔案中將一些命令重新命名。

也許你會感到很奇怪,為什麼能夠將一個只讀模式的slave恢復為可寫的呢,儘管可寫,但是隻要slave一同步master的資料,就會丟失那些寫在slave的資料。不過還是有一些合法的應用場景需要儲存瞬時資料會用到這個特性。不過,之後可能會考慮廢除掉這個特性。

Setting a slave to authenticate to a master

如果master通過requirepass配置項設定了密碼,slave每次同步操作都需要驗證密碼,可以通過在slave的配置檔案中新增以下配置項:

masterauth <password>

也可以通過客戶端在執行時傳送以下命令:

config set masterauth <password>

至少N個slave才允許向master寫資料

從redis2.8版本開始,master可以被配置為,只有當master當前有至少N個slave連線著的時候才接受寫資料的請求。

然而,由於redis是非同步複製的,所以它並不能保證slave會受到一個寫請求,所以總有一個資料丟失的時間視窗存在。

這個機制的工作原理如下所示:

  • slave每秒傳送ping心跳給master,詢問當前複製了多少資料。

  • master會記錄下它上次收到某個slave的ping心跳是什麼時候。

  • 使用者可以配置一個時間,來指定ping心跳的傳送不應超過的一個超時時間

如果master有至少N個slave,並且ping心跳的超時不超過M秒,那麼它就會接收寫請求。

也許你會認為這情形好似CAP理論中弱化版的C(consistency),因為寫請求並不能保證資料的一致性,但這樣做,至少資料丟失被限制在了限定的時間內。即M秒。

如果N和M的條件都無法達到,那麼master會回覆一個錯誤資訊。寫請求也不會被處理。

有兩個配置項用來配置上文中提到的N和M:

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

如果需要了解更多,請查閱redis.conf配置檔案。

相關文章