redis主从利用VIP进行热备高可用解决方案

上一篇文章写到了关于redis的主从复制以及使用sentinel自动切换宕机的redis master主机,但是结尾留下了一个问题那就是当redis master宕机之后sentinel又指定了一个redis slave作为master但是客户端主机连接的IP与端口是原来宕机的redis master该这么解决的问题。

其实对于这个问题,解决的办法还是有很多的,比如:

①利用keepalive来控制redis主从,并利用keepalive可自定义脚本自动监控两个节点(主、从)随后当主节点一旦宕机之后通过脚本自动修改主从关系。这种办法不但脚本难写之外而且还不稳定…
②利用twemproxy或者codis这种中间件作为热备切换的工具。这种办法其实还是很好的,不过对于小规模redis来说其实太浪费资源了。
③使用端口映射方式配合sentinel的client-reconfig-script配置参数来运行脚本当master宕机后将端口映射映射到哪里,这个与本博客的很类似,不过这样的话配置一主一从外加sentinel主机一共三台机器,其中端口映射功能放在sentinel主机上面客户端则连接那个端口映射的地址即可!但是这样有个坏处那就是一旦sentinel宕机之后该咋办?应用肯定停了。其实这种方式还是不错的,但是端口映射的主机只有一台宕机就结束了不过这种方法对我启发很大。这个博客的链接请点我

后来经过我在关键词的搜索之中加入了client-reconfig-script这个sentinel配置参数找到了一个日本人的博客,他所用的方法还是非常值得使用的!首先上链接。这篇文章值得大家去看原文思路比较清晰而且架构简单不复杂也不需要外部的第三方工具。

解决方法的拓扑以及概述:

拓扑就用上一篇文章讲到的拓扑,这个拓扑最适合这种方法:

安装好了三个redis让172.16.1.20作为master然后安装好三个sentinel配置可以和上一篇的一样。随后我们在sentinel.conf中找到这么一段配置:

vim sentinel.conf
sentinel client-reconfig-script <master-name> <script-path>
#这段配置的意思就是如果当sentinel改变redis master时会执行指定路径的脚本,其中master-name就是主节点的
#定义名,而script-path代表脚本所在位置,下面是上面拓扑的示例配置:
sentinel client-reconfig-script test /usr/local/redis/shells/change.sh
#当然除了上面的改变redis master会执行指定路径的脚本之外还有一个很好的配置:
sentinel notification-script <master-name> <script-path>
#与上面的配置其实差不多不过这个是当master宕机或slave宕机之后执行的通知脚本可以用来发送邮件。
#不过现在有了zabbix之后其实也不需要了,zabbix也会检测程序进程宕机之后会自动发送邮件、短信甚至微信。

现在我们使用了这个参数后该写什么样的脚本好呢?神奇的事情就在后面,由于linux操作系统允许在同一块网卡上配置多个IP地址的特性,所以我们可以首先在redis master主机网卡上多配置一个ip地址比如配置一个172.16.1.200的地址,随后在脚本中这么写:

首先使用sentinel内件变量${6}来获取现在redis master的IP地址然后比对当前所在主机的ip地址如果为一样则添加一个virtualIP就是172.16.1.200,然后地址不同的则使用命令删除172.16.1.200这个地址。

也就是说三台redis都安装了sentinel当redis master宕机以后sentinel则会选举一个新的redies master,选举完毕以后三台安装过sentinel的主机都会运行该脚本来判断当前master的IP是否与本机的IP相同(假设virtualIP为172.16.1.200),如果不同则会删除这个virtualIP,如果相同则会添加这个virtualIP.

所以会有这么一个流程:当一台redis master宕机以后两台sentinel客观判断redis master下线发生选举,选举后产生一个新的redis master此时这台新的master是没有virtualIP的,随后利用了sentinel client-reconfig-script这个参数执行了一个脚本来判断当前sentinel选举的主机IP是否与现在的主机IP相同,如果相同则会添加所指定的virtualIP,如果不同咋会删除virtualIP.即使这台机器没有virtualIP时执行也不会报错,如果原来redis master的virtualIP还在肯定会删除(假设原来redis master时应用挂了而sentinel没有宕机)。所以保证了三台机器只有一个virtualIP只要客户端连接这个virtualIP就能保证高可用而无需人工干预即便时半夜2点宕机也没事会自动进行切换,最多过30秒客户端又能进行对redis的访问了。

说了这么多的理论知识让大家了解这种方法的过程,了解完毕以后接下来来看看如何配置!

关于配置与检测:

前面配置redis和sentinel我就不再进行多说了,请自行查看上一篇上上篇的文章!第一步我们修改参数并且将脚本写好:

cd /usr/local/redis/
vim sentinel.conf
sentinel client-reconfig-script hailijr /usr/local/redis/shells/change.sh
#首先添加好到时候redis master发生改变时候的脚本路径。
mkdir shells #创建脚本的目录
vim change.sh #填写脚本,我直接参照日本人那篇博客拷贝下来的,版权归他我只是使用一下嘿嘿。
#!/bin/bash
#
MASTER_IP=${6} #使用内建变量查看当前master地址,这个在配置文件有过解释:
# The following arguments are passed to the script:
# <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>
#请从左往右数6个
MY_IP='172.16.1.40' # 各サーバ自身のIP 当前主机的地址
VIP='172.16.1.200' # VIP
NETMASK='24' # Netmask
INTERFACE='enp0s3' # インターフェイス 网卡设备名字

