Redis高可用之 redis+sentinel(脚本自动切换VIP)

redis集群实现有以下几种方式:
1.redis-cluster, 官方提供的集群搭建方案(过于重量级,比较适合后期数据量较大的时候的使用)
2.redis+keepalive 虚拟IP,多台配置非常复杂,不宜维护,需要 slaveof no one 脚本
3.redis+zookeeper 需要引入zookeeper,对现有代码变动较大
4.redis+sentinel redis自带监控中间件
本篇实现 redis+sentinel 星形架构
实验环境需要四台Redis服务器
192.168.10.11 redis11 主
192.168.10.12 redis12 从
192.168.10.13 redis13 从
192.168.10.14 redis14 从
192.168.10.100 VIP
使用后端模板创建四台虚拟机
[root@client 桌面]# cd /var/lib/libvirt/images/
[root@client images]# for i in {1..4}
> do
> qemu-img create -b centos7.qcow2 -f qcow2 redis$i.qcow2
> done
[root@client images]# cd /etc/libvirt/qemu/
[root@client qemu]# for i in {1..4}
> do
> virsh dumpxml centos7 > redis$i.xml
> done
[root@client qemu]# vim redis1.xml
<name>redis1</name> //修改名称
....
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2'/>
<source file='/var/lib/libvirt/images/redis1.qcow2'/> //修改前端镜像文件路径
<target dev='vda' bus='virtio'/>
</disk>
....
:g/add/d //删除add个性化参数
启用虚拟机并配置网络参数一次配置四台redis
[root@client qemu]# for i in {1..4}
> do
> virsh define redis$i.xml
> done
定义域 redis1(从 redis1.xml)
....
[root@client qemu]# for i in {1..4}; do virsh start redis$i; done
域 redis1 已开始
....
[root@client qemu]# for i in {1..4}; do virsh console redis$i; done
[root@localhost ~]# vim /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE="eth0"
ONBOOT="yes"
IPV6INIT="no"
TYPE="Etnernet"
BOOTPROTO="static"
IPADDR=192.168.10.11
PREFIX=24
GATEWAY=192.168.10.254
[root@localhost ~]# systemctl restart network
[root@localhost ~]# hostnamectl set-hostname redis11
四台节点配置host、yum、ssh秘钥这里不再演示
[root@redis11 ~]# for i in {11..14}
> do
> ssh redis$i yum -y install gcc gcc-c++ make //所有节点安装依赖包
> done
部署master主机 192.168.10.11
[root@redis11 ~]# tar -xf redis-3.2.11.tar.gz
[root@redis11 ~]# cd redis-3.2.11
[root@redis11 redis-3.2.11]# make && make install //安装编译redis
[root@redis11 redis-3.2.11]# cd utils/
[root@redis11 utils]# ./install_server.sh //初始化redis
....
Starting Redis server...
Installation successful!
修改redis运行参数
[root@redis11 utils]# /etc/init.d/redis_6379 stop
....
bind 192.168.10.11 //修改成本机IP
修改启动脚本
[root@redis11 utils]# vim /etc/init.d/redis_6379
....
IP="192.168.10.11"
...
PID=$(cat $PIDFILE)
echo "Stopping ..."
$CLIEXEC -h $IP -p $REDISPORT shutdown //添加主机IP
while [ -x /proc/${PID} ]
do
[root@redis11 utils]# /etc/init.d/redis_6379 start //启动服务并确认端口
Starting Redis server...
[root@redis11 utils]# ss -ntulp | grep 6379
tcp LISTEN 0 128 192.168.10.11:6379 *:* users:(("redis-server",pid=13531,fd=4))
[root@redis11 utils]# redis-cli -h 192.168.10.11 -p 6379 //登录查看服务运行状态
192.168.10.11:6379> PING
PONG
192.168.10.11:6379> info replication
role:master //角色master
connected_slaves:0 //没有slave
部署slave主机(安装步骤与上述相同)
[root@redis12 utils]# /etc/init.d/redis_6379 stop
[root@redis12 utils]# vim /etc/redis/6379.conf
....
bind 192.168.10.12 //本机ip
slaveof 192.168.10.11 6379 //master主机 ip 端口
[root@redis12 utils]# vim /etc/init.d/redis_6379 //修改启动脚本
....
IP="192.168.10.12"
$CLIEXEC -h $IP -p $REDISPORT shutdown
[root@redis12 utils]# /etc/init.d/redis_6379 start
Starting Redis server...
[root@redis12 utils]# ss -netstat | grep 6379
[root@redis12 utils]# redis-cli -h 192.168.10.12 -p 6379 //登录查看状态
192.168.10.12:6379> PING
PONG
192.168.10.12:6379> INFO replication
#Replication
role:slave //角色slave
master_host:192.168.10.11 //谁是master
master_port:6379
master_link_status:up
依次启动另外两台slave主机与上述配置相同
登录主库查看slave状态
[root@redis11 utils]# redis-cli -h 192.168.10.11 -p 6379 -a 123456
192.168.10.11:6379> info replication
#Replication
role:master
connected_slaves:3 //已显示三台从库信息
slave0:ip=192.168.10.12,port=6379,state=online,offset=2003,lag=0
slave1:ip=192.168.10.13,port=6379,state=online,offset=2003,lag=0
slave2:ip=192.168.10.14,port=6379,state=online,offset=2003,lag=0
部署sentinel
[root@redis11 ~]# cp /root/redis-3.2.11/sentinel.conf /etc/redis/
[root@redis11 ~]# vim /etc/redis/sentinel.conf
....
bind 0.0.0.0
port 26379
protected-mode no
daemonize yes
dir /tmp
sentinel monitor mymaster 192.168.10.11 6379 2 //master ip 票数
sentinel down-after-milliseconds mymaster 3000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 5000
sentinel client-reconfig-script mymaster /usr/local/bin/reconfig.sh //开启故障切换脚本
[root@redis11 ~]# grep -Pv "^(#|$)" /etc/redis/sentinel.conf //确认配置参数
bind 0.0.0.0
port 26379
protected-mode no
....
将sentinel配置文件拷贝到所有slave节点
[root@redis11 ~]# for i in {12..14}
> do
> scp /etc/redis/sentinel.conf redis$i:/etc/redis/
> done
在所有redis服务器上添加脚本文件
[root@redis11 ~]# cat > /usr/local/bin/reconfig.sh << EOF
> #!/bin/bash
> echo "$@" > /tmp/redis.log //收集切换信息
> EOF
[root@redis11 ~]# chmod 755 /usr/local/bin/reconfig.sh
在所有redis主机启动sentinel监控
[root@redis11 ~]# /usr/local/bin/redis-sentinel /etc/redis/sentinel.conf
[root@redis11 ~]# ss -ntulp | grep 26379
tcp LISTEN 0 128 *:26379 *:* users:(("redis-sentinel",pid=13747,fd=4))
[root@redis11 ~]# redis-cli -h 192.168.10.11 -p 26379
192.168.10.11:26379> PING
PONG
192.168.10.11:26379> INFO sentinel
#Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.10.11:6379,slaves=3,sentinels=4 //状态slave3台 sentinel四台
测试主从切换—将master主机宕机之后查看主从状态
192.168.10.11:6379> shutdown
[root@redis11 ~]# cat /tmp/redis.log //查看监本日志
mymaster observer start 192.168.10.11 6379 192.168.10.14 6379 //master已经切换到 192.168.10.14 这台主机
登录redis14 查看状态
[root@redis14 ~]# redis-cli -h 192.168.10.14 -p 6379
192.168.10.14:6379> INFO replication
#Replication
role:master //角色已经切换成master
connected_slaves:2 //还有两台从库
slave0:ip=192.168.10.12,port=6379,state=online,offset=34337,lag=1
slave1:ip=192.168.10.13,port=6379,state=online,offset=34337,lag=0
恢复redis11主机并加入集群
[root@redis11 ~]# /etc/init.d/redis_6379 start
再次查看redis14主机状态
192.168.10.14:6379> INFO replication
#Replication
role:master
connected_slaves:3 //三台slave,redis11主机已加入集群
slave0:ip=192.168.10.12,port=6379,state=online,offset=86514,lag=1
slave1:ip=192.168.10.13,port=6379,state=online,offset=86514,lag=1
slave2:ip=192.168.10.11,port=6379,state=online,offset=86655,lag=1
问题:
客户端程序(如PHP程序)连接redis时需要ip和port,但redis-server进行故障转移时,主是变化的,所以ip地址也是变化的
客户端程序如何感知当前主redis的ip地址和端口呢?
redis-sentinel提供了接口,请求任何一个sentinel,发送SENTINEL get-master-addr-by-name 就能得到当前主redis的ip和port。
解决方案1:
程序兼容,优势:扩展性好,运维成本低
劣势:开发成本高,连接变成 2 次
解决方案2:
vip 漂移,优势:程序端无感知,架构不需要改变
劣势:集群庞大时配置管理复杂,运维成本高
方案2:
增加配置切换脚本 sentinel.conf
sentinel client-reconfig-script mymaster /usr/local/redis/conf/reconfig.sh
在redis任意主机创建vip自动切换脚本并同步到其他主机(删除原脚本内容)
[root@redis11 ~]# > /usr/local/bin/reconfig.sh
[root@redis11 ~]# vim /usr/local/bin/reconfig.sh
#!/bin/bash
#args=(<master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>)
#mymaster leader start old.ip old.port new.ip new.port
logger -p local0.info -t redis "${@:-NULL}"
vip="192.168.10.100/24"
read oldip newip <<<"$4 $6"
if $(ip -o a s |grep -q ${oldip:-0.0.0.0});then
/usr/sbin/ifconfig eth0:1 down &>/dev/null
elif $(ip -o a s|grep -q ${newip:-0.0.0.0});then
/usr/sbin/ifconfig eth0:1 ${vip}
/sbin/arping -q -c 3 -A ${vip%/*} -I eth0
fi
同步脚本到其他主机
[root@redis11 ~]# for i in {12..14}
> do
> scp /usr/local/bin/reconfig.sh redis$i:/usr/local/bin/
> done
在master主机部署VIP 192.168.10.100 (宕机并查看vip切换状态)
[root@redis14 ~]# ifconfig eth0:1 192.168.10.100/24
[root@redis14 ~]# ifconfig eth0:1
eth0:1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.10.100 netmask 255.255.255.0 broadcast 192.168.10.255
ether 52:54:00:3a:1b:34 txqueuelen 1000 (Ethernet)
[root@redis14 ~]# ifconfig eth0:1
eth0:1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.10.100 netmask 255.255.255.0 broadcast 192.168.10.255
ether 52:54:00:57:e8:ab txqueuelen 1000 (Ethernet)
[root@redis14 ~]# /etc/init.d/redis_6379 stop //将redis14宕机后再次查看vip已经不存在(vip漂移时间在3~5秒左右)
查找到master主机后ifconfig查看vip已经绑定上(这里不做过多演示)




更多推荐
所有评论(0)