跳到主要内容

Redis 主从 + Keepalived 高可用服务配置

IP角色
192.168.1.13redis Node01
192.168.1.14redis Node02
192.168.1.100VIP

配置 redis​

  1. 先参考 redis 主从文档完成部署

  2. 修改 Master 节点 redis.conf 文件,增加 slaveof 参数同步从节点

    slaveof 192.168.1.14 6379

配置 Keepalived​

安装 keepalived​

yum install -y keepalived

修改 keepalived 配置文件​

Redis Node01 节点​

修改 /etc/keepalived/keepalived.conf 文件内容如下

global_defs {
router_id hap-redis-ha-01
}

vrrp_script check_redis_health {
script "/usr/local/redis/script/check_redis_health.sh"
interval 10
}

vrrp_sync_group VG1 {
group {
VI_1
}
}

vrrp_instance VI_1 {
state BACKUP
interface eth0 # 修改为部署主机的网卡名称
virtual_router_id 180 # 同一子网上的所有 VRRP 路由器中唯一,范围0-255
priority 100 # 优先级,每个节点不同
advert_int 1
nopreempt
authentication {
auth_type PASS
auth_pass HAP-redis-Keepalived-Auth
}
track_script {
check_redis_health
}
notify_master /usr/local/redis/script/notify_master.sh
notify_backup /usr/local/redis/script/notify_backup.sh
virtual_ipaddress {
192.168.1.100 # VIP address
}
}
  • 注意两个节点配置文件中 priority 的值是不同的
  • 默认仅需修改 interface 与 VIP address 即可

Redis Node02 节点​

修改 /etc/keepalived/keepalived.conf 文件内容如下

global_defs {
router_id hap-redis-ha-01
}

vrrp_script check_redis_health {
script "/usr/local/redis/script/check_redis_health.sh"
interval 10
}

vrrp_sync_group VG1 {
group {
VI_1
}
}

vrrp_instance VI_1 {
state BACKUP
interface eth0 # 修改为部署主机的网卡名称
virtual_router_id 180 # 同一子网上的所有 VRRP 路由器中唯一,范围0-255
priority 90 # 优先级,每个节点不同
advert_int 1
nopreempt
authentication {
auth_type PASS
auth_pass HAP-redis-Keepalived-Auth
}
track_script {
check_redis_health
}
notify_master /usr/local/redis/script/notify_master.sh
notify_backup /usr/local/redis/script/notify_backup.sh
virtual_ipaddress {
192.168.1.100 # VIP address
}
}
  • 注意两个节点配置文件中 priority 的值是不同的
  • 默认仅需修改 interface 与 VIP address 即可

创建 redis 相关脚本​

两个节点都需要创建以下 redis 相关脚本

创建脚本存放目录

mkdir -p /usr/local/redis/script/

执行 vim /usr/local/redis/script/check_redis_health.sh 创建 redis 状态检查脚本

check_redis_health.sh 脚本内容如下:

#!/bin/bash

# Redis 相关信息
redis_cli="/usr/local/redis/bin/redis-cli"
redis_host="127.0.0.1"
redis_port="6379"
redis_password="123456"

# 日志函数
redis_keepalived_log_file="/var/log/redis_keepalived.log"
log_info() {
echo "$(date +"%Y-%m-%d %H:%M:%S") INFO: $1" >> "$redis_keepalived_log_file"
}

# 检查配置
max_retries=3
retry_interval=2

check_redis_status() {
# 检查 Redis 服务是否在运行中
$redis_cli -h $redis_host -p $redis_port -a $redis_password ping > /dev/null 2>&1
redis_status=$?
}

# 连续检查 Redis 服务状态,最多尝试 max_retries 次
retry_count=0
while true; do
check_redis_status

if [ $redis_status -eq 0 ]; then
# Redis 服务正常,退出循环
exit 0
else
if [ $retry_count -ge $max_retries ]; then
# 达到最大重试次数,执行停止 Keepalived 服务的操作并退出
log_info "After $max_retries retries, Redis remains unhealthy, stop Keepalived."
systemctl stop keepalived
exit 0
fi
fi

