Redis復制(Replication)
概述
Redis 支持簡單且易用的主從復制(master-slave replication)功能, 該功能可以讓從服務器(slave server)成為主服務器(master server)的精確復制品。
以下是關于 Redis 復制功能的幾個重要方面:
-
Redis 使用異步復制。 從 Redis 2.8 開始, 從服務器會以每秒一次的頻率向主服務器報告復制流(replication stream)的處理進度。
-
一個主服務器可以有多個從服務器。
-
不僅主服務器可以有從服務器, 從服務器也可以有自己的從服務器, 多個從服務器之間可以構成一個圖狀結構。
-
復制功能不會阻塞主服務器: 即使有一個或多個從服務器正在進行初次同步, 主服務器也可以繼續處理命令請求。
-
復制功能也不會阻塞從服務器: 只要在 redis.conf 文件中進行了相應的設置, 即使從服務器正在進行初次同步, 服務器也可以使用舊版本的數據集來處理命令查詢。
不過, 在從服務器刪除舊版本數據集并載入新版本數據集的那段時間內, 連接請求會被阻塞。
你還可以配置從服務器, 讓它在與主服務器之間的連接斷開時, 向客戶端發送一個錯誤。
-
復制功能可以單純地用于數據冗余(data redundancy), 也可以通過讓多個從服務器處理只讀命令請求來提升擴展性(scalability): 比如說, 繁重的 SORT 命令可以交給附屬節點去運行。
-
可以通過復制功能來讓主服務器免于執行持久化操作: 只要關閉主服務器的持久化功能, 然后由從服務器去執行持久化操作即可。
配置
配置一個從服務器非常簡單, 只要在配置文件中增加以下的這一行就可以了:
slaveof 192.168.1.1 6379
當然, 你需要將代碼中的 192.168.1.1 和 6379 替換成你的主服務器的 IP 和端口號。
另外一種方法是調用 SLAVEOF 命令, 輸入主服務器的 IP 和端口, 然后同步就會開始:
127.0.0.1:6379> SLAVEOF 192.168.1.1 10086 OK
如果主服務器通過 requirepass 選項設置了密碼, 那么為了讓從服務器的同步操作可以順利進行, 我們也必須為從服務器進行相應的身份驗證設置。
對于一個正在運行的服務器, 可以使用客戶端輸入以下命令:
config set masterauth <password>
要永久地設置這個密碼, 那么可以將它加入到配置文件中:
masterauth <password>
關閉主服務器持久化時,復制功能的數據安全
當配置Redis復制功能時,強烈建議打開主服務器的持久化功能。 否則的話,由于延遲等問題,部署的服務應該要避免自動拉起。
為了幫助理解主服務器關閉持久化時自動拉起的危險性,參考一下以下會導致主從服務器數據全部丟失的例子:
1. 假設節點A為主服務器,并且關閉了持久化。 并且節點B和節點C從節點A復制數據
2. 節點A崩潰,然后由自動拉起服務重啟了節點A. 由于節點A的持久化被關閉了,所以重啟之后沒有任何數據
3. 節點B和節點C將從節點A復制數據,但是A的數據是空的, 于是就把自身保存的數據副本刪除。
在關閉主服務器上的持久化,并同時開啟自動拉起進程的情況下,即便使用Sentinel來實現Redis的高可用性,也是非常危險的。 因為主服務器可能拉起得非常快,以至于Sentinel在配置的心跳時間間隔內沒有檢測到主服務器已被重啟,然后還是會執行上面的數據丟失的流程。
無論何時,數據安全都是極其重要的,所以應該禁止主服務器關閉持久化的同時自動拉起。
復制功能的運作原理
無論是初次連接還是重新連接, 當建立一個從服務器時, 從服務器都將向主服務器發送一個 SYNC 命令。
接到 SYNC 命令的主服務器將開始執行 BGSAVE , 并在保存操作執行期間, 將所有新執行的寫入命令都保存到一個緩沖區里面。
當 BGSAVE 執行完畢后, 主服務器將執行保存操作所得的 .rdb 文件發送給從服務器, 從服務器接收這個 .rdb 文件, 并將文件中的數據載入到內存中。
之后主服務器會以 Redis 命令協議的格式, 將寫命令緩沖區中積累的所有內容都發送給從服務器。
你可以通過 telnet 命令來親自驗證這個同步過程: 首先連上一個正在處理命令請求的 Redis 服務器, 然后向它發送 SYNC 命令, 過一陣子, 你將看到 telnet 會話(session)接收到服務器發來的大段數據(.rdb 文件), 之后還會看到, 所有在服務器執行過的寫命令, 都會重新發送到 telnet 會話來。
即使有多個從服務器同時向主服務器發送 SYNC , 主服務器也只需執行一次 BGSAVE 命令, 就可以處理所有這些從服務器的同步請求。
從服務器可以在主從服務器之間的連接斷開時進行自動重連, 在 Redis 2.8 版本之前, 斷線之后重連的從服務器總要執行一次完整重同步(full resynchronization)操作, 但是從 Redis 2.8 版本開始, 從服務器可以根據主服務器的情況來選擇執行完整重同步還是部分重同步(partial resynchronization)。
只讀從服務器
從 Redis 2.6 開始, 從服務器支持只讀模式, 并且該模式為從服務器的默認模式。
只讀模式由 redis.conf 文件中的 slave-read-only 選項控制, 也可以通過 CONFIG SET 命令來開啟或關閉這個模式。
只讀從服務器會拒絕執行任何寫命令, 所以不會出現因為操作失誤而將數據不小心寫入到了從服務器的情況。
即使從服務器是只讀的, DEBUG 和 CONFIG 等管理式命令仍然是可以使用的, 所以我們還是不應該將服務器暴露給互聯網或者任何不可信網絡。 不過, 使用 redis.conf 中的命令改名選項, 我們可以通過禁止執行某些命令來提升只讀從服務器的安全性。
你可能會感到好奇, 既然從服務器上的寫數據會被重同步數據覆蓋, 也可能在從服務器重啟時丟失, 那么為什么要讓一個從服務器變得可寫呢?
原因是, 一些不重要的臨時數據, 仍然是可以保存在從服務器上面的。 比如說, 客戶端可以在從服務器上保存主服務器的可達性(reachability)信息, 從而實現故障轉移(failover)策略。
主服務器只在有至少 N 個從服務器的情況下,才執行寫操作
從 Redis 2.8 開始, 為了保證數據的安全性, 可以通過配置, 讓主服務器只在有至少 N 個當前已連接從服務器的情況下, 才執行寫命令。
不過, 因為 Redis 使用異步復制, 所以主服務器發送的寫數據并不一定會被從服務器接收到, 因此, 數據丟失的可能性仍然是存在的。
以下是這個特性的運作原理:
-
從服務器以每秒一次的頻率 PING 主服務器一次, 并報告復制流的處理情況。
-
主服務器會記錄各個從服務器最后一次向它發送 PING 的時間。
-
用戶可以通過配置, 指定網絡延遲的最大值 min-slaves-max-lag , 以及執行寫操作所需的至少從服務器數量 min-slaves-to-write 。
如果至少有 min-slaves-to-write 個從服務器, 并且這些服務器的延遲值都少于 min-slaves-max-lag 秒, 那么主服務器就會執行客戶端請求的寫操作。
你可以將這個特性看作 CAP 理論中的 C 的條件放寬版本: 盡管不能保證寫操作的持久性, 但起碼丟失數據的窗口會被嚴格限制在指定的秒數中。
另一方面, 如果條件達不到 min-slaves-to-write 和 min-slaves-max-lag 所指定的條件, 那么寫操作就不會被執行, 主服務器會向請求執行寫操作的客戶端返回一個錯誤。
以下是這個特性的兩個選項和它們所需的參數:
-
min-slaves-to-write <number of slaves>
-
min-slaves-max-lag <number of seconds>
詳細的信息可以參考 Redis 源碼中附帶的 redis.conf 示例文件。