Redis M/S + Keepalived 主从备份高可用

网友投稿 611 2022-05-29

目录

文章目录

目录

高可用

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@:/var/lib/redis/dump.rdb

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

Redis M/S + Keepalived 主从备份高可用

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小时内删除侵权内容。

上一篇:【图像分类】实战——使用GoogLeNet识别动漫
下一篇:体验应用魔方做个抽奖小应用丨【玩转应用魔方】
相关文章