Keepalived 配置文件详解
本文以 MySQL 高可用场景为例,完整讲解 Keepalived 唯一配置文件
/etc/keepalived/keepalived.conf的三个核心区块,以及配套的外部脚本文件。
1. 配置文件整体结构
Keepalived 只有一个主配置文件:
/etc/keepalived/keepalived.conf
文件内部由三个区块组成,各司其职:
| 区块 | 作用 | 是否必须 |
|---|---|---|
global_defs |
全局背景配置,整个进程共用 | 否 |
vrrp_script |
定义健康检测脚本的执行规则 | 建议有 |
vrrp_instance |
定义 VIP 的管理逻辑,核心区块 | 必须 |
三者的关系是:vrrp_instance 是真正干活的核心,vrrp_script 是被它引用的工具,global_defs 是两者共用的公共背景。

图1 :三个区块关系总览。注意
vrrp_script只是定义,必须在vrrp_instance的track_script中引用才会执行。
2. global_defs --- 全局配置
global_defs 配置整个 Keepalived 进程的公共属性,与 VIP 管理逻辑无关,可以理解为"机器的自我介绍"。
nginx
global_defs {
# 本节点的唯一标识名,出现在日志和告警邮件中
# 两台机器写不同的名字,方便区分
router_id MySQL_HA_Master
# 故障时发送告警邮件(可选)
notification_email {
ops@example.com
dba@example.com
}
notification_email_from keepalived@example.com
smtp_server 127.0.0.1
smtp_connect_timeout 30
# 执行 vrrp_script 脚本时使用的系统用户
script_user root
# 安全模式:防止脚本文件被非授权用户篡改
# 开启后脚本文件的 owner 必须是 script_user,且不能有 group/other 写权限
enable_script_security
}
缺少 global_defs 的影响:不影响 VIP 切换功能,只是没有节点标识和邮件告警。生产环境建议配置,方便日志排查。
3. vrrp_script --- 健康检测脚本定义
vrrp_script 定义"如何检测 MySQL 是否健康"以及"检测结果如何影响本节点的选举优先级"。
nginx
vrrp_script check_mysql {
# 要执行的脚本路径
# 脚本返回 0 = 正常,返回非 0 = 故障
script "/etc/keepalived/check_mysql.sh"
# 每隔 2 秒执行一次检测
interval 2
# 单次脚本执行超时时间(秒)
# 超时视为失败,建议设为 interval 的 2 倍以上
timeout 5
# 连续失败 2 次,才触发 weight 扣分(防止偶发抖动误切换)
fall 2
# 连续成功 1 次,即恢复正常状态
rise 1
# 检测失败时,将本节点优先级降低 30 分
# 负数表示失败时扣分;绝对值必须大于两台 priority 的差值
weight -30
}

图2 :
vrrp_script各参数作用说明。
3.1 weight 的计算逻辑
Keepalived 选举 MASTER 时,使用的不是配置文件里写死的 priority,而是实际优先级:
实际优先级 = priority + 所有 track_script 的 weight 叠加值
- 检测正常时,weight 不生效(视为 0),实际优先级 = priority
- 检测失败时,实际优先级 = priority + weight(负数即为减法)

