Redis M/S + Keepalived 主從備份高可用
目錄
文章目錄
目錄
高可用
Redis 的高可用
Redis 主從復制配置
Redis 主從切換(手動方式)
SLAVEOF 指令
Redis M/S + Keepalived
故障的 3 種情況
主節點配置 keepalived.conf
從節點配置 keepalived.conf
redis_check.sh
redis_master.sh
redis_backup.sh
redis_fault.sh
redis_stop.sh
高可用
高可用是指服務器可以正常訪問的時間,衡量的標準是在多長時間內可以提供正常服務(99.9%、99.99%、99.999% 等等)。而在 Redis 的語境中,高可用的含義似乎要更寬泛一些,除了保證提供正常服務(如:主從分離、快速容災技術等),還需要考慮數據容量的擴展、數據安全不會丟失等。
Redis 的高可用
在 Redis 中,實現高可用的技術主要包括持久化、復制、哨兵和集群:
持久化:即將數據存儲在硬盤,保證數據不會因進程退出而丟失,主要作用是數據備份。
復制:主要實現了數據的多機備份以及對于讀操作的負載均衡和簡單的故障恢復。缺陷是故障恢復無法自動化、寫操作無法負載均衡、存儲能力受到單機的限制。
哨兵:在復制的基礎上,哨兵實現了自動化的故障恢復。缺陷是寫操作無法負載均衡、存儲能力受到單機的限制。
集群:通過集群,Redis 解決了寫操作無法負載均衡以及存儲能力受到單機限制的問題,實現了較為完善的高可用方案。
本文主要討論通過 Redis 的 “復制” 技術支撐的高可用方案。
Redis 主從復制配置
Redis 主從復制實際上就是將 MASTER 節點的數據,復制到其他 SLAVE 節點去進行存儲。
修改關鍵配置:
MASTER
bind 0.0.0.0 port 6379 slave-serve-stale-data yes slave-read-only no ...
1
2
3
4
5
SLAVE
bind 0.0.0.0 port 6379 slave-serve-stale-data yes slave-read-only no slaveof 172.16.81.140 6379 ...
1
2
3
4
5
6
可以看見,Redis 主從配置中最主要的一個項目就是 slaveof,他指定了 SLAVE 節點與 MASTER 節點的從屬關系。
重啟 Redis Daemon 之后,查看配合是否有生效:
MASTER
$ redis-cli 127.0.0.1:6379> INFO ... # Replication role:master connected_slaves:1 slave0:ip=172.18.22.202,port=6379,state=online,offset=108458,lag=0 master_repl_offset:108458 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:22541 repl_backlog_histlen:85918
1
2
3
4
5
6
7
8
9
10
11
12
SLAVE
$ redis-cli 127.0.0.1:6379> INFO ... # Replication role:slave master_host:172.18.22.204 master_port:6379 master_link_status:up master_last_io_seconds_ago:1 master_sync_in_progress:0 slave_repl_offset:108654 slave_priority:100 slave_read_only:0 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
可以看見 MASTER 和 SLAVE 當前是互相認證的:在 MASTER 上可以查看分別由哪些 SLAVE,狀態如何,復制(Replication)的配置如何;在 SLAVE 上可以查看自己的 MASTER 是誰,狀態如何,自己的權重是多少,是否只讀。如果是只讀的話,SLAVE 將無法寫入任何數據:
127.0.0.1:6379> SET test2 123 (error) READONLY You can't write against a read only slave.
1
2
下面進行一次同步測試:
MASTER
$ redis-cli 127.0.0.1:6379> SET test1 123 OK
1
2
3
SLAVE
$ redis-cli 127.0.0.1:6379> GET test1 "123"
1
2
3
Redis 主從切換(手動方式)
當 MASTER 宕機時,最簡單的恢復方式就是使用手動切換的方式,手動的將一臺從節點切換成主節點。手動方式顯然是不推薦的,但我們不放了解一下。
關閉 MASTER。
systemctl stop redis
1
手動將 SLAVE 設置成主節點。
$ redis-cli 127.0.0.1:6379> slaveof no one 127.0.0.1:6379> INFO ... # Replication role:master connected_slaves:0 master_repl_offset:1177 repl_backlog_active:0 repl_backlog_size:1048576 repl_backlog_first_byte_offset:0 repl_backlog_histlen:0
1
2
3
4
5
6
7
8
9
10
11
12
新的數據寫入到 SLAVE。
127.0.0.1:6379> SET test4 123 OK 127.0.0.1:6379> SET test5 123 OK 127.0.0.1:6379> SET test6 123 OK
1
2
3
4
5
6
下面為執行數據恢復的步驟:
持久化 SLAVE 的數據。
127.0.0.1:6379> save OK
1
2
拷貝從節點的 dump.rdb 文件到主節點中。
scp /var/lib/redis/dump.rdb root@
1
重啟 MASTER 和 SLAVE,發現 MASTER 和 SLAVE 的數據又保持了同步,而且身份角色也恢復到了初始狀態。這是因為:當 Redis 重啟時,手動執行的主從切換設置將會失效,還原為初始狀態,因為我們在上面已寫入了 SLAVE 的配置文件。
SLAVEOF 指令
SLAVEOF 指令指定了當前 Redis 實例是從屬于某個 MASTER 的 SLAVE。如果這個指令在配置文件中寫死,那么實例重啟后就永遠是 SLAVE,除非有哨兵將它提升為 MASTER,或手動執行指令 SLAVEOF NO ONE。
在本文討論的 M/S 場景中,則需要腳本或手動執行。而在哨兵模式的場景中,這個指令會被哨兵動態地從配置文件中添加或刪除,它的存在與否最好交由哨兵決定。需要注意的是,該指令不應該寫死在 “子文件” 中,因為子文件中寫死的指令是無法被哨兵移除的,這將導致 SLAVE 每次重啟后都是 SLAVE。這個問題很難排查。
Redis M/S + Keepalived
M/S + Keepalived 是一個非常經典的 Redis 高可用方案,是哨兵模式出現之前的主流方案。現在常見與雙節點的 Redis 高可用需求場景(哨兵模式需要三節點)。此方案使用了 Redis 原生的主從復制機制結合 Keepalived 的 VRRP 技術:Redis M/S 提供數據持久化和備份策略,Keepalived 提供了健康檢查、監控告警、故障切換以及統一的 VIP 訪問接口。
優點:
高可靠性。雙機主備架構、數據持久化以及備份策略。
秒級切換。
故障切換對應用透明。
部署簡單,維護成本低。
缺點:
Redis 主從切換需要自定義腳本實現。
Keepalived 存在主從腦裂風險。
故障的 3 種情況
Keepalived 掛了,同時 Redis 也掛了,這樣的話 VIP 飄走之后,是不需要進行 Redis 數據同步的,因為 Redis 已經掛了,你也無法去 MASTER 上同步,會損失已經寫在 MASTER 上但還沒同步到 SLAVE 上面的這部分數據。
Keepalived 掛了,Redis 沒掛,這時 VIP 飄走后,Redis 的 MASTER/SLAVE 還是老的對應關系。默認情況下,會把數據寫入 Redis SLAVE 中,而不會同步到 MASTER 上去,這時就要借助監控腳本反轉 Redis 的身份關系了。并且需要預留一點時間里進行數據同步,然后切換主從關系。
Keepalived 沒掛,Redis 掛了,這時根據監控腳本檢測到 Redis 掛了,馬上降低 Keepalived Master 的優先級,導致 VIP 飄走,情況和第二種一樣,也是需要進行數據同步,然后 Redis 主從切換。
主節點配置 keepalived.conf
! Configuration File for keepalived global_defs { notification_email { acassen@firewall.loc failover@firewall.loc sysadmin@firewall.loc } notification_email_from Alexandre.Cassen@firewall.loc smtp_server 192.168.200.1 smtp_connect_timeout 30 router_id redis01 } vrrp_script chk_redis { script "/etc/keepalived/script/redis_check.sh" interval 2 } vrrp_instance VI_1 { state MASTER interface eno16777984 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } track_script { chk_redis } virtual_ipaddress { 172.16.81.139 } notify_master /etc/keepalived/script/redis_master.sh notify_backup /etc/keepalived/script/redis_backup.sh notify_fault /etc/keepalived/script/redis_fault.sh notify_stop /etc/keepalived/script/redis_stop.sh }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
notify_master:Keepalived 切換為主節點時執行的腳本。
notify_backup:Keepalived 切換為從節點時執行的腳本。
notify_fault:Keepalived 進程故障時執行的腳本。
notify_stop:keepalived 進程停止前執行的腳本。
nopreempt:設置不搶占,這里只能設置在 state 為 backup 的節點上,而且這個節點的優先級必須別另外的高。
從節點配置 keepalived.conf
! Configuration File for keepalived global_defs { notification_email { acassen@firewall.loc failover@firewall.loc sysadmin@firewall.loc } notification_email_from Alexandre.Cassen@firewall.loc smtp_server 192.168.200.1 smtp_connect_timeout 30 router_id redis02 } vrrp_script chk_redis { script "/etc/keepalived/script/redis_check.sh" interval 2 } vrrp_instance VI_1 { state BACKUP interface eno16777984 virtual_router_id 51 priority 99 advert_int 1 authentication { auth_type PASS auth_pass 1111 } track_script { chk_redis } virtual_ipaddress { 172.16.81.139 } notify_master /etc/keepalived/script/redis_master.sh notify_backup /etc/keepalived/script/redis_backup.sh notify_fault /etc/keepalived/script/redis_fault.sh notify_stop /etc/keepalived/script/redis_stop.sh }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
redis_check.sh
#!/bin/bash CHECK=`/usr/local/bin/redis-cli PING` if [ "$CHECK" == "PONG" ] ;then echo $CHECK exit 0 else echo $CHECK service keepalived stop # 確保讓出 MASTER exit 1 fi
1
2
3
4
5
6
7
8
9
10
11
keepalived 會根據該監控腳本的返回碼來調整優先級:
如果腳本返回碼為 0,并且 weight > 0,則優先級相應的增加;
如果腳本返回碼為非 0,并且 weight < 0,則優先級相應的減少;
其他情況,原本配置的優先級不變,即配置文件中 priority 對應的值。
NOTE:
優先級不會不斷的提高或者降低;
可以編寫多個檢測腳本并為每個檢測腳本設置不同的 weight(在配置中列出就行);
不管提高優先級還是降低優先級,最終優先級的范圍是在 [1, 254],不會出現優先級小于等于 0 或者優先級大于等于 255 的情況;
配置 nopreempt ,避免正常情況下做無謂的切換。
redis_master.sh
#!/bin/bash REDISCLI="/usr/local/redis/bin/redis-cli -a 123456" LOGFILE="/var/log/keepalived-redis-state.log" sleep 15 echo "[master]" >> $LOGFILE date >> $LOGFILE echo "Being master...." >>$LOGFILE 2>&1 echo "Run SLAVEOF cmd ...">> $LOGFILE $REDISCLI SLAVEOF 172.16.81.141 6379 >>$LOGFILE 2>&1 # 先同步數據 if [ $? -ne 0 ];then echo "data rsync fail." >>$LOGFILE 2>&1 else echo "data rsync OK." >> $LOGFILE 2>&1 fi sleep 10 # 延遲 10 秒以后待數據同步完成后再取消同步狀態 echo "Run SLAVEOF NO ONE cmd ...">> $LOGFILE $REDISCLI SLAVEOF NO ONE >> $LOGFILE 2>&1 # 切換為 MASTER if [ $? -ne 0 ];then echo "Run SLAVEOF NO ONE cmd fail." >>$LOGFILE 2>&1 else echo "Run SLAVEOF NO ONE cmd OK." >> $LOGFILE 2>&1 fi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
redis_backup.sh
#!/bin/bash REDISCLI="/usr/local/redis/bin/redis-cli -a 123456" LOGFILE="/var/log/keepalived-redis-state.log" echo "[backup]" >> $LOGFILE date >> $LOGFILE echo "Being slave...." >>$LOGFILE 2>&1 sleep 15 # 延遲 15 秒待數據被對方同步完成之后再切換主從角色 echo "Run SLAVEOF cmd ...">> $LOGFILE $REDISCLI SLAVEOF 172.16.81.141 6379 >>$LOGFILE 2>&1 # 切換為 BACKUP
1
2
3
4
5
6
7
8
9
10
11
12
redis_fault.sh
#!/bin/bash LOGFILE=/var/log/keepalived-redis-state.log echo "[fault]" >> $LOGFILE date >> $LOGFILE
1
2
3
4
5
6
redis_stop.sh
#!/bin/bash LOGFILE=/var/log/keepalived-redis-state.log echo "[stop]" >> $LOGFILE date >> $LOGFILE
1
2
3
4
5
6
Redis
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。