Redis 復制
Redis
通過持久化技術(RDB/AOF
)保證即使緩存服務器重啟數據也基本不會丟失。當我們部署一臺單節點Redis
服務器時,假若磁盤損壞,服務將會直接不可用,并且數據丟失,這對應用層面來講是絕對不能夠容忍的。為了避免單節點故障,通常會部署多個副本在不同的服務器來保證Redis
的高可用性。Redis
提供了Replication
功能,當一臺Master服務器數據更新后,自動同步到Slave上。
Master-Slave機制下,Master負責讀寫,Slave一般負責讀。默認配置Slave是只讀的,如果在Slave上直接進行寫操作會報錯誤。
(error) READONLY You can't write against a read only slave.
如果希望Slave可以直接進行寫操作,設置slave-read-only yes
即可。當然建議設置為no
。
實踐
創建redis.conf
,端口7991為Master
,端口7992為Slave
。
mkdir -p cluster-7991/{config,log,data,pid}
mkdir -p cluster-7992/{config,log,data,pid}
分別為兩個Redis
實例配置文件,將配置文件配置在config
目錄下,名為redis.conf
。
port 7991
bind 0.0.0.0
daemonize yes
protected-mode yes
appendonly yes
dir /Users/wujunbin/Work/redis-cluster/cluster-7991/
#repl-diskless-sync yes
port 7992
bind 0.0.0.0
SLAVEOF 127.0.0.1 7991
daemonize yes
protected-mode yes
appendonly yes
dir /Users/wujunbin/Work/redis-cluster/cluster-7992/
#repl-diskless-sync yes
注意在Slave的的配置文件中加入slaveof
用于指定當前實力是誰的slave
。
啟動redis-server
redis-server cluster-7991/config/redis.conf &
redis-server cluster-7992/config/redis.conf &
redis-cli
進入查看
:~/Work/redis-cluster$redis-cli -p 7991
127.0.0.1:7991> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=7992,state=online,offset=70,lag=0
master_replid:ee41a261a4aa0c89ffeca4776e23a5598f896c7f
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:70
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:70
connected_salves:1
表明了連接了一個slave節點。接下來插入數據。
127.0.0.1:7991> set hello world
OK
登錄Slave節點查看
:~/Work/redis-cluster$redis-cli -p 7992
127.0.0.1:7992> get hello
"world"
127.0.0.1:7992>
成功的取出了數據,說明主從配置成功。
同步原理
首先引用一張圖
主要分為三個階段
-
Slave
發送sync
命令或者psync
請求初始化。 -
Master
判斷是否增量初始化。如果不是,生成dump.rdb
文件,并將該文件傳輸給Slave
。如果是,則將積壓隊列中命令偏移量之后的命令發送給Slave
。 - 初始化之后
Master
對Slave
進行增量更新,一旦有更新傳輸寫命令給Slave
節點。
Sync和Psync
試想一下Slave
的某個流程:啟動-Master數據同步-停止-啟動。最后一步的啟動,因為Slave
在停止前已經接受了Master
的數據同步,所以本地是有數據的。所以是不需要將Master
的dump.rdb
全部傳輸給Slave
。只需要將Slave
停止之后的所有寫命令在Slave
再次啟動后傳輸給Slave
,即可完成數據同步。Redis
為了完成這一點在Master
維護了一個命令積壓隊列(默認大小1M,有效時常1個小時)。每一次Master
的寫入命令會放入這個隊列,并同步寫命令和寫命令在隊列中的偏移量給Slave
。Slave
除了執行寫命令也會記錄這個命令的偏移量。當Slave再次啟動時發送PSYNC + Master Run ID + 命令偏移量
到Master
。Master
收到psync
指令,首先判斷run id
是不是自己,如果是再根據命令偏移量從隊列中查找。如果找到直接同步偏移量之后的命令給Slave
。如果偏移量不在隊列中那么無法滿足增量復制,Master
就會生成dump.rdb
進行同步。
無硬盤復制
當Redis
使用一主多從的集群架構時,每次和Slave全量同步,Redis
都會執行一次快照,同時對硬盤進行讀寫,導致性能下降。Redis
提供了
repl-diskless-sync yes
參數。指定后,在復制初始化時就會直接將生成到dump.rdb
數據的內容通過網絡傳輸給Slave
,而不需要先存儲在磁盤上。
Master崩潰,Slave切換為Master
當Master
崩潰時,在Slave
中使用SLAVEOF NO ONE
命令將從數據庫提升為主數據庫繼續服務。然后重新啟動崩潰的Reids
實例,該實例就變成了Slave
然后從Master
再次同步數據。