一、簡介
Redis的replication機制允許slave從master那里通過網絡傳輸拷貝到完整的數據備份。具有以下特點:
-
異步復制
-
可以配置一主多從
-
可以配置從服務器可以級聯從服務器,既 M->S->S
-
M replication時是非阻塞的(在replication期間,M依然能夠處理客戶端的請求)
-
S replication期間也是非阻塞的(也可以接受來自客戶端的請求,但是它用的是之前的舊數據)可以通過配置來決定S是否在進行replication時用舊數據響應客戶端的請求,如果配置為否,那么slave將會返回一個錯誤消息給客戶端。不過當新的數據接收完全后,必須將新數據與舊數據替換,即刪除舊數據,在替換數據的這個時間窗口內,slave將會拒絕客戶端的請求和連接
-
能夠通過replication來避免master每次持久化時都將整個數據集持久化到硬盤中。只需把master配置為不進行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發生的時候,應該禁止實例的自啟動
三、M/S 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,而不用經過硬盤的存儲。不過這個功能目前處於實驗階段,還未正式發布
四、配置M/S
slaveof <masterip> <masterport> slave實例需要配置該項,指向master的(ip, port) masterauth <master-password> 如果master實例啟用了密碼保護,則該配置項需填master的啟動密碼;若master未啟用密碼,該配置項需要注釋掉 slave-serve-stale-data 指定slave與master連接中斷時的動作。默認為yes,表明slave會繼續應答來自client的請求,但這些數據可能已經過期(因為連接中斷導致無法從master同步) 若配置為no,則slave除正常應答"INFO"和"SLAVEOF"命令外,其余來自客戶端的請求命令均會得到"SYNC with master in progress"的應答, 直到該slave與master的連接重建成功或該slave被提升為master。 slave-read-only 指定slave是否只讀,默認為yes。若配置為no,這表示slave是可寫的,但寫的內容在主從同步完成后會被刪掉 repl-ping-slave-period Redis部署為Replication模式后,slave會以預定周期(默認10s)發PING包給master,該配置可以更改這個默認周期 repl-timeout 有2種情況的超時均由該配置指定:1) Bulk transfer I/O timeout; 2) master data or ping response timeout 需要特別注意的是:若修改默認值,則用戶輸入的值必須大於repl-ping-slave-period的配置值,否則在主從鏈路延時較高時,會頻繁timeout repl-disable-tcp-nodelay 指定向slave同步數據時,是否禁用socket的NO_DELAY選項。 若配置為yes,則禁用NO_DELAY,則TCP協議棧會合並小包統一發送,這樣可以減少主從節點間的包數量並節省帶寬,但會增加數據同步到slave的時間 若配置為no,表明啟用NO_DELAY,則TCP協議棧不會延遲小包的發送時機,這樣數據同步的延時會減少,但需要更大的帶寬 通常情況下,應該配置為no以降低同步延時,但在主從節點間網絡負載已經很高的情況下,可以配置為yes 備注:socket的NO_DELAY選項涉及到TCP協議棧的擁塞控制算法—Nagle's Algorithm slave-priority 指定slave的優先級。在不只1個slave存在的部署環境下,當master宕機時,Redis Sentinel會將priority值最小的slave提升為master 需要注意的是,若該配置項為0,則對應的slave永遠不會被Redis Sentinel自動提升為master
replication相關的配置比較簡單,只需要把下面一行加到slave的配置文件中
slaveof 192.168.1.1 6379
你也可以通過客戶端發送SLAVEOF命令給slave。無硬盤復制功能可以通過repl-diskless-sync來配置,另外一個配置項repl-diskless-sync-delay用來配置當收到第一個請求時,等待多個slave一起來請求之間的間隔時間
1、同時啟動兩個Redis服務器,可以考慮在同一台機器上啟動兩個Redis服務器,分別監聽不同的端口,如6379和6380
2、配置文件為6379.conf 6380.conf
3、啟動並配置
./src/redis-server 6380.conf ./src/redis-server 6379.conf
4、測試
[root@localhost redis]# ./src/redis-cli -p 6379 127.0.0.1:6379> flushdb OK 127.0.0.1:6379> set aa 1 OK 127.0.0.1:6379> set bb 2 OK 127.0.0.1:6379> set cc 3 OK 127.0.0.1:6379> exit [root@localhost redis]# ./src/redis-cli -p 6380 127.0.0.1:6380> keys * 1) "bb" 2) "aa" 3) "cc" 127.0.0.1:6380> get aa "1" 127.0.0.1:6380> get bb "2"
五、only read slave
從redis2.6版本開始,slave支持只讀模式,而且是默認的。可以通過配置項slave-read-only來進行配置,並且支持客戶端使用CONFIG SET命令來動態修改配置
只讀的slave會拒絕所有的寫請求,只讀的slave並不是為了防范不可信的客戶端,畢竟一些管理命令例如DEBUG和CONFIG在只讀模式下還是可以使用的。如果確實要確保安全性,那么可以在配置文件中將一些命令重新命名。也許你會感到很奇怪,為什么能夠將一個只讀模式的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>
參考文章
https://support.pivotal.io/hc/en-us/articles/205309278-How-to-setup-Redis-Master-and-Salve-replication