retry_count=$((retry_count + 1))
sleep $retry_interval
done

执行 vim /usr/local/redis/script/notify_master.sh 创建该节点 Keepalived 被选为 Master 时,Keepalived 所执行的脚本

notify_master.sh 脚本内容如下:

#!/bin/bash

# Redis 相关信息
redis_host="127.0.0.1"
redis_port="6379"
redis_password="123456"
redis_cli="/usr/local/redis/bin/redis-cli"
redis_config="/usr/local/redis/redis.conf"

# 日志函数
redis_keepalived_log_file="/var/log/redis_keepalived.log"
log_info() {
echo "$(date +"%Y-%m-%d %H:%M:%S") INFO: $1" >> "$redis_keepalived_log_file"
}

# 停止当前节点的同步线程
if $redis_cli -h $redis_host -p $redis_port -a $redis_password <<< "slaveof no one"; then
log_info "The current node becomes master, successfully stopped redis master-slave replication on the current node."
else
log_info "The current node becomes master, failed to stop redis master-slave replication on the current node."
fi

# 注释掉当前节点的 slaveof
if sed -i '/^slaveof/ s/^/#/' $redis_config; then
log_info "Successfully commented out the slaveof for the current node."
else
log_info "Failed to comment out the slaveof for the current node."
fi

执行 vim /usr/local/redis/script/notify_backup.sh 创建该节点 Keepalived 被选为 Backup 时,Keepalived 所执行的脚本

notify_backup.sh 脚本内容如下:

#!/bin/bash

# Redis 相关信息
redis_host="127.0.0.1"
redis_port="6379"
redis_password="123456"
redis_cli="/usr/local/redis/bin/redis-cli"
redis_config="/usr/local/redis/redis.conf"
redis_master_host="192.168.1.13"

# 日志函数
redis_keepalived_log_file="/var/log/redis_keepalived.log"
log_info() {
echo "$(date +"%Y-%m-%d %H:%M:%S") INFO: $1" >> "$redis_keepalived_log_file"
}

# 启动当前节点的同步线程
if $redis_cli -h $redis_host -p $redis_port -a $redis_password <<< "slaveof $redis_master_host 6379"; then
log_info "The current node becomes backup, successfully started redis master-slave replication on the current node."
else
log_info "The current node becomes backup, failed to start redis master-slave replication on the current node."
fi

# 打开当前节点的 slaveof 注释
if sed -i '/^#slaveof/ s/^#//' $redis_config; then
log_info "Successfully uncommented the slaveof configuration for the current node."
else
log_info "Failed to uncomment the slaveof configuration for the current node."
fi
  • redis_master_host 两个节点的配置文件中,这个变量值不是相同的,注意替换为另外一台 redis 的 IP 地址

给所有脚本添加可执行权限

chmod +x /usr/local/redis/script/*.sh

启动 Keepalived​

systemctl start keepalived
systemctl enable keepalived

测试​

可以通过重启 keepalived 来观察是否符合预期

正常现象:

  • VIP 所在节点,redis 为 master 状态, redis.conf 文件 slaveof 参数是注释的状态

  • 非 VIP 所在节点,redis 为 slave 同步状态, redis.conf 文件 slaveof 参数是非注释的状态

故障排除​

两台服务器都有 VIP​

通常可能受以下原因导致:

  • 两台机器之间有防火墙或其他网络限制

    • 限制了端口(默认使用 112 端口)

    • 网络环境不支持 VRRP(虚拟路由冗余协议)

  • 两台机器之间互相到对方地址网络不通

  • 两台节点配置的优先级可能一致,导致无法选举主节点

  • 可以通过 /var/log/messages 日志文件进行排查

两台服务器都没有 VIP​

通常可能受以下原因导致:

  • keepalived.conf 中指定的 vrrp_script 脚本文件执行异常,返回总是非0错误值导致keepalived 状态一直无法完成初始化,无法绑定vip

    • 比如 redis 未启动,或者脚本文件中连接 redis 的密码不对都有可能,也可以手动执行脚本进行排查
  • 可以通过 /var/log/messages 日志文件进行排查