高可用:Keepalived 配置文件详解

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_instancetrack_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
}

图2vrrp_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=90weight=-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:

sql 复制代码
CREATE 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 状态变更回调脚本 可选,推荐配置
相关推荐
Paxon Zhang2 小时前
MySQL初阶入门的第一步
数据库·mysql·adb
XDHCOM2 小时前
PHP用来把Oracle的数据搬到Mysql里边的一个具体操作示范过程
mysql·oracle·php
蒋大钊!3 小时前
[MySQL] 大厂开发常用 Explain 字段快记
数据库·mysql
原来是猿3 小时前
MySQL【复合查询】
数据库·mysql
Arva .3 小时前
MySQL建表考虑的方面
数据库·mysql
qiuyuyiyang11 小时前
【MySQL】环境变量配置
数据库·mysql·adb
神仙别闹12 小时前
基于NodeJS+Vue+MySQL实现一个在线编程笔试平台
前端·vue.js·mysql
RDCJM13 小时前
【MySQL】在MySQL中STR_TO_DATE()以及其他用于日期和时间的转换
android·数据库·mysql
加成BUFF13 小时前
解决MySQL/MariaDB忘记root密码:完整重置教程(XAMPP/Windows版)
数据库·mysql·xampp