图3:三种场景下优先级的实际计算过程,以及 weight 设置错误导致 VIP 无法切换的反例。
常见陷阱 :weight 的绝对值必须大于两台机器 priority 的差值,否则主节点故障后实际优先级仍然高于备节点,VIP 不会切换。
主节点 priority = 100,备节点 priority = 90,差值 = 10
错误示例:weight = -5
主节点故障:100 - 5 = 95,备节点:90
95 > 90,VIP 不切换!
正确示例:weight = -30
主节点故障:100 - 30 = 70,备节点:90
70 < 90,备节点接管 VIP ✓
推荐配置:主 priority=100,备 priority=90,weight=-30,留出足够裕量。
3.2 更简单的替代方案
生产中很多团队干脆不依赖 weight 数值计算,检测失败时直接停掉 keepalived 进程,强制触发切换,逻辑更直接:
bash
# check_mysql.sh
mysql -e "SELECT 1" > /dev/null 2>&1
if [ $? -ne 0 ]; then
systemctl stop keepalived # 直接停进程,备节点必然接管
exit 1
fi
exit 0
4. vrrp_instance --- VRRP 实例(核心)
vrrp_instance 是整个配置文件的核心,它定义"负责管理哪个 VIP"以及"如何与对端机器协商 MASTER 角色"。
nginx
vrrp_instance VI_MYSQL {
# ── 角色与网卡 ──────────────────────────────────
# 初始角色。配合 nopreempt 使用时,两台机器都写 BACKUP
# 由 priority 决定谁在启动时先成为 MASTER
state BACKUP
# VIP 绑定在哪张网卡上,用 "ip a" 命令确认网卡名
# 常见名称:eth0、ens33、enp0s3
interface eth0
# ── VRRP 组标识 ──────────────────────────────────
# 虚拟路由器组编号,范围 1-255
# ★ 同组的两台机器必须填写完全相同的数字
# ★ 不同业务使用不同编号,互不干扰
virtual_router_id 51
# ── 优先级 ───────────────────────────────────────
# 基础优先级,结合 weight 计算实际优先级
# 主节点写 100,备节点写 90
priority 100
# VRRP 心跳发送间隔(秒),默认 1s
advert_int 1
# ── 抢占控制 ──────────────────────────────────────
# 禁止高优先级节点恢复后自动抢回 VIP
# 防止主节点恢复时造成二次业务中断
# 只在 state BACKUP 时生效
nopreempt
# ── 认证 ─────────────────────────────────────────
# ★ 同组两台机器必须使用完全相同的认证配置
authentication {
auth_type PASS
auth_pass mysql_ha_2024
}
# ── VIP 地址 ──────────────────────────────────────
# 要管理的虚拟 IP,可以写多个
virtual_ipaddress {
192.168.1.100/24 dev eth0 label eth0:vip
}
# ── ARP 优化 ──────────────────────────────────────
# 成为 MASTER 后延迟 1s 发送免费 ARP(等网卡就绪)
garp_master_delay 1
# 连续发送 3 次 ARP,提高到达率
garp_master_repeat 3
# 每 10s 刷新一次 ARP,防止缓存过期
garp_master_refresh 10
# ── 引用检测脚本 ───────────────────────────────────
# ★ 必须在这里引用,vrrp_script 定义的脚本才会被执行
# 可以引用多个脚本,weight 值会叠加计算
track_script {
check_mysql
}
# ── 状态变更通知 ───────────────────────────────────
# 每次在 MASTER / BACKUP / FAULT 之间切换时调用
# 接收参数:$1=TYPE $2=NAME $3=STATE
notify /etc/keepalived/notify.sh
}
4.1 virtual_router_id 的作用
virtual_router_id 是两台机器互相识别的"暗号"。只有相同 ID 的节点才会互发 VRRP 心跳、参与同一个选举组。不同 ID 的实例之间完全隔离,互不感知。
4.2 一台机器运行多个实例
一台机器上可以同时定义多个 vrrp_instance,每个实例独立管理一个 VIP,可以实现"主机跑 MySQL 的 MASTER,同时跑 Redis 的 BACKUP",充分利用两台机器的资源。

图4:两台机器各运行两个实例,MySQL VIP 在主机,Redis VIP 在备机,两台机器同时承载业务,资源利用率翻倍。
对应配置示例:
nginx
# 主机配置片段
vrrp_instance VI_MYSQL {
virtual_router_id 51
priority 100 # MySQL 这里是 MASTER
virtual_ipaddress { 192.168.1.100/24 }
track_script { check_mysql }
}
vrrp_instance VI_REDIS {
virtual_router_id 52
priority 90 # Redis 这里是 BACKUP
virtual_ipaddress { 192.168.1.200/24 }
track_script { check_redis }
}
nginx
# 备机配置片段
vrrp_instance VI_MYSQL {
virtual_router_id 51
priority 90 # MySQL 这里是 BACKUP
virtual_ipaddress { 192.168.1.100/24 }
track_script { check_mysql }
}
vrrp_instance VI_REDIS {
virtual_router_id 52
priority 100 # Redis 这里是 MASTER
virtual_ipaddress { 192.168.1.200/24 }
track_script { check_redis }
}
5. 外部脚本文件
这两个文件不是 Keepalived 自带的,需要自己编写,Keepalived 负责调用。
5.1 check_mysql.sh --- 健康检测脚本
bash
#!/bin/bash
# /etc/keepalived/check_mysql.sh
MYSQL_HOST="127.0.0.1"
MYSQL_PORT="3306"
MYSQL_USER="keepalived_check"
MYSQL_PASS="your_password"
# 使用 timeout 防止 MySQL 无响应时脚本卡住
timeout 3 mysql -h$MYSQL_HOST -P$MYSQL_PORT \
-u$MYSQL_USER -p$MYSQL_PASS \
-e "SELECT 1" > /dev/null 2>&1
if [ $? -ne 0 ]; then
logger "keepalived check_mysql: FAILED, stopping keepalived"
systemctl stop keepalived
exit 1
fi
exit 0
bash
chmod +x /etc/keepalived/check_mysql.sh
建议在 MySQL 中单独创建只有 SELECT 权限的检测账号,不要使用 root:
sqlCREATE USER 'keepalived_check'@'127.0.0.1' IDENTIFIED BY 'your_password'; GRANT SELECT ON *.* TO 'keepalived_check'@'127.0.0.1';
5.2 notify.sh --- 状态变更通知脚本
每次节点在三种状态之间切换时,Keepalived 都会调用这个脚本,并传入三个参数:
$1:类型,固定为"INSTANCE"$2:实例名,如"VI_MYSQL"$3:新状态,"MASTER"/"BACKUP"/"FAULT"

