Redis主從複製的配置和實現原理

Redis的持久化功能在必定程度上保證了數據的安全性,即使是服務器宕機的狀況下,也能夠保證數據的丟失很是少。一般,爲了不服務的單點故障,會把數據複製到多個副本放在不一樣的服務器上,且這些擁有數據副本的服務器能夠用於處理客戶端的讀請求,擴展總體的性能html

下面會介紹Redis的主從複製配置和實現原理,後續還會有Redis的高可用方案:哨兵機制(Sentinel)、分區集羣(Cluster)git

什麼是主從複製

咱們能夠經過slaveof <host> <port>命令,或者經過配置slaveof選項,來使當前的服務器(slave)複製指定服務器(master)的內容,被複制的服務器稱爲主服務器(master),對主服務器進行復制操做的爲從服務器(slave)github

主服務器master能夠進行讀寫操做,當主服務器的數據發生變化,master會發出命令流來保持對salve的更新,而從服務器slave一般是隻讀的(能夠經過slave-read-only指定),在主從複製模式下,即使master宕機了,slave是不能變爲主服務器進行寫操做的redis

一個master能夠有多個slave,即一主多從;而slave也能夠接受其餘slave的鏈接,造成「主從鏈」層疊狀結構(cascading-like structure),自 Redis 4.0 起,全部的sub-slave也會從master收到徹底同樣的複製流。以下圖數據庫

主從複製的好處:緩存

  • 數據冗餘,實現數據的熱備份
  • 故障恢復,避免單點故障帶來的服務不可用
  • 讀寫分離,負載均衡。主節點負載讀寫,從節點負責讀,提升服務器併發量
  • 高可用基礎,是哨兵機制和集羣實現的基礎

主從複製的配置

使用和配置主從複製是比較簡單的,在從服務器slave的配置文件中設置slaveof選項,或者直接使用slaveof <masterip> <masterport>命令安全

這裏我使用3臺虛擬機來搭建一下,主服務器的ip爲192.168.249.20,兩個從服務器的ip分別爲192.168.249.21192.168.249.21,端口號都爲6379,具體的配置以下bash

主服務器並不須要額外多配置什麼,這裏咱們先把三臺服務器的都須要改的地方列一下服務器

# 設置爲後臺運行
daemonize yes
# 保存pid的文件,若是是在一臺機器搭建主從,須要區分一下
pidfile /var/run/redis_6379.pid
# 綁定的主機地址,這裏註釋掉,開放ip鏈接
#bind 127.0.0.1
# 指定日誌文件
logfile "6379.log"

在從服務器中添加配置slaveof <masterport> <masterport>選項,在5.0版本中使用了replicaof代替了slaveofhttps://github.com/antirez/redis/issues/5335),slaveof還能夠繼續使用,不過建議使用replicaof。若是是使用命令行來複制的話,重啓以後會無效網絡

# replicaof <masterip> <masterport>
replicaof 192.168.249.20 6379

配置好redis.conf以後,咱們分別啓動3臺服務器,能夠用戶命令info replication查看複製信息

192.168.249.20:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.249.22,port=6379,state=online,offset=700,lag=0
slave1:ip=192.168.249.21,port=6379,state=online,offset=700,lag=0
master_replid:b80a4720c0001efb62940f5ad6abaf9cdaf7a813
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:700
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:700

192.168.249.21:6379> info replication
# Replication
role:slave
master_host:192.168.249.20
master_port:6379
master_link_status:up
master_last_io_seconds_ago:3
master_sync_in_progress:0
slave_repl_offset:854
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:b80a4720c0001efb62940f5ad6abaf9cdaf7a813
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:854
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:57
repl_backlog_histlen:798

192.168.249.22:6379> info replication
# Replication
role:slave
master_host:192.168.249.20
master_port:6379
master_link_status:up
master_last_io_seconds_ago:6
master_sync_in_progress:0
slave_repl_offset:854
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:b80a4720c0001efb62940f5ad6abaf9cdaf7a813
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:854
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:854

接下來咱們能夠在主服務器中寫入數據,而後能夠在其餘的從服務器中讀取數據

192.168.249.20:6379> set test 'Hello World'
OK

192.168.249.21:6379> get test
"Hello World"

192.168.249.22:6379> get test
"Hello World"

而後咱們試着在從服務器中寫入數據,會提示不能在只讀的從服務器中寫入數據

192.168.249.21:6379> set test2 hello
(error) READONLY You can't write against a read only replica.

若是咱們須要slave對master的複製進行驗證,能夠在master中配置requirepass <password>選項設置密碼

那麼須要在從服務器中使用該密碼,可使用命令config set masterauth <password>,或者在配置文件中設置masterauth <password>

主從複製的實現原理

主從複製的配置仍是比較簡單的,下面來了解下主從複製的實現原理

Redis的主從複製過程大致上分3個階段:創建鏈接數據同步命令傳播

創建鏈接

這個階段主要是從服務器發出slaveof命令以後,與主服務器如何創建鏈接,爲數據同步作準備的過程。

1)在slaveof命令執行以後,從服務器根據設置的master的ip地址和端口,建立連向主服務器的socket套接字鏈接,鏈接成功後,從服務器會爲這個套接字關聯一個專門的處理器,用於處理後續的複製工做

2)創建鏈接以後,從服務器會向主服務器發送ping命令,確認主服務器是否可用,以及當前是否可用接受處理命令。若是收到主服務器的pong回覆說明是可用的,不然有多是網絡超時或主服務器阻塞,從服務器會斷開鏈接發起重連

3)身份驗證。若是主服務器設置了requirepass選項,那麼從服務器必須配置masterauth選項,且保證密碼一致才能經過驗證

4)身份驗證完成以後,從服務器會發送本身的監聽端口,主服務器會保存下來

192.168.249.20:6379> info replication
...
slave0:ip=192.168.249.22,port=6379,state=online,offset=700,lag=0
slave1:ip=192.168.249.21,port=6379,state=online,offset=700,lag=0
...

數據同步

在主從服務器創建鏈接確認各自身份以後,就開始數據同步,從服務器向主服務器發送PSYNC命令,執行同步操做,並把本身的數據庫狀態更新至主服務器的數據庫狀態

Redis的主從同步分爲:完整重同步(full resynchronization)部分重同步(partial resynchronization)

完整重同步

有兩種狀況下是完整重同步,一是slave鏈接上master第一次複製的時候;二是若是當主從斷線,從新鏈接複製的時候有多是完整重同步,這個在後面說

下面是完整重同步的步驟

  • 從服務器鏈接主服務器,發送SYNC命令
  • 主服務器接收到SYNC命名後,開始執行bgsave命令生成RDB文件並使用緩衝區記錄此後執行的全部寫命令
  • 主服務器basave執行完後,向全部從服務器發送快照文件,並在發送期間繼續記錄被執行的寫命令
  • 從服務器收到快照文件後丟棄全部舊數據,載入收到的快照
  • 主服務器快照發送完畢後開始向從服務器發送緩衝區中的寫命令
  • 從服務器完成對快照的載入,開始接收命令請求,並執行來自主服務器緩衝區的寫命令

部分重同步

部分重同步是用於處理斷線後重複製的狀況,先介紹幾個用於部分重同步的部分

  • runid(replication ID),主服務器運行id,Redis實例在啓動時,隨機生成一個長度40的惟一字符串來標識當前節點
  • offset,複製偏移量。主服務器和從服務器各自維護一個複製偏移量,記錄傳輸的字節數。當主節點向從節點發送N個字節數據時,主節點的offset增長N,從節點收到主節點傳來的N個字節數據時,從節點的offset增長N
  • replication backlog buffer,複製積壓緩衝區。是一個固定長度的FIFO隊列,大小由配置參數repl-backlog-size指定,默認大小1MB。須要注意的是該緩衝區由master維護而且有且只有一個,全部slave共享此緩衝區,其做用在於備份最近主庫發送給從庫的數據

當slave鏈接到master,會執行PSYNC <runid> <offset>發送記錄舊的master的runid(replication ID)和偏移量offset,這樣master可以只發送slave所缺的增量部分。可是若是master的複製積壓緩存區沒有足夠的命令記錄,或者slave傳的runid(replication ID)不對,就會進行完整重同步,即slave會得到一個完整的數據集副本

PSYNC命令執行完整重同步和部分重同步的流程圖

命令傳播

當完成數據同步以後,主從服務器的數據暫時達到一致狀態,當主服務器執行了客戶端的寫命令以後,主從的數據便再也不一致。爲了可以使主從服務器的數據保持一致性,主服務器會對從服務器執行命令傳播操做,即每執行一個寫命令就會向從服務器發送一樣的寫命令

在命令傳播階段,從服務器會默認以每秒一次的頻率向主服務器發送心跳檢測

REPLCONF ACK <replication_offset>

其中replication_offset是當前從服務器的複製偏移量,該命令的做用有三個

  • 檢測主從服務器的網絡鏈接狀態
  • 輔助實現min-slaves選項
  • 檢測命令丟失

關閉持久化時,複製的安全性

關於關閉持久化時,複製的安全性問題,我這裏摘入官網的一段描述http://www.redis.cn/topics/replication.html

在使用Redis複製功能時的設置中,強烈建議在master和在slave中啓用持久化。當不可能啓用時,例如因爲很是慢的磁盤性能而致使的延遲問題,應該配置實例來避免重置後自動重啓

爲了更好地理解爲何關閉了持久化並配置了自動重啓的 master 是危險的,檢查如下故障模式,這些故障模式中數據會從 master 和全部 slave 中被刪除:

  1. 咱們設置節點 A 爲 master 並關閉它的持久化設置,節點 B 和 C 從 節點 A 複製數據。
  2. 節點 A 崩潰,可是他有一些自動重啓的系統能夠重啓進程。可是因爲持久化被關閉了,節點重啓後其數據集合爲空。
  3. 節點 B 和 節點 C 會從節點 A 複製數據,可是節點 A 的數據集是空的,所以複製的結果是它們會銷燬自身以前的數據副本。

當 Redis Sentinel 被用於高可用而且 master 關閉持久化,這時若是容許自動重啓進程也是很危險的。例如, master 能夠重啓的足夠快以至於 Sentinel 沒有探測到故障,所以上述的故障模式也會發生。

任什麼時候候數據安全性都是很重要的,因此若是 master 使用複製功能的同時未配置持久化,那麼自動重啓進程這項應該被禁用

參考:《Redis設計與實現》、redis replication

相關文章
相關標籤/搜索