Redis主從復(fù)制
一.主從復(fù)制介紹
1.Redis復(fù)制功能介紹
1)Redis 使用異步復(fù)制铅歼。從 Redis2.8開始卖漫,從服務(wù)器會以每秒一次的頻率向主服務(wù)器報告復(fù)制流(replication stream)的處理進(jìn)度以舒。
2)一個主服務(wù)器可以有多個從服務(wù)器淫半。
3)不僅主服務(wù)器可以有從服務(wù)器鸣个,從服務(wù)器也可以有自己的從服務(wù)器辑畦,多個從服務(wù)器之間可以構(gòu)成一個圖狀結(jié)構(gòu)吗蚌。
4)復(fù)制功能不會阻塞主服務(wù)器:即使有一個或多個從服務(wù)器正在進(jìn)行初次同步, 主服務(wù)器也可以繼續(xù)處理命令請求纯出。
5)復(fù)制功能也不會阻塞從服務(wù)器:只要在 redis.conf 文件中進(jìn)行了相應(yīng)的設(shè)置蚯妇, 即使從服務(wù)器正在進(jìn)行初次同步, 服務(wù)器也可以使用舊版本的數(shù)據(jù)集來處理命令查詢暂筝。
6)在從服務(wù)器刪除舊版本數(shù)據(jù)集并載入新版本數(shù)據(jù)集的那段時間內(nèi)箩言,連接請求會被阻塞。
7)還可以配置從服務(wù)器焕襟,讓它在與主服務(wù)器之間的連接斷開時陨收,向客戶端發(fā)送一個錯誤。
8)復(fù)制功能可以單純地用于數(shù)據(jù)冗余(data redundancy)胧洒,也可以通過讓多個從服務(wù)器處理只讀命令請求來提升擴(kuò)展性(scalability): 比如說畏吓,繁重的SORT命令可以交給附屬節(jié)點(diǎn)去運(yùn)行。
9)可以通過復(fù)制功能來讓主服務(wù)器免于執(zhí)行持久化操作:只要關(guān)閉主服務(wù)器的持久化功能卫漫,然后由從服務(wù)器去執(zhí)行持久化操作即可菲饼。
二.架構(gòu)圖
三.關(guān)閉主服務(wù)器持久化時,復(fù)制功能的數(shù)據(jù)安全問題
1.當(dāng)配置Redis復(fù)制功能時列赎,強(qiáng)烈建議打開主服務(wù)器的持久化功能宏悦。 否則的話,由于延遲等問題包吝,部署的服務(wù)應(yīng)該要避免自動拉起饼煞。
2.為了幫助理解主服務(wù)器關(guān)閉持久化時自動拉起的危險性,參考一下以下會導(dǎo)致主從服務(wù)器數(shù)據(jù)全部丟失的例子:
1)假設(shè)節(jié)點(diǎn)A為主服務(wù)器诗越,并且關(guān)閉了持久化砖瞧。并且節(jié)點(diǎn)B和節(jié)點(diǎn)C從節(jié)點(diǎn)A復(fù)制數(shù)據(jù)
2)節(jié)點(diǎn)A崩潰,然后由自動拉起服務(wù)重啟了節(jié)點(diǎn)A. 由于節(jié)點(diǎn)A的持久化被關(guān)閉了嚷狞,所以重啟之后沒有任何數(shù)據(jù)
3)節(jié)點(diǎn)B和節(jié)點(diǎn)C將從節(jié)點(diǎn)A復(fù)制數(shù)據(jù)块促,但是A的數(shù)據(jù)是空的,于是就把自身保存的數(shù)據(jù)副本刪除床未。
結(jié)論:
1)在關(guān)閉主服務(wù)器上的持久化竭翠,并同時開啟自動拉起進(jìn)程的情況下,即便使用Sentinel來實現(xiàn)Redis的高可用性薇搁,也是非常危險的斋扰。因為主服務(wù)器可能拉起得非常快,以至于Sentinel在配置的心跳時間間隔內(nèi)沒有檢測到主服務(wù)器已被重啟传货,然后還是會執(zhí)行上面的數(shù)據(jù)丟失的流程屎鳍。
2)無論何時,數(shù)據(jù)安全都是極其重要的损离,所以應(yīng)該禁止主服務(wù)器關(guān)閉持久化的同時自動拉起哥艇。
四.主從復(fù)制原理
主從復(fù)制流程:
1.從節(jié)點(diǎn)發(fā)送同步請求到主節(jié)點(diǎn)
2.主節(jié)點(diǎn)接收到從節(jié)點(diǎn)的請求之后,做了如下操作
立即執(zhí)行bgsave將當(dāng)前內(nèi)存里的數(shù)據(jù)持久化到磁盤上
持久化完成之后,將rdb文件發(fā)送給從節(jié)點(diǎn)
3.從節(jié)點(diǎn)從主節(jié)點(diǎn)接收到rdb文件之后,做了如下操作
清空自己的數(shù)據(jù)
載入從主節(jié)點(diǎn)接收的rdb文件到自己的內(nèi)存里
4.后面的操作就是和主節(jié)點(diǎn)實時的了
五.復(fù)制的一致性
1)在讀寫分離環(huán)境下,客戶端向主服務(wù)器發(fā)送寫命令 SET k10086 v10086僻澎,主服務(wù)器在執(zhí)行這個寫命令之后貌踏,向客戶端返回回復(fù),并將這個寫命令傳播給從服務(wù)器窟勃。
2)接到回復(fù)的客戶端繼續(xù)向從服務(wù)器發(fā)送讀命令 GET k10086 祖乳,并且因為網(wǎng)絡(luò)狀態(tài)的原因,客戶端的 GET命令比主服務(wù)器傳播的 SET 命令更快到達(dá)了從服務(wù)器秉氧。
3)因為從服務(wù)器鍵k10086的值還未被更新眷昆,所以客戶端在從服務(wù)器讀取到的將是一個錯誤(過期)的k10086值。
Redis是怎么保證數(shù)據(jù)安全的呢汁咏?
1)主服務(wù)器只在有至少N個從服務(wù)器的情況下亚斋,才執(zhí)行寫操作
2)從Redis 2.8開始,為了保證數(shù)據(jù)的安全性攘滩,可以通過配置帅刊,讓主服務(wù)器只在有至少N個當(dāng)前已連接從服務(wù)器的情況下,才執(zhí)行寫命令漂问。
3)不過赖瞒,因為 Redis 使用異步復(fù)制,所以主服務(wù)器發(fā)送的寫數(shù)據(jù)并不一定會被從服務(wù)器接收到蚤假,因此栏饮, 數(shù)據(jù)丟失的可能性仍然是存在的。
4)通過以下兩個參數(shù)保證數(shù)據(jù)的安全:
#執(zhí)行寫操作所需的至少從服務(wù)器數(shù)量
min-slaves-to-write <number of slaves>
#指定網(wǎng)絡(luò)延遲的最大值
min-slaves-max-lag <number of seconds>
這個特性的運(yùn)作原理:
1)從服務(wù)器以每秒一次的頻率 PING 主服務(wù)器一次磷仰, 并報告復(fù)制流的處理情況袍嬉。主服務(wù)器會記錄各個從服務(wù)器最后一次向它發(fā)送 PING 的時間。用戶可以通過配置灶平, 指定網(wǎng)絡(luò)延遲的最大值 min-slaves-max-lag 伺通, 以及執(zhí)行寫操作所需的至少從服務(wù)器數(shù)量 min-slaves-to-write 。
2)如果至少有 min-slaves-to-write 個從服務(wù)器民逼, 并且這些服務(wù)器的延遲值都少于 min-slaves-max-lag 秒泵殴, 那么主服務(wù)器就會執(zhí)行客戶端請求的寫操作涮帘。你可以將這個特性看作 CAP 理論中的 C 的條件放寬版本: 盡管不能保證寫操作的持久性拼苍, 但起碼丟失數(shù)據(jù)的窗口會被嚴(yán)格限制在指定的秒數(shù)中。
3)另一方面, 如果條件達(dá)不到 min-slaves-to-write 和 min-slaves-max-lag 所指定的條件疮鲫, 那么寫操作就不會被執(zhí)行吆你, 主服務(wù)器會向請求執(zhí)行寫操作的客戶端返回一個錯誤。
六.Redis主從實戰(zhàn)
環(huán)境規(guī)劃以及地址分配
配置主從
1.安裝redis
#安裝依賴
[root@redis01 ~]# install gcc -y
#創(chuàng)建目錄
[root@redis01 ~]# mkdir -p /data/soft
[root@redis01 ~]# mkdir -p /data/redis_6379
[root@redis01 ~]# mkdir -p /opt/redis_6379/{conf,pid,logs}
#下載并安裝
[root@redis01 ~]# cd /data/soft/
[root@redis01 ~]# wget http://download.redis.io/releases/redis-3.2.9.tar.gz
[root@redis01 ~]# tar zxf redis-3.2.9.tar.gz -C /opt/
[root@redis01 ~]# ln -s /opt/redis-3.2.9/ /opt/redis
[root@redis01 ~]# cd /opt/redis
[root@redis01 ~]# make && make install
#配置文件
[root@redis01 ~]# vim /opt/redis_6379/conf/redis_6379.conf
### 以守護(hù)進(jìn)程模式啟動
daemonize yes
### 綁定的主機(jī)地址
bind 127.0.0.1 10.0.0.73
### 監(jiān)聽端口
port 6379
### pid文件和log文件的保存地址
pidfile /opt/redis_6379/pid/redis_6379.pid
logfile /opt/redis_6379/logs/redis_6379.log
### 本地數(shù)據(jù)庫的目錄
dir /data/redis_6379
### 指定本地持久化文件的文件名,默認(rèn)是dump.rdb
dbfilename redis_6379.rdb
#如果需要密碼認(rèn)證做如下配置
主從密碼配置文件里添加2行參數(shù):
requirepass "123456"
masterauth "123456"
#啟動redis
[root@redis01 ~]# redis-server /opt/redis_6379/conf/redis_6379.conf
#檢查是否啟動
[root@redis01 ~]# ps -ef|grep redis
[root@redis01 ~]# netstat -lntup|grep redis
2.快速部署其它服務(wù)器
[root@redis02 ~]# rsync -avz 10.0.0.73:/opt/* /opt/
[root@redis02 ~]# mkdir /data/redis_6379/ -p
[root@redis02 ~]# cd /opt/redis
[root@redis02 ~]# make install
[root@redis02 ~]# sed -i 's#73#74#g' /opt/redis_6379/conf/redis_6379.conf
[root@redis02 ~]# redis-server /opt/redis_6379/conf/redis_6379.conf
3.開啟主從
#開啟從庫
配置方法:
方法1: 臨時生效
[root@redis02 ~]# redis-cli -h 10.0.0.74
10.0.0.74:6379> SLAVEOF 10.0.0.73 6379
OK
?
方法2: 寫入配置文件(如果使用哨兵不建議寫入配置文件)
SLAVEOF 10.0.0.73 6379
4.檢測主從
#master
[root@redis01 ~]# redis-cli
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=10.0.0.75,port=6379,state=online,offset=15261,lag=0
slave1:ip=10.0.0.74,port=6379,state=online,offset=15261,lag=0
master_repl_offset:15261
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:15260
?
#連接從庫查看
[root@redis02 ~]# redis-cli
127.0.0.1:6379> INFO replication
# Replication
role:slave
master_host:10.0.0.73
master_port:6379
master_link_status:up
master_last_io_seconds_ago:10
master_sync_in_progress:0
slave_repl_offset:1107
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
?
[root@redis03 ~]# redis-cli
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:10.0.0.73
master_port:6379
master_link_status:up
master_last_io_seconds_ago:2
master_sync_in_progress:0
slave_repl_offset:1205
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
注意
1.從節(jié)點(diǎn)只讀不可寫
2.從節(jié)點(diǎn)不會自動故障轉(zhuǎn)移,它會一直同步主
10.0.0.74:6379> set k1 v1
(error) READONLY You can't write against a read only slave.
3.主從復(fù)制故障轉(zhuǎn)移需要人工介入
?
- 修改代碼指向REDIS的IP地址
- 從節(jié)點(diǎn)需要執(zhí)行SLAVEOF no one
4.從節(jié)點(diǎn)會清空自己原有的數(shù)據(jù),如果同步的對象寫錯了,就會導(dǎo)致數(shù)據(jù)丟失
?
安全的操作:
1.無論是同步,無論是主節(jié)點(diǎn)還是從節(jié)點(diǎn)
2.先備份一下數(shù)據(jù)
主從切換
#連接master
[root@redis01 ~]# redis-cli
#關(guān)閉主庫
127.0.0.1:6379> shutdown
?
#連接slave01
[root@redis02 ~]# redis-cli
#查看主從信息
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:10.0.0.73
master_port:6379
master_link_status:down #連接主庫的狀態(tài)是:down
master_last_io_seconds_ago:-1
master_sync_in_progress:0
slave_repl_offset:16717
master_link_down_since_seconds:77
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
#取消主從關(guān)系
127.0.0.1:6379> SLAVEOF no one
OK
127.0.0.1:6379> info replication
# Replication
role:master #此時的角色就變成了master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
?
#將其他從庫重新只想新主
#連接從庫
[root@redis03 ~]# redis-cli
127.0.0.1:6379> SLAVEOF 10.0.0.74 6379
OK
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:10.0.0.74
master_port:6379
master_link_status:up
master_last_io_seconds_ago:5
master_sync_in_progress:0
slave_repl_offset:15
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0