前提:
centos7,所有操作在root用户下进行
Redis server 版本 6.2.4
keepalived + redis高可用主备
一、rpm安装keepalived
1、rpm -ivh mysql-community-common-5.7.9-1.el7.x86_64.rpm
2、rpm -ivh mysql-community-libs-5.7.9-1.el7.x86_64.rpm
3、rpm -ivh mysql-community-libs-compat-5.7.22-1.el7.x86_64.rpm
4、rpm -ivh net-snmp-agent-libs-5.7.2-49.el7_9.1.x86_64.rpm
5、rpm -ivh keepalived-1.3.5-19.el7.x86_64.rpm
6、设置开机自启 systemctl enable keepalived.service
7、启动 systemctl start keepalived
关闭 systemctl stop keepalived
重启 systemctl restart keepalived
rpm安装包下载地址:https://download.csdn.net/download/linhan007/20598357
不同的系统,可能稍有区别,安装过程中如有缺少的库,可到此网站下载:https://centos.pkgs.org/
二、新建目录
mkdir -p /usr/local/keepalived/var/log 放日志文件
mkdir -p /usr/local/keepalived/scripts/redis 放脚本文件
三、先决条件
(一)关闭selinux
(1)暂时调试,可临时关闭
setenforce 0
(2)不过长期运行,特别是重启后自动运行,还是要永久关闭才行
sed -i "s/^SELINUX=.*/SELINUX=disabled/g" /etc/selinux/config
记得重启电脑
(二)清除iptables规则
就算因某种原因不能清除iptables规则,那么你需要增加一条规则放行多播。
确保Keepalive使用的网卡开启了多播,如下图:
(三)关闭防火墙
如果虚拟IP在每台主机上都生效,说明广播被防火墙拦截了
(四)各个节点时间同步,
启用时间同步服务 systemctl start chronyd
四、配置文件和脚本
用于演示的两台主台ip分别是 :
192.168.171.150,默认为master;
192.168.171.160,默认为slave;
虚拟飘移vip是192.168.171.100
配置文件和脚本打包下载地址:
https://download.csdn.net/download/linhan007/20600223
(一)keepalived.conf配置文件
放到/etc/keepalived/keepalived.conf路径下
1.150上的配置文件
global_defs {
router_id dhbt-redis-master
script_user root
enable_script_security
}
vrrp_script chk_redis
{
#监控脚本
script "/usr/local/keepalived/scripts/redis/redis_check.sh"
#监控时间,脚本的执行时间间隔
interval 2
#超时时间
timeout 2
weight -15
#3次失败才算失败,会用weight减少优先级(1-255之间)
fall 3
#1次成功就算成功,但不修改优先级
rise 1
}
vrrp_instance VI_1 {
#设置为BACKUP
state BACKUP
#本机监控网卡
interface ens33
# garp_master_delay 10
#主从需要在同一路由编号
virtual_router_id 55
#权重值
priority 100
#不抢占
nopreempt
#vrrp通告的时间间隔,默认1s
advert_int 5
authentication {
#加密
auth_type PASS
#密码
auth_pass dhbt
}
virtual_ipaddress {
#Keppalived虚拟出来的VIP
192.168.171.100
}
track_script {
chk_redis
}
#keepalived成为master
notify_master /usr/local/keepalived/scripts/redis/redis_master.sh
#keepalived成为backup
notify_backup /usr/local/keepalived/scripts/redis/redis_slave.sh
#keepalived fault时
notify_fault /usr/local/keepalived/scripts/redis/redis_fault.sh
#keepalived服务中止时
notify_stop /usr/local/keepalived/scripts/redis/redis_stop.sh
}
注意:
(1)脚本所在路径,默认为第二章节所建目录;如放到其它目录,切记要修改;
(2)本机监控网卡名称,要和本机相符,否则切记要修改;
(3)vip,切记要改为主机实际IP同网段的ip;
(4)keepalived启动后,由于设置了不抢占,则起始状态都是backup;会先调用redis_slave.sh;
设置了advert_int 5,默认检测三次,所以15秒之后才向master转变,为什么设置间隔这么长时间呢?是为了让redis_backup.sh脚本有充足的时间执行完毕。之后转变为master状态,这时才执行redis_master.sh脚本。
2.160上的配置文件
除了以下几点,其它和150上完全一致
(1)router_id dhbt-redis-slave
(2)state BACKUP #设置为BACKUP
(3)priority 90 #权重值
3.说明
主备的state配置的都是BACKUP,并且nopreempt非抢占,这样priority和weight就无用了,不是谁的权重大谁为主,keepalived不会竞争并主动切换主从;这样从而可以防止redis的无谓切换,以免影响数据稳定性。
不过需要在redis_check.sh中,检测到redis故障后,同时退出keepalived(会调用redis_stop.sh,在此脚本中把redis切为从); 以此保证对机可以切为主(不是竞争获得的主,而是一个keepalived死后,剩下的一个自动升为主),从而调用redis_master.sh
state是BACKUP,并且nopreempt非抢占,则keepalived重启后,会先为从,如网段内无其它keepalived存活,再切为主;
比如开始150是主,160是备:
1.如160上的redis异常,150无影响;
160上redis_check.sh退出keepalived;160守护进程或手动重启redis和keepalived,切 为从;
2.如150上的redis异常,则redis_check.sh会关闭keepalived;
160上的keepalived切为主,调用redis_master.sh,redis切为主;
150上守护进程或手动重启redis和keepalived,切为从;
(二)脚本文件
shell脚本文件全部放在第二章节中所建目录下:/usr/local/keepalived/scripts/redis
在150与160上都要以下五个脚本,并给脚本都加上可执行权限:
chmod +x /usr/local/keepalived/scripts/redis/*
不要权限777或744,否则日志中会报脚本不安全
1.redis_check.sh 主备两机一致
#!/bin/bash
ALIVE=`/home/uiot_core/bin/redis/redis-cli -p 6339 PING`
LOGFILE="/usr/local/keepalived/var/log/keepalived-redis-state.log"
if [ "$ALIVE" == "PONG" ]; then
echo $ALIVE
exit 0
else
echo $ALIVE
#可确保让出MASTER
systemctl stop keepalived
killall -9 keepalived
exit 1
fi
注意:redis-cli和端口,及日志路径,要根据实际配置;
如果redis异常,则keepalived会自身退出;
所以无人值守的项目应用时,需要对redis和keepalived守护运行;
不管手动启,还是守护运行,必须需要先启动redis,再启动keepalvied;
2.redis_master.sh
150上的脚本如下编写:
!/bin/bash
REDISCLI="/home/uiot_core/bin/redis/redis-cli -p 6339"
LOGFILE="/usr/local/keepalived/var/log/keepalived-redis-state.log"
echo "[master]" >> $LOGFILE
date >> $LOGFILE
echo "Being master...." >> $LOGFILE 2>&1
echo "Run [SLAVEOF 192.168.171.160 6339] cmd ..." >> $LOGFILE
$REDISCLI SLAVEOF 192.168.171.160 6339 >> $LOGFILE 2>&1
#延迟10秒以后待数据同步完成后再取消同步状态
sleep 10
date >> $LOGFILE
echo "Run [SLAVEOF NO ONE] cmd ..." >> $LOGFILE
$REDISCLI SLAVEOF NO ONE >> $LOGFILE 2>&1
注意:redis-cli和端口,及日志路径,要根据实际配置。
160上的脚本,把150上脚本中的ip改为192.168.171.150即可,其它一致;
也就是说要填写对方主机的ip;
3.redis_slave.sh
150上的脚本如下编写:
#!/bin/bash
REDISCLI="/home/uiot_core/bin/redis/redis-cli -p 6339"
LOGFILE="/usr/local/keepalived/var/log/keepalived-redis-state.log"
echo "[backup]" >> $LOGFILE
date >> $LOGFILE
echo "Being slave...." >> $LOGFILE 2>&1
#延迟13秒待数据被对方同步完成之后再切换主从角色
sleep 13
date >> $LOGFILE
echo "Run [SLAVEOF 192.168.171.160 6339] cmd ..." >> $LOGFILE
$REDISCLI SLAVEOF 192.168.171.160 6339 >> $LOGFILE 2>&1
注意:redis-cli和端口,及日志路径,要根据实际配置。
160上的脚本,把150上脚本中的ip改为192.168.171.150即可,其它一致;
也就是说要填写对方主机的ip;
4.redis_fault.sh 主备两机一致
#!/bin/bash
LOGFILE="/usr/local/keepalived/var/log/keepalived-redis-state.log"
echo "[fault]" >> $LOGFILE
date >> $LOGFILE
sh /usr/local/keepalived/scripts/redis/redis_slave_now.sh
注意:redis-cli和端口,及日志路径,要根据实际配置
5.redis_stop.sh 主备两机一致
#!/bin/bash
LOGFILE="/usr/local/keepalived/var/log/keepalived-redis-state.log"
echo "[stop]" >> $LOGFILE
date >> $LOGFILE
sh /usr/local/keepalived/scripts/redis/redis_slave_now.sh
注意:红色字体的redis-cli和端口,及日志路径,要根据实际配置;
6.redis_slave_now.sh
150上的脚本如下编写:
!/bin/bash
REDISCLI="/home/uiot_core/bin/redis/redis-cli -p 6339"
LOGFILE="/usr/local/keepalived/var/log/keepalived-redis-state.log"
echo "[backup now]" >> $LOGFILE
date >> $LOGFILE
echo "Being slave...." >> $LOGFILE 2>&1
echo "Run [SLAVEOF 192.168.171.160 6339] cmd ..." >> $LOGFILE
$REDISCLI SLAVEOF 192.168.171.160 6339 >> $LOGFILE 2>&1
注意:redis-cli和端口,及日志路径,要根据实际配置;
160上的脚本,把150上脚本中的ip改为192.168.171.150即可,其它一致;
主要用于keepalved异常或退出时,把本机redis同时切换为从;
五、测试
(一)查看keepalvied最新运行日志信息以助调试
执行命令:tail -f /var/log/messages
(1)redis_check.sh中redis_cli的路径错误时,日志如下
(2)redis_check.sh中redis_cli的路径正确,redis服务启动时
可看到 priority权重和keepalvied.conf中配置的一致,不变;
因为script中的weight配的是-15;详见:
https://blog.csdn.net/HzSunshine/article/details/62041036
(3)redis服务退出时
(二)如果报脚本不安全和禁止执行
global_defs {
router_id dhbt-redis-master
script_user root
enable_script_security
}
配置文件中script_user要配root;因为所有操作都是在root下进行的。
否则keepalived日志中会报以下错误,脚本会禁止执行
(三)飘移vip
在终端用 ***ip add***命令查看。
150查看如下:
160查看如下:
结论:此时ip飘移在150上,即150上的keepalived是master,理论此时其上的redis也是master。
在redis客户端用命令 info replication查看其状态
150上的redis:
160上的redis:
(四)测试用例和结果
测试结果可用以下方法验证:
1.终端输入命令 ip a,看vip飘移到哪个主机上,则其为master
2.redis的连接客户端输入命令info replication,直接查看redis的主备
3.查看脚本运行的日志文件 cat /usr/local/keepalived/var/log/keepalived-redis-state.log
注意:keepalved的停止要用systemctl stop keepalived,不要用service keepalved stop,否则不会触发notify_stop
redis_check.sh在检测到redis失败时,会停止keepalived,所以需要再守护keepalived和redis;
这样如果redis一直启动失败,一直没有运行,那么keepalived会一直重启;
也可以手动启keepalived
六、如何实现自动竞争
(一)150上的修改
1.keepalived.conf
如下,state改为MASTER;屏蔽nopreempt即可;keepalived默认是开启nopreempt的。
2.redis_check.sh
如下,检测到redis异常后,屏蔽掉退出keepalvied的脚本
(二)160上的修改
1、keepalived.conf
state改为BACKUP;屏蔽nopreempt;
2、redis_check.sh
和150上一致即可;
(三)分析
150上的redis故障后,权重从100下降到85;此时160上权重还是90,则抢占为主,redis也切为主;
此后150上的redis恢复后,权重从85上升到100,大于160的90,抢占为主,则redis也切为主;
这样会造成redis无谓切换,有可能会丢失数据,影响uiot稳定运行;