if [ ${MASTER_IP} == ${MY_IP} ]; then
#其中的sudo可以省略如果你的sentinel是以root启动的。
 sudo /sbin/ip addr add ${VIP}/${NETMASK} dev ${INTERFACE}
 sudo /sbin/arping -q -c 3 -A ${VIP} -I ${INTERFACE}
 exit 0
else
 sudo /sbin/ip addr del ${VIP}/${NETMASK} dev ${INTERFACE}
 exit 0
fi
exit 1

其实这个脚本写的有些简单没有提供日志功能,后来在我的查找下有看到了一篇专业redis的文章(咱就偷个懒嘿嘿!)当然这些脚本不符合你的需要可以修改但是核心功能就是判断IP地址增加或删除VIP!

#!/bin/bash
_DEBUG="on" #当DEBUG=on这个字段的时候就会记录日志
DEBUGFILE=/tmp/sentinel_failover.log
VIP='172.16.1.200'
MASTERIP=${6}
MASK='24'
IFACE='enp0s3'
MYIP=$(ip -4 -o addr show dev ${IFACE}| grep -v secondary| awk '{split($4,a,"/");print a[1]}')
#自动检测当前主机地址通过过滤的办法。
DEBUG () {
if [ "$_DEBUG" = "on" ]; then
echo `$@` >> ${DEBUGFILE}
fi
}

set -e
DEBUG date
DEBUG echo $@
DEBUG echo "Master: ${MASTERIP} My IP: ${MYIP}"
if [ ${MASTERIP} = ${MYIP} ]; then
if [ $(ip addr show ${IFACE} | grep ${VIP} | wc -l) = 0 ]; then
/sbin/ip addr add ${VIP}/${MASK} dev ${IFACE}
DEBUG date
DEBUG echo "/sbin/ip addr add ${VIP}/${MASK} dev ${IFACE}"
DEBUG date
DEBUG echo "IP Arp cleaning: /usr/sbin/arping -q -f -c 1 -A ${VIP} -I ${IFACE}"
/usr/sbin/arping -q -f -c 1 -A ${VIP} -I ${IFACE}
DEBUG date
DEBUG echo "IP Failover finished!"
fi
exit 0
else
if [ $(ip addr show ${IFACE} | grep ${VIP} | wc -l) != 0 ]; then
/sbin/ip addr del ${VIP}/${MASK} dev ${IFACE}
DEBUG echo "/sbin/ip addr del ${VIP}/${MASK} dev ${IFACE}"
fi
exit 0
fi
exit 1

写好脚本之后别忘了重启sentinel否则配置是不会生效的,这样第一步就算做完了,第二步添加当前redis master的virtualIP!由于这个脚本只能在sentinel发生主从切换时才会执行所以第一次的VIP要我们手动添加:

#在172.16.1.20主机上添加
ip addr add 172.16.1.200/24 dev enp0s3
#随后自己运行ip addr show 看看是否添加完毕!

关闭当前redis master结点查看运行效果:

redis-cli -h 172.16.1.200 shutdown #直接关闭当前master节点
#随后查看sentinel.log日志,要是没有设定就惨咯那就无法看到切换过程
#如果sentinel如果切换了主从那就紧接着执行脚本你会看到这样的字段:
+config-update-from sentinel #这样就说明脚本执行成功!
#随后别忘了看看ip时候切换,如果脚本语法有错才不会切换IP呢!
#通过日志我发现已经切换到172.16.1.40上去了:
+sdown master test 172.16.1.40 6379
#查看172.16.1.40地址:
ip addr show
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
 link/ether 08:00:27:bb:30:00 brd ff:ff:ff:ff:ff:ff
 inet 172.16.1.40/24 brd 172.16.1.255 scope global enp0s3
 valid_lft forever preferred_lft forever
 inet 172.16.1.200/24 scope global secondary enp0s3
 valid_lft forever preferred_lft forever
 inet6 fe80::a00:27ff:febb:3000/64 scope link
 valid_lft forever preferred_lft forever

支持这个VIP已经切换到了新的master上去了,如果执行了脚本并且成功的话原来的172.16.1.20会没有这个172.16.1.200地址,为了安全起见还是要上去看看:

ip addr show
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
 link/ether 08:00:27:9d:bd:8a brd ff:ff:ff:ff:ff:ff
 inet 172.16.1.20/24 brd 172.16.1.255 scope global enp0s3
 valid_lft forever preferred_lft forever
 inet6 fe80::a00:27ff:fe9d:bd8a/64 scope link
 valid_lft forever preferred_lft forever

好了到这里就算吧这个精巧的高可用的微型redis集群就算布置完毕了。

结语:

此方法只适合于高可用的redis集群,如果想要做到读写分离有两种办法:第一种找中间件,那样还不如用数据切片+codis第二种方法就得麻烦程序员了在查询(GET)和插入(SET)数据时分开写程序那样架构较为负载我上面的方法还不如不用既然都让客户端写程序指定了!

如果偏要使用也不是不可以这样的话有一台slave需要增加优先级数字比如调整到200那么这样可能会最后轮到这台slave变成主节点其他的slave优先级保持不动!

注意,上述讲的架构只能宕机一台(因为sentinel配置的是客观下线)如果配置为主观下线则可以宕机两台!还有此方法不适合用在不在同一网段的客户端访问,因为VIP没有配置网关(如果需要可以在脚本中再配置)。

Comments

Leave a Reply

Your email address will not be published. Name and email are required