图5:三种状态之间的流转路径,以及每次流转时 notify.sh 被触发的时机。
bash
#!/bin/bash
# /etc/keepalived/notify.sh
TYPE=$1
NAME=$2
STATE=$3
MYSQL_ROOT_PASS="your_root_password"
LOG_TAG="keepalived_notify"
case $STATE in
MASTER)
logger "$LOG_TAG: $NAME 切换为 MASTER,解除 MySQL 只读"
mysql -uroot -p$MYSQL_ROOT_PASS \
-e "SET GLOBAL read_only=0; SET GLOBAL super_read_only=0;"
# 可在此发送告警通知(钉钉、企微、邮件等)
;;
BACKUP)
logger "$LOG_TAG: $NAME 切换为 BACKUP,设置 MySQL 只读"
mysql -uroot -p$MYSQL_ROOT_PASS \
-e "SET GLOBAL read_only=1; SET GLOBAL super_read_only=1;"
;;
FAULT)
logger "$LOG_TAG: $NAME 进入 FAULT 状态,设置 MySQL 只读"
mysql -uroot -p$MYSQL_ROOT_PASS \
-e "SET GLOBAL read_only=1; SET GLOBAL super_read_only=1;"
;;
esac
exit 0
bash
chmod +x /etc/keepalived/notify.sh
6. 完整配置文件汇总
主节点(192.168.1.101)
nginx
global_defs {
router_id MySQL_HA_Master
script_user root
enable_script_security
}
vrrp_script check_mysql {
script "/etc/keepalived/check_mysql.sh"
interval 2
timeout 5
fall 2
rise 1
weight -30
}
vrrp_instance VI_MYSQL {
state BACKUP
interface eth0
virtual_router_id 51
priority 100
advert_int 1
nopreempt
authentication {
auth_type PASS
auth_pass mysql_ha_2024
}
virtual_ipaddress {
192.168.1.100/24 dev eth0 label eth0:vip
}
garp_master_delay 1
garp_master_repeat 3
garp_master_refresh 10
track_script {
check_mysql
}
notify /etc/keepalived/notify.sh
}
备节点(192.168.1.102)
与主节点配置完全相同,只需修改两处:
nginx
global_defs {
router_id MySQL_HA_Slave # ← 改为不同的名字
...
}
vrrp_instance VI_MYSQL {
...
priority 90 # ← 改为较低的优先级
...
}
7. 配置验证与常用命令
bash
# 语法检查,不实际启动
keepalived --config-test -f /etc/keepalived/keepalived.conf
# 启动并设置开机自启
systemctl enable --now keepalived
# 查看实时日志
journalctl -u keepalived -f
# 确认当前节点是否持有 VIP
ip addr show eth0 | grep "192.168.1.100"
# 手动触发切换(在主节点执行,备节点自动接管)
systemctl stop keepalived
# 手动切回(在备节点执行,主节点重新接管)
systemctl restart keepalived
8. 配置参数速查表
vrrp_script 参数
| 参数 | 说明 | 推荐值 |
|---|---|---|
script |
检测脚本路径 | --- |
interval |
检测间隔(秒) | 2 |
timeout |
脚本超时(秒) | 5 |
fall |
触发故障所需连续失败次数 | 2 |
rise |
恢复正常所需连续成功次数 | 1 |
weight |
失败时优先级变化量 | -30 |
vrrp_instance 参数
| 参数 | 说明 | 注意事项 |
|---|---|---|
state |
初始角色 | 配合 nopreempt 时两台都写 BACKUP |
interface |
绑定网卡 | 用 ip a 确认实际网卡名 |
virtual_router_id |
VRRP 组编号 | 同组两台必须一致 |
priority |
基础优先级 | 主 100,备 90 |
advert_int |
心跳间隔(秒) | 默认 1 |
nopreempt |
禁止自动抢占 | 推荐开启,防二次中断 |
auth_pass |
认证密码 | 同组两台必须一致 |
virtual_ipaddress |
VIP 地址 | 必须与两台机器同网段 |
track_script |
引用检测脚本 | 不写则脚本不执行 |
notify |
状态变更回调脚本 | 可选,推荐配置 |