Redis 主從同步(Master&Slave)
Redis主從同步。數據可以從主服務器向任意數量的從服務器上同步,從服務器可以是關聯其他從服務器的主服務器。這使得Redis可執行單層樹復制。存盤可以有意無意的對數據進行寫操作。
工作原理:
Redis的主從結構可以采用一主多從或者級聯結構,Redis主從復制可以根據是否是全量分為全量同步和增量同步。
Master&Slave是什么?
也就是我們所說的主從復制,主機數據更新后根據配置和策略,自動同步到備機的master/slaver機制,Master以寫為主,Slave以讀為主。
全量同步
Redis全量復制一般發生在Slave初始化階段,這時Slave需要將Master上的所有數據都復制一份。具體步驟如下:
1)從服務器連接主服務器,發送SYNC命令;
2)主服務器接收到SYNC命名后,開始執行BGSAVE命令生成RDB文件並使用緩沖區記錄此后執行的所有寫命令;
3)主服務器BGSAVE執行完后,向所有從服務器發送快照文件,並在發送期間繼續記錄被執行的寫命令;
4)從服務器收到快照文件后丟棄所有舊數據,載入收到的快照;
5)主服務器快照發送完畢后開始向從服務器發送緩沖區中的寫命令;
6)從服務器完成對快照的載入,開始接收命令請求,並執行來自主服務器緩沖區的寫命令;
完成上面幾個步驟后就完成了從服務器數據初始化的所有操作,從服務器此時可以接收來自用戶的讀請求。
增量同步
Redis增量復制是指Slave初始化后開始正常工作時主服務器發生的寫操作同步到從服務器的過程。
增量復制的過程主要是主服務器每執行一個寫命令就會向從服務器發送相同的寫命令,從服務器接收並執行收到的寫命令。
Redis主從同步策略
主從剛剛連接的時候,進行全量同步;全同步結束后,進行增量同步。當然,如果有需要,slave 在任何時候都可以發起全量同步。redis 策略是,無論如何,首先會嘗試進行增量同步,如不成功,要求從機進行全量同步。
注意點
如果多個Slave斷線了,需要重啟的時候,因為只要Slave啟動,就會發送sync請求和主機全量同步,當多個同時出現的時候,可能會導致Master IO劇增宕機。
實驗環境:
server3:172.25.254.103 redis-slave
server4:172.25.254.104 redis-slave
server2:172.25.254.101 redis-master
1.redis 環境搭建
1)在所有實驗主機上安裝 Redis
先下載安裝包 redis-4.0.8.tar.gz 並做以下操作
tar zxf redis-4.0.8.tar.gz ##解壓安裝包 cd redis-4.0.8 yum install gcc -y make && make install ###安裝
cd redis-4.0.8/utils/ ./install_server.sh 執行這個腳本
2)編輯配置文件
vim /etc/redis/6379.conf 找到第70行的bind 后面寫0.0.0.0 /etc/init.d/redis_6379 stop /etc/init.d/redis_6379 start
2.配置redis-slave
[root@server3 ~]# vim /etc/redis/6379.conf
slaveof 172.25.254.101 6379 # redis-master 的ip
[root@server3 ~]# /etc/init.d/redis_6379 restart
Stopping ...
Redis stopped
Starting Redis server...
[root@server4 ~]# vim /etc/redis/6379.conf
slaveof 172.25.254.101 6379
[root@server4 ~]# /etc/init.d/redis_6379 restart
Stopping ...
Redis stopped
Starting Redis server...
復制原理:
1、Slave啟動成功連接到master后會發送一個sync命令;
2、Master接到命令啟動后的存盤進程,同時收集所有接收到的用於修改數據集命令,在后台進程執行完畢之后,master
將傳送整個數據文件到slave,以完成一次完全同步;
3、全量復制:而slave服務在數據庫文件數據后,將其存盤並加載到內存中;
4、增量復制:Master繼續將新的所有收集到的修改命令依次傳給slave,完成同步;
5、但是只要是重新連接master,一次完全同步(全量復制)將被自動執行。
————————————————
如上操作所示,已經完成redis的主從復制
3.測試
在master端server2:操作,在slave端server3查看
執行redis-cli,登陸 若數據一致,則同步成功
1)在master 端操作
2)在selave 端查看
三、Redis Sentinel(哨兵)架構下的高可用
Redis的主從復制下,一旦主節點由於故障不能提供服務,需要人工將從節點晉升為主節點,同時還要通知應用方更新主節點地址,對於很多應用場景這種故障處理的方法是無法接受的。但是Redis從2.8開始正式提供了Redis Sentinel(哨兵)架構來解決這個問題。
Redis Sentinel是一個分布式架構,其中包含若干個Sentinel節點和Redis數據節點,每個Sentinel節點會對數據節點和其余Sentinel節點進行監控,當它發現節點不可達時,會對節點做下線標識。如果被標識的是主節點,它還會和其他Sentinel節點進行“協商”,當大多數Sentinel節點都認為主節點不可達時,它們會選舉出一個Sentinel節點來完成自動故障轉移的工作,同時會將這個變化通知給Redis應用方。整個過程完全是自動的,不需要人工來介入,所以這套方案很有效地解決了Redis的高可用問題。
哨兵模式(sentinel)
反客為主的自動版,能夠后台監控Master庫是否故障,如果故障了根據投票數自動將slave庫轉換為主庫。一組sentinel能
同時監控多個Master。
使用步驟:
1、在Master對應redis.conf同目錄下新建sentinel.conf文件,名字絕對不能錯;
2、配置哨兵,在sentinel.conf文件中填入內容:
sentinel monitor 被監控數據庫名字(自己起名字) ip port 1
說明:上面最后一個數字1,表示主機掛掉后slave投票看讓誰接替成為主機,得票數多少后成為主機。
3、啟動哨兵模式:
命令鍵入:redis-sentinel /myredis/sentinel.conf
注:上述sentinel.conf路徑按各自實際情況配置
————————————————
實現原理:
三個定時監控任務
1)每隔10秒,每個Sentinel節點會向主節點和從節點發送info命令獲取最新的拓撲結構。
2)每隔2秒,每個Sentinel節點會向Redis數據節點的__sentinel__:hello頻道上發送該Sentinel節點對於主節點的判斷以及當前Sentinel節點的信息,同時每個Sentinel節點也會訂閱該頻道,來了解其他Sentinel節點以及它們對主節點的判斷。
3)每隔一秒,每個Sentinel節點會向主節點、從節點、其余Sentinel節點發送一條ping命令做一次心跳檢測,來確認這些節點當前是否可達。
主觀下線
因為每隔一秒,每個Sentinel節點會向主節點、從節點、其余Sentinel節點發送一條ping命令做一次心跳檢測,當這些節點超過down-after-milliseconds沒有進行有效回復,Sentinel節點就會對該節點做失敗判定,這個行為叫做主觀下線。
客觀下線
當Sentinel主觀下線的節點是主節點時,該Sentinel節點會向其他Sentinel節點詢問對主節點的判斷,當超過<quorum>個數,那么意味着大部分的Sentinel節點都對這個主節點的下線做了同意的判定,於是該Sentinel節點認為主節點確實有問題,這時該Sentinel節點會做出客觀下線的決定。
領導者Sentinel節點選舉
Raft算法:假設s1(sentinel-1)最先完成客觀下線,它會向其余Sentinel節點發送命令,請求成為領導者;收到命令的Sentinel節點如果沒有同意過其他Sentinel節點的請求,那么就會同意s1的請求,否則拒絕;如果s1發現自己的票數已經大於等於某個值,那么它將成為領導者。
故障轉移
1)領導者Sentinel節點在從節點列表中選出一個節點作為新的主節點
2)上一步的選取規則是與主節點復制相似度最高的從節點
3)領導者Sentinel節點讓剩余的從節點成為新的主節點的從節點
4)Sentinel節點集合會將原來的主節點更新為從節點,並保持着對其關注,當其恢復后命令它去復制新的主節點
————————————————
1.實驗環境 (首先搭建好Redis環境並可以進行主從同步)
系統版本:rhel6.5
server3:172.25.254.103 redis-slave
server4:172.25.254.104 redis-slave
server2:172.25.254.101 redis-master
2.主節點操作
1)在安裝包中將 sentinel 文件復制到/etc/redis/下
[root@server2 ~]# cd redis-4.0.1
[root@server2 redis-4.0.1]# cp sentinel.conf /etc/redis/
[root@server2 redis-4.0.1]# cd /etc/redis/
2)修改配置文件
[root@server2 redis]# vim sentinel.conf
關閉保護模式
第98 行 Sentinel 去監視一個名為 mymaster 的主服務器, 這個主服務器的IP 地址為 172.25.154.101,端口號為 6379 ,而將這個主服務器判斷為失效至少需要 2 個 Sentinel 同意 (只要同意 Sentinel 的數量不達標,自動故障遷移就不會執行)
如:
sentinel monitor mymaster 172.25.254.101 6379 2
3)將配置好的文件發送給所有從節點
[root@server2 redis]# scp sentinel.conf root@172.25.254.102:/etc/redis/
sentinel.conf 100% 7609 7.4KB/s 00:00
[root@server2 redis]# scp sentinel.conf root@172.25.254.104:/etc/redis/
sentinel.conf 100% 7609 7.4KB/s 00:00
4)三台redis 開啟 sentinel 服務
[root@server2 redis]# redis-sentinel /etc/redis/sentinel.conf
————————————————
兩台slave
[root@server3 ~]# redis-sentinel /etc/redis/sentinel.conf
[root@server4 ~]# redis-sentinel /etc/redis/sentinel.conf
+slave 表示 :一個新的從服務器已經被 Sentinel 識別並關聯 可以看到片此時 master 是 server2;server3和 server4 是 slave。
3.測試
1)停掉現在的Redis-master info 查看 replication 信息
[root@server2 ~]# redis-cli -p 26379
127.0.0.1:26379> info
master0:name=mymaster,status=ok,address=172.25.254.101:6379,slaves=2,sentinels=3[root@server2 ~]# redis-cli
127.0.0.1:6379> SHUTDOWN
not connected>
[root@server2 ~]# redis-cli
Could not connect to Redis at 127.0.0.1:6379: Connection refused
Could not connect to Redis at 127.0.0.1:6379: Connection refused
not connected>
[root@server2 ~]# redis-cli -p 26379
127.0.0.1:26379> info
master0:name=mymaster,status=ok,address=172.25.254.102:6379,slaves=2,sentinels=3
127.0.0.1:26379>
2)查看任意一台redis主機的監控日志
[root@server4 ~]# redis-sentinel /etc/redis/sentinel.conf
+switch-master :配置變更,主服務器的 IP 和地址已經改變 由之前的172.25.254.101 更改為172.25.254.102。
+sdown :給定的實例 server2現在處於主觀下線狀態。
在原先的master被停掉后,通過選舉產生新的master 172.25.254.102 6379
實際現在只有一個slave 可以使用
四、Redis Cluster(集群)下的高可用
實現原理:
主觀下線
集群中每個節點都會定期向其他節點發送ping消息,接受節點回復ping消息作為響應。如果在cluster-node-timeout時間內通信一直失敗,則發送節點會認為接收節點存在故障,把接受節點標記為主觀下線(pfail)狀態。
客觀下線
1)當某個節點判斷另一個節點主觀下線后,相應的節點狀態會跟隨消息在集群內傳播。
2)假設節點a標記節點b為主觀下線,一段時間后節點a通過消息把節點b的狀態發送到其他節點,當其他節點收到消息並解析出消息體中含有b的pfail狀態,把節點b加入下線報告鏈表;
3)當某一節點c收到節點b的pfail狀態時,此時有超過一半的槽主節點都標記了節點b為pfail狀態時,則標記故障節點b為客觀下線;
4)向集群廣播一條pfail消息,通知集群內的所有節點標記故障節點b為客觀下線狀態並立刻生效,同時通知故障節點b的從節點觸發故障轉移流程。
故障恢復
1)資格檢查
若從節點與主節點斷線時間超過一定時間,則不具備資格
2)准備選舉時間
當從節點符合故障轉移資格后,要等待一段選舉時間后才開始選舉
在故障節點的所有從節點中,復制偏移量最大的那個從節點最先開始(與主節點的數據最一致)進行選舉,然后是次大的節點開始選舉.....剩下其余的從節點等待到它們的選舉時間到達后再進行選舉
3)發起選舉
4)選舉投票
只有持有槽的主節點才具有一張唯一的選票,從從節點收集到N/2 + 1個持有槽的主節點投票時,從節點可以執行替換主節點操作
5)替換主節點
當從節點收集到足夠的選票之后,觸發替換主節點操作
當前從節點取消復制變為主節點
撤銷故障主節點負責的槽,並把這些槽委派給自己
向集群廣播自己的pong消息,通知集群內所有的節點當前從節點變為主節點並接管了故障主節點的槽信息
1.實驗環境:
使用任意一台redis 主機
2.部署高可用
1)搭建環境
[root@server2 redis]# /etc/init.d/redis_6379 stop cd /usr/local/ mkdir cluster ##建立集群目錄 [root@server2 local]# cd cluster/ [root@server2 cluster]# pwd /usr/local/cluster [root@server2 cluster]# mkdir 700{1..6} [root@server2 cluster]# ll total 24 drwxr-xr-x 2 root root 4096 Oct 9 11:02 7001 drwxr-xr-x 2 root root 4096 Oct 9 11:02 7002 drwxr-xr-x 2 root root 4096 Oct 9 11:02 7003 drwxr-xr-x 2 root root 4096 Oct 9 11:02 7004 drwxr-xr-x 2 root root 4096 Oct 9 11:02 7005 drwxr-xr-x 2 root root 4096 Oct 9 11:02 7006 [root@server2 cluster]# cd 7001/ [root@server2 7001]# vim redis.conf [root@server2 ~]# cat /usr/local/cluster/7001/redis.conf port 7001 cluster-enabled yes #打開集群設備 cluster-config-file nodes.conf cluster-node-timeout 5000 #延時時間 appendonly yes daemonize yes pidfile /usr/local/cluster/7001/redis.pid ##pid文件存放目錄 logfile /usr/local/cluster/7001/redis.log ##日志存放目錄 [root@server2 7001]# redis-server redis.conf ###打開集群服務
[root@server2 cluster]# cp 7001/redis.conf 7002/
[root@server2 cluster]# cp 7001/redis.conf 7003/
[root@server2 cluster]# cp 7001/redis.conf 7004/
[root@server2 cluster]# cp 7001/redis.conf 7005/
[root@server2 cluster]# cp 7001/redis.conf 7006/
[root@server2 cluster]# cd 7002/
[root@server2 7002]# vim redis.conf ###將文件中的端口號改為7002和存放目錄的更改
redis-server redis.conf ###打開集群的redis
cd ..
cd 7003/ vim redis.conf ###將文件中的端口號改為7003和存放目錄的更改
redis-server redis.conf ###打開集群的redis
cd ..
cd 7004/ vim redis.conf ###將文件中的端口號改為7004和存放目錄的更改
redis-server redis.conf ###打開集群的redis
cd ..
cd 7005/
vim redis.conf ###將文件中的端口號改為7005和存放目錄的更改
redis-server redis.conf ###打開集群的redis
cd ..
cd 7006/ vim redis.conf ###將文件中的端口號改為7006和存放目錄的更改
redis-server redis.conf ###打開集群的redis
ps ax ##查看進程是否都打開了
netstat -antlp ##查看端口號是否開啟
[root@server2 ~]# cd redis-4.0.1
[root@server2 redis-4.0.1]# cd src/
[root@server2 src]# cp redis-trib.rb /usr/local/bin/
[root@server2 src]# yum install -y ruby
[root@server2 ~]# yum install -y rubygems-1.3.7-5.el6.noarch.rpm
[root@server2 ~]# rpm -Uvh ruby-2.2.3-1.el6.x86_64.rpm
[root@server2 ~]# yum install -y ruby-2.2.3-1.el6.x86_64.rpm libyaml-0.1.3-4.el6_6.x86_64.rpm
[root@server2 ~]# gem install --local redis-4.0.1.gem
2)創建集群
[root@server2 ~]# redis-trib.rb create --replicas 1 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006
[root@server2 ~]# redis-cli -c -p 7001
127.0.0.1:7001> set name linux
-> Redirected to slot [5798] located at 127.0.0.1:7002
OK
127.0.0.1:7002>
[root@server2 ~]# redis-cli -c -p 7006
127.0.0.1:7006> set name kb
-> Redirected to slot [5798] located at 127.0.0.1:7002
OK
127.0.0.1:7002> get name
"kb"
127.0.0.1:7002>
redis-cli -c -p 7001
登錄,set name linux 寫入內容,會提示寫入內容傳到2上
redis-cli -c -p 7002
輸入info,發現2是master,他的slave是6
3)測試
停掉master 2
[root@server2 ~]# redis-cli -c -p 7002
127.0.0.1:7002> SHUTDOWN
not connected>
redis-trib.rb check 127.0.0.1:7001 ##查看集群的狀態
可以查看之前的內容
[root@server2 ~]# redis-cli -c -p 7001
127.0.0.1:7001> get name
-> Redirected to slot [5798] located at 127.0.0.1:7005
"kb"
127.0.0.1:7005>
再關掉一個master
[root@server2 ~]# redis-cli -c -p 7005
127.0.0.1:7005> SHUTDOWN
not connected>
查看信息
關閉掉兩個master后,集群的功能會破壞
[root@server2 ~]# redis-cli -c -p 7001
127.0.0.1:7001> get name
(error) CLUSTERDOWN The cluster is down
127.0.0.1:7001>
4)恢復關閉的兩個節點
[root@server2 ~]# cd /usr/local/cluster/
[root@server2 cluster]# ls
7001 7002 7003 7004 7005 7006
[root@server2 cluster]# cd 7002
[root@server2 7002]# redis-server redis.conf
1292:C 09 Oct 11:40:46.513 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1292:C 09 Oct 11:40:46.513 # Redis version=4.0.1, bits=64, commit=00000000, modified=0, pid=1292, just started
1292:C 09 Oct 11:40:46.513 # Configuration loaded
[root@server2 7002]# cd ..
[root@server2 cluster]# cd 7005
[root@server2 7005]# redis-server redis.conf
1298:C 09 Oct 11:41:15.609 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1298:C 09 Oct 11:41:15.609 # Redis version=4.0.1, bits=64, commit=00000000, modified=0, pid=1298, just started
1298:C 09 Oct 11:41:15.609 # Configuration loaded
高可用搭建完成