Redis主从架构持久化存在一个问题,即前次测试的结论,持久化需要配置在主实例上才能跨越实例保证数据不丢失,这样以来主实例在持久化数据到硬盘的过程中,势必会造成磁盘的I/O等待,经过实际测试,这个持久化写硬盘的过程给应用程序带来的影响无法忍受;因而在大多数场景下,会考虑把持久化配置在从实例上,当主实例宕机后,通过手动或者自动的方式将从实例提升为主实例,继续提供服务!当主实例恢复后,先从原从实例上同步数据,同步完成后再恢复到原始的主从状态!要实现这种的要求,需要有keepalive的配合,一方面keepalive提供了VIP,可以避免修改应用程序连接,同时redis实例的配置文件监听部分也需要修改为全网监听;另一方面keepalive定时调度脚本来监控主从实例的状态,根据具体情况进行切换!本文将重点介绍下使用keepalive实现redis主从自动failover!
环境介绍
操作系统版本均为:Centos6.0 64bit
redis版本:2.6.4
redis实例端口均为:6379
VIP:172.16.1.200
主实例为Master-redis(172.16.1.170)
从实例为Slave-redis(172.16.1.171,开启快照持久化)
一:安装keepalive软件,server11安装完成后直接scp至server12上即可
[root@Master-redis ~]# wget http://keepalived.org/software/keepalived-1.1.19.tar.gz
[root@Master-redis ~]# tar zxf keepalived-1.1.19.tar.gz
[root@Master-redis ~]# cd keepalived-1.1.19/
[root@Master-redis keepalived-1.1.19]# ./configure --prefix=/usr/local/keepalived/ && make && make install
二:配置主节点Master-redis配置文件
[root@Master-redis ~]# cat /usr/local/keepalived/etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
router_id LVS_DEVEL
}
vrrp_script Monitor_redis {
script "/usr/local/scripts/redis_monitor.sh"
interval 2
weight 2
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 20
mcast_src_ip 172.16.1.170
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
track_script {
Monitor_redis
}
virtual_ipaddress {
172.16.1.200
}
notify_fault /usr/local/scripts/redis_fault.sh
notify_stop /usr/local/scripts/redis_stop.sh
三:配置从节点Slave-redis配置文件
四:准备相关的脚本,主从实例上都需要存在这些脚本,同时注意脚本需要由可执行权限
[root@Master-redis ~]# cat /usr/local/scripts/redis_monitor.sh
#!/bin/bash
ALIVE=`/usr/local/bin/redis-cli PING`
if [ "$ALIVE" == "PONG" ] ; then
echo $ALIVE
exit 0
else
echo $ALIVE
killall -9 keepalived
service network restart
exit 1
Fi
[root@Master-redis ~]# sh /usr/local/scripts/redis_monitor.sh
PONG
[root@Slave-redis ~]# cat /usr/local/scripts/redis_master.sh
#!/bin/bash
REDISCLI="/usr/local/bin/redis-cli -h 172.16.1.171"
LOGFILE="/usr/local/src/logs/keepalived-redis-state.log"
echo "[master]" >>$LOGFILE
date >>$LOGFILE
echo "Being master ...." >>$LOGFILE 2>&1
echo "Run SLAVEOF cmd...." >>$LOGFILE
echo "Run SLAVEOF NO ONE cmd.." >>$LOGFILE
$REDISCLI SLAVEOF NO ONE >>$LOGFILE 2>&1
[root@Slave-redis ~]# cat /usr/local/scripts/redis_backup.sh
#!/bin/bash
REDISCLI="/usr/local/bin/redis-cli -h 172.16.1.171"
LOGFILE="/usr/local/src/logs/keepalived-redis-state.log"
echo "[backup]" >>$LOGFILE
date >>$LOGFILE
echo "Being slave...." >>$LOGFILE 2>&1
sleep 15
echo "Run SLAVEOF cmd..." >>$LOGFILE
$REDISCLI SLAVEOF 172.16.1.170 6379 >>$LOGFILE 2>&1
[root@Slave-redis ~]# cat /usr/local/scripts/redis_stop.sh
#!/bin/bash
LOGFILE="/usr/local/src/logs/keepalived-redis-state.log"
echo "[stop]" >>$LOGFILE
date >>$LOGFILE
[root@Slave-redis ~]# cat /usr/local/scripts/redis_fault.sh
#!/bin/bash
LOGFILE="/usr/local/src/logs/keepalived-redis-state.log"
echo "[fault]" >> $LOGFILE
date >> $LOGFILE
五:主从实例分别启动keepalive进程,测试VIP是否正常
[root@Master-redis ~]# /usr/local/keepalived/sbin/keepalived -D -f /usr/local/keepalived/etc/keepalived/keepalived.conf
[root@Master-redis ~]# tail -f /var/log/messages
Jan 17 15:59:58 Master-redis Keepalived_healthcheckers: Configuration is using : 5707 Bytes
Jan 17 15:59:58 Master-redis Keepalived_healthcheckers: Using LinkWatch kernel netlink reflector...
Jan 17 15:59:58 Master-redis Keepalived_vrrp: VRRP_Script(Monitor_redis) succeeded
Jan 17 15:59:58 Master-redis Keepalived_vrrp: VRRP_Instance(VI_1) Transition to MASTER STATE
Jan 17 15:59:59 Master-redis Keepalived_vrrp: VRRP_Instance(VI_1) Entering MASTER STATE
Jan 17 15:59:59 Master-redis Keepalived_vrrp: VRRP_Instance(VI_1) setting protocol VIPs.
Jan 17 15:59:59 Master-redis Keepalived_vrrp: VRRP_Instance(VI_1) Sending gratuitous ARPs on eth0 for 172.16.1.200
Jan 17 15:59:59 Master-redis Keepalived_healthcheckers: Netlink reflector reports IP 172.16.1.200 added
Jan 17 15:59:59 Master-redis avahi-daemon[1240]: Registering new address record for 172.16.1.200 on eth0.IPv4.
Jan 17 16:00:02 Master-redis Keepalived_vrrp: VRRP_Instance(VI_1) Sending gratuitous ARPs on eth0 for 172.16.1.200
[root@Master-redis ~]# ip a | grep 172
inet 172.16.1.170/22 brd 172.16.3.255 scope global eth0
inet 172.16.1.200/32 scope global eth0
[root@Slave-redis ~]# /usr/local/keepalived/sbin/keepalived -D -f /usr/local/keepalived/etc/keepalived/keepalived.conf
[root@Slave-redis ~]# tail -f /var/log/messages
Jan 17 16:16:31 Slave-redis Keepalived: Starting VRRP child process, pid=11377
Jan 17 16:16:31 Slave-redis Keepalived_vrrp: Registering Kernel netlink reflector
Jan 17 16:16:31 Slave-redis Keepalived_vrrp: Registering Kernel netlink command channel
Jan 17 16:16:31 Slave-redis Keepalived_vrrp: Registering gratutious ARP shared channel
Jan 17 16:16:31 Slave-redis Keepalived_vrrp: Opening file '/usr/local/keepalived/etc/keepalived/keepalived.conf'.
Jan 17 16:16:31 Slave-redis Keepalived_vrrp: Configuration is using : 64882 Bytes
Jan 17 16:16:31 Slave-redis Keepalived_vrrp: Using LinkWatch kernel netlink reflector...
Jan 17 16:16:31 Slave-redis Keepalived_vrrp: VRRP_Instance(VI_1{) Entering BACKUP STATE
Jan 17 16:16:31 Slave-redis Keepalived_vrrp: VRRP sockpool: [ifindex(2), proto(112), fd(9,10)]
Jan 17 16:16:31 Slave-redis Keepalived_vrrp: VRRP_Script(Monitor_redis) succeeded
[root@Master-redis ~]# redis-cli -h 172.16.1.200 info | grep -A 3 'Replication'
# Replication
role:master
connected_slaves:1
slave0:172.16.1.171,6379,online
六:主实例写入测试数据
[root@Master-redis ~]# for i in {1..10000}
> do
> redis-cli -h 172.16.1.200 set $i abc
> done
[root@Master-redis ~]# redis-cli -h 172.16.1.200 info
# Keyspace
db0:keys=10673,expires=0
[root@Master-redis data]# ls -lh
总用量 1.4M
-rw-r--r-- 1 root root 883K 1月 17 14:33 appendonly.aof
-rw-r--r-- 1 root root 472K 1月 17 15:58 dump.rdb
[root@Slave-redis data]# ls -lh
total 1.6M
-rw-r--r-- 1 root root 883K Jan 17 15:59 appendonly.aof
-rw-r--r-- 1 root root 472K Jan 17 15:59 dump.rdb
七:模拟主实例故障,观察日志输出,验证从实例是否能成功接管VIP,同时将实例变成读写模式
[root@Master-redis ~]# killall redis-server
[root@Master-redis ~]# ip a | grep 172
inet 172.16.1.170/22 brd 172.16.3.255 scope global eth0
[root@Master-redis ~]# ps -ef | grep redis-server
root 32461 32379 0 16:23 pts/1 00:00:00 grep --color=auto redis-server
[root@Master-redis ~]# ps -ef | grep keepalived
root 32500 32379 0 16:24 pts/1 00:00:00 grep --color=auto keepalived
[root@Slave-redis data]# tail -f /usr/local/src/logs/keepalived-redis-state.log
OK
Run SLAVEOF NO ONE cmd..
OK
[master]
Thu Jan 17 16:22:25 CST 2013
Being master ....
Run SLAVEOF cmd....
Could not connect to Redis at 172.16.1.170:6379: Connection refused
Run SLAVEOF NO ONE cmd..
Could not connect to Redis at 172.16.1.170:6379: Connection refused
[root@Slave-redis data]# tail -f /var/log/messages
Jan 17 16:16:31 Slave-redis Keepalived_vrrp: Using LinkWatch kernel netlink reflector...
Jan 17 16:16:31 Slave-redis Keepalived_vrrp: VRRP_Instance(VI_1{) Entering BACKUP STATE
Jan 17 16:16:31 Slave-redis Keepalived_vrrp: VRRP sockpool: [ifindex(2), proto(112), fd(9,10)]
Jan 17 16:16:31 Slave-redis Keepalived_vrrp: VRRP_Script(Monitor_redis) succeeded
Jan 17 16:22:24 Slave-redis Keepalived_vrrp: VRRP_Instance(VI_1{) Transition to MASTER STATE
Jan 17 16:22:25 Slave-redis Keepalived_vrrp: VRRP_Instance(VI_1{) Entering MASTER STATE
Jan 17 16:22:25 Slave-redis Keepalived_vrrp: VRRP_Instance(VI_1{) setting protocol VIPs.
Jan 17 16:22:25 Slave-redis Keepalived_vrrp: VRRP_Instance(VI_1{) Sending gratuitous ARPs on eth0 for 172.16.1.200
Jan 17 16:22:25 Slave-redis avahi-daemon[1259]: Registering new address record for 172.16.1.200 on eth0.IPv4.
Jan 17 16:22:30 Slave-redis Keepalived_vrrp: VRRP_Instance(VI_1{) Sending gratuitous ARPs on eth0 for 172.16.1.200
[root@Slave-redis data]# ip a | grep 172
inet 172.16.1.171/22 brd 172.16.3.255 scope global eth0
inet 172.16.1.200/32 scope global eth0
[root@Slave-redis data]# redis-cli -h 172.16.1.200 info | grep -A 3 'Replication'
# Replication
role:slave
master_host:172.16.1.170
master_port:6379
九:主实例角色的恢复过程,使用shell脚本自动恢复
[root@Slave-redis ~]# cat /usr/local/scripts/remover_master.sh
#!/bin/sh
ALIVE=`/usr/local/bin/redis-cli -h 171.16.1.170 -p 6379 PING`
MDB=/usr/local/src/data/dump.rdb
SDB=/usr/local/src/data/
if [ "$ALIVE" == "PONG" ]; then
echo $ALIVE
scp $MDB [email protected]:$SDB
else
echo $ALIVE
exit 1
fi
redis-server /etc/redis.conf
/usr/local/keepalived/sbin/keepalived -D -f /usr/local/keepalived/etc/keepalived/keepalived.conf