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.21
和192.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
代替了slaveof
(https://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第一次複製的時候;二是若是當主從斷線,從新鏈接複製的時候有多是完整重同步,這個在後面說
下面是完整重同步的步驟
bgsave
命令生成RDB文件並使用緩衝區記錄此後執行的全部寫命令basave
執行完後,向全部從服務器發送快照文件,並在發送期間繼續記錄被執行的寫命令部分重同步是用於處理斷線後重複製的狀況,先介紹幾個用於部分重同步的部分
runid
(replication ID),主服務器運行id,Redis實例在啓動時,隨機生成一個長度40的惟一字符串來標識當前節點offset
,複製偏移量。主服務器和從服務器各自維護一個複製偏移量,記錄傳輸的字節數。當主節點向從節點發送N個字節數據時,主節點的offset增長N,從節點收到主節點傳來的N個字節數據時,從節點的offset增長Nreplication 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 中被刪除:
當 Redis Sentinel 被用於高可用而且 master 關閉持久化,這時若是容許自動重啓進程也是很危險的。例如, master 能夠重啓的足夠快以至於 Sentinel 沒有探測到故障,所以上述的故障模式也會發生。
任什麼時候候數據安全性都是很重要的,因此若是 master 使用複製功能的同時未配置持久化,那麼自動重啓進程這項應該被禁用
參考:《Redis設計與實現》、redis replication