Keepalived 高可用配置实战
概述
在现代互联网架构中,服务的高可用性(High Availability, HA)是保障业务连续性的核心要求。当单点服务(如 Nginx 反向代理、MySQL 数据库、API 网关等)发生故障时,如何实现流量的无缝切换,避免业务中断,是每一位运维工程师必须面对的课题。
Keepalived 正是解决这一问题的成熟方案。它基于 VRRP(Virtual Router Redundancy Protocol,虚拟路由冗余协议)实现 IP 地址的漂移,配合自定义健康检查脚本,能够在主节点故障时自动将虚拟 IP(VIP)切换到备用节点,整个过程对客户端透明。
本文将围绕以下内容展开:
- VRRP 协议的工作原理
- Keepalived 的安装与基本配置
- 健康检查脚本的编写与集成
- 主备(Master/Backup)故障切换实战
- Keepalived 结合 Nginx 和 MySQL 的典型场景
通过阅读本文,你将掌握 Keepalived 从原理到生产部署的完整流程。
VRRP 协议原理
什么是 VRRP
VRRP 是一种容错协议,它将一组运行在局域网内的路由器(或服务器)组成一个虚拟路由器,对外暴露一个虚拟 IP 地址。在这个虚拟路由器组中:
- Master 节点:当前承载虚拟 IP 的节点,负责响应发往该 VIP 的所有请求。
- Backup 节点:处于待命状态的节点,持续监听 Master 的心跳通告。一旦 Master 失效,优先级最高的 Backup 将接管 VIP。
VRRP 通过 RFC 5798 标准化,Keepalived 是其 Linux 平台最为流行的实现。
VRRP 工作流程
- 虚拟路由器组内的所有节点选举出一个 Master(根据优先级 priority 决定)。
- Master 周期性(默认每秒)发送 VRRP 通告(Advertisement)报文到多播地址 224.0.0.18。
- Backup 节点持续监听通告报文。如果在
advert_int * 3 + skew_time时间内未收到 Master 的通告,则认为 Master 已宕机。 - Backup 节点中优先级最高的一个抢占成为新的 Master,接管虚拟 IP 并发送免费 ARP 报文,通知局域网内的其他设备更新 ARP 缓存。
Keepalived 的扩展能力
与标准的 VRRP 实现不同,Keepalived 引入了 vrrp_script 机制,允许通过自定义脚本对服务进行实时健康检查。当脚本检测到服务异常时,可以动态降低当前节点的优先级,从而主动触发主备切换。这使得 Keepalived 不仅能够应对服务器级别的故障,还能处理进程级别的异常。
Keepalived 安装
在 CentOS/RHEL 系统上,Keepalived 可直接通过 yum 安装:
yum install -y keepalived对于 Ubuntu/Debian 系统:
apt-get install -y keepalived安装完成后,主配置文件位于 /etc/keepalived/keepalived.conf,启动与管理命令如下:
# 启动
systemctl start keepalived
# 设置开机自启
systemctl enable keepalived
# 查看运行状态
systemctl status keepalived
# 热加载配置(不中断服务)
kill -HUP $(cat /var/run/keepalived.pid)其中热加载(reload)命令在生产环境中尤为重要:它允许你在不重启 Keepalived 进程、不触发 VIP 漂移的情况下,使配置变更生效。
配置文件详解
Keepalived 的配置文件使用其独有的语法格式,以 ! 开头表示注释行(非标准 Shell 风格的 #)。配置文件主要由 global_defs、vrrp_script 和 vrrp_instance 三大块组成。
global_defs——全局定义
global_defs {
notification_email {
admin@example.com
}
notification_email_from keepalived@example.com
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id LVS_DEVEL
}关键参数说明:
| 参数 | 说明 |
|---|---|
notification_email | 告警邮件接收地址列表,Master/Backup 切换时触发 |
notification_email_from | 告警邮件的发件人地址 |
smtp_server | SMTP 邮件服务器地址 |
smtp_connect_timeout | SMTP 连接超时时间(秒) |
router_id | 当前 Keepalived 节点的唯一标识,在同一局域网内应保持唯一 |
在云环境或容器化部署中,SMTP 告警通常被替换为自定义的通知脚本或监控系统(如 Prometheus AlertManager),因此在生产环境中 notification_email 相关配置并非必需。
vrrp_script——健康检查脚本
这是 Keepalived 最强大的特性之一。通过定义 vrrp_script,你可以让 Keepalived 周期性执行一个脚本,并根据脚本的返回值动态调整节点优先级。
vrrp_script chk_service {
script "/etc/keepalived/check_service.sh"
interval 1 # 检查间隔,单位秒
weight -2 # 优先级调整权重
fall 3 # 连续失败多少次后判定为异常
rise 2 # 连续成功多少次后恢复为正常
}参数说明:
| 参数 | 说明 |
|---|---|
script | 要执行的检查脚本路径 |
interval | 执行间隔,单位秒,默认 1 秒 |
weight | 优先级调整值。脚本失败时当前 priority 减去该绝对值,脚本恢复时加回 |
fall | 需要连续失败多少次才判定为 FAULT 状态 |
rise | 需要连续成功多少次才从 FAULT 恢复为正常 |
脚本约定:返回 0 表示正常,返回非 0 表示异常。weight 值直接影响优先级计算。假设当前节点的 priority 为 100,weight 为 -2,则脚本连续失败 fall 次后,有效优先级降至 98。若此时 Backup 节点的优先级为 99,则 Backup 会抢占成为 Master。
健康检查脚本示例
以下是一个检查 Nginx 进程是否存活的 Shell 脚本:
#!/bin/bash
# /etc/keepalived/check_nginx.sh
counter=$(ps -C nginx --no-heading | wc -l)
if [ "${counter}" -eq "0" ]; then
# Nginx 进程不存在,尝试重启
systemctl start nginx
sleep 2
counter=$(ps -C nginx --no-heading | wc -l)
if [ "${counter}" -eq "0" ]; then
# 重启失败,通知 Keepalived 降低优先级
exit 1
fi
fi
exit 0对于 MySQL 服务,可以结合 mysqladmin ping 命令进行检查:
#!/bin/bash
# /etc/keepalived/check_mysql.sh
mysqladmin -u root -p'your_password' ping 2>/dev/null | grep -q "mysqld is alive"
if [ $? -ne 0 ]; then
exit 1
fi
exit 0在生产环境中,你也可以使用 Python 等语言编写更为复杂的检查逻辑,例如检查 API 接口的 HTTP 状态码、验证数据库读写能力等。
vrrp_instance——VRRP 实例
vrrp_instance 是 Keepalived 配置的核心,它定义了一个 VRRP 虚拟路由器。
vrrp_instance VI_1 {
state MASTER # 初始状态:MASTER 或 BACKUP
interface eth0 # 绑定网卡
virtual_router_id 51 # VRRP 路由器 ID(0-255),同一组节点必须一致
priority 100 # 优先级(1-255),值越大优先级越高
advert_int 1 # VRRP 通告间隔,单位秒
authentication {
auth_type PASS # 认证类型:PASS(密码)或 AH
auth_pass MyPassword # 认证密码,同一组节点必须一致(最长 8 字符)
}
virtual_ipaddress {
192.168.1.100/24 # 虚拟 IP 地址
}
track_script {
chk_service # 关联健康检查脚本
}
}关键配置点:
- state:MASTER 和 BACKUP 仅为初始状态。实际运行中,如果多台节点同时启动且均配置为 MASTER,则通过
priority值竞选。state 并不强制角色。 - virtual_router_id:同一 VRRP 组内所有节点的该值必须相同,否则节点间无法互相通告。
- priority:优先级数字越大越优先。在多节点场景下,通常给期望成为 Master 的节点分配最高优先级。
- advert_int:通告报文发送间隔。值越小,切换速度越快,但 CPU 和网络开销也相应增加。
- track_script:关联前面定义的
vrrp_script,使健康检查结果直接影响本实例的优先级。
双 VIP 主备互切实战
在实际生产部署中,两台服务器往往需要同时提供服务,充分利用硬件资源。下面是一个经典的双 VIP 主备互切方案:两台服务器各承载一个 VIP 的 Master 角色,互为 Backup,实现负载分担与高可用的统一。
架构拓扑:
Server A (10.241.47.100) Server B (10.241.47.101)
┌─────────────────────────┐ ┌─────────────────────────┐
│ VIP1: 10.241.47.127 │ │ VIP1: 10.241.47.127 │
│ state: MASTER (pri=100)│◄── VRRP ───►│ state: BACKUP (pri=99) │
│ │ │ │
│ VIP2: 10.81.79.104 │ │ VIP2: 10.81.79.104 │
│ state: BACKUP (pri=99) │ │ state: MASTER (pri=100)│
└─────────────────────────┘ └─────────────────────────┘正常运行时,Server A 承载 VIP1,Server B 承载 VIP2,两台服务器各自处理业务流量。当 Server A 宕机后,VIP1 漂移到 Server B,Server B 同时承载两个 VIP;反之亦然。
Server A 配置(主节点视角)
! Configuration File for keepalived
global_defs {
notification_email {
admin@example.com
}
notification_email_from keepalived@example.com
smtp_server mail.example.com
smtp_connect_timeout 30
router_id ServerA
}
vrrp_script chk_gateway_port {
script "/etc/keepalived/check_gateway.py"
interval 1
weight -2
fall 3
rise 2
}
vrrp_instance VI_Gateway1 {
state MASTER
interface bond6
virtual_router_id 231
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass gateway_vip1
}
virtual_ipaddress {
10.241.47.127/24
}
track_script {
chk_gateway_port
}
}
vrrp_instance VI_Gateway2 {
state BACKUP
interface bond6
virtual_router_id 232
priority 99
advert_int 1
authentication {
auth_type PASS
auth_pass gateway_vip2
}
virtual_ipaddress {
10.81.79.104/24
}
track_script {
chk_gateway_port
}
}Server B 配置(备节点视角)
! Configuration File for keepalived
global_defs {
notification_email {
admin@example.com
}
notification_email_from keepalived@example.com
smtp_server mail.example.com
smtp_connect_timeout 30
router_id ServerB
}
vrrp_script chk_gateway_port {
script "/etc/keepalived/check_gateway.py"
interval 1
weight -2
fall 3
rise 2
}
vrrp_instance VI_Gateway1 {
state BACKUP
interface bond6
virtual_router_id 231
priority 99
advert_int 1
authentication {
auth_type PASS
auth_pass gateway_vip1
}
virtual_ipaddress {
10.241.47.127/24
}
track_script {
chk_gateway_port
}
}
vrrp_instance VI_Gateway2 {
state MASTER
interface bond6
virtual_router_id 232
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass gateway_vip2
}
virtual_ipaddress {
10.81.79.104/24
}
track_script {
chk_gateway_port
}
}配置要点总结:
- 每个 VRRP 实例(
virtual_router_id231 / 232)在两个节点上的角色(state)和优先级(priority)互为镜像。 - 认证密码
auth_pass在同一个 VRRP 实例的两端必须完全一致,否则节点间无法正常通信。 - 两个 VRRP 实例共享同一个
vrrp_script检测脚本,确保任一服务异常都能触发 VIP 漂移。 fall 3和rise 2的设置可以避免因网络抖动造成的频繁切换(flapping)。
Keepalived 结合 Nginx 的高可用方案
Nginx 作为反向代理和负载均衡器,是企业架构中常见的流量入口。通过 Keepalived 为 Nginx 提供 VIP 漂移,可以消除 Nginx 的单点故障。
方案架构
┌───────────┐
│ Client │
└─────┬─────┘
│
┌─────▼─────────────────┐
│ Virtual IP (VIP) │
│ 10.241.47.127 │
└─────┬───────┬─────────┘
│ │
┌─────────▼──┐ ┌──▼─────────┐
│ Nginx A │ │ Nginx B │
│ (Master) │ │ (Backup) │
└─────┬──────┘ └──────┬─────┘
│ │
┌─────▼───────────────▼─────┐
│ Backend Servers │
└───────────────────────────┘Nginx 健康检查脚本
#!/bin/bash
# /etc/keepalived/check_nginx.sh
# 检查 Nginx 进程是否存在
if ! pidof nginx &>/dev/null; then
# 尝试启动 Nginx
/usr/sbin/nginx -c /etc/nginx/nginx.conf
sleep 1
if ! pidof nginx &>/dev/null; then
# 启动失败,告知 Keepalived 切换
exit 1
fi
fi
exit 0在 Keepalived 配置中关联:
vrrp_script chk_nginx {
script "/etc/keepalived/check_nginx.sh"
interval 2
weight -5
fall 2
rise 1
}
vrrp_instance VI_Nginx {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass nginx_ha
}
virtual_ipaddress {
10.241.47.127/24
}
track_script {
chk_nginx
}
}关键细节:非抢占模式
在某些场景下,你可能希望 Primary 节点恢复后不要立即抢回 VIP(避免二次切换造成连接中断)。此时可以在 vrrp_instance 中添加 nopreempt 参数,并配合 state BACKUP 使用(因为 nopreempt 仅在 state 为 BACKUP 时生效):
vrrp_instance VI_Nginx {
state BACKUP # nopreempt 仅在 BACKUP 状态下生效
nopreempt
priority 100
# ... 其余配置 ...
}Keepalived 结合 MySQL 的高可用方案
对于 MySQL 主从复制的架构,Keepalived 可以确保应用始终将读写请求指向当前的主库 VIP。
MySQL 健康检查脚本
#!/bin/bash
# /etc/keepalived/check_mysql.sh
MYSQL_USER="root"
MYSQL_PASS="your_password"
MYSQL_HOST="localhost"
mysqladmin -u${MYSQL_USER} -p${MYSQL_PASS} -h${MYSQL_HOST} ping 2>/dev/null \
| grep -q "mysqld is alive"
if [ $? -ne 0 ]; then
exit 1
fi
# 可选:进一步检查是否为可写状态(只读时为从库角色)
READ_ONLY=$(mysql -u${MYSQL_USER} -p${MYSQL_PASS} -h${MYSQL_HOST} \
-e "SELECT @@read_only;" -sN 2>/dev/null)
if [ "${READ_ONLY}" -eq "1" ]; then
exit 1
fi
exit 0该脚本不仅检测 MySQL 进程是否存活,还通过 SELECT @@read_only 判断当前实例是否为可写主库。当 MySQL 主从发生切换导致旧主库变为只读时,该脚本会返回失败信号,Keepalived 随即降低优先级并触发 VIP 漂移,使 VIP 始终指向可写的 MySQL 实例。
运维与故障排查
查看 VIP 状态
# 在 Master 节点上查看 VIP 是否绑定
ip addr show bond6 | grep 10.241.47.127
# 查看 Keepalived 日志
journalctl -u keepalived -f验证 VRRP 通信
# 通过 tcpdump 抓取 VRRP 通告报文
tcpdump -i bond6 vrrp -n如果 Backup 节点无法收到 Master 的通告报文,请检查:
- 两台服务器之间的网络连通性
- 防火墙是否放行了 VRRP 协议(IP 协议号 112)
virtual_router_id和auth_pass是否一致
模拟故障切换
# 方法一:手动停止 Keepalived
systemctl stop keepalived
# 方法二:关闭网卡接口
ip link set bond6 down
# 方法三:手动杀死被监控的服务
systemctl stop nginx在 Backup 节点观察日志,journalctl -u keepalived -f 应输出类似 Entering MASTER STATE 的日志信息,并使用 ip addr show 确认 VIP 已绑定到 Backup 节点。
处理脑裂(Split-Brain)
脑裂是 HA 方案中的常见风险,表现为两台节点同时认为自己是 Master,双端同时绑定同一 VIP,导致 IP 冲突和网络异常。预防措施:
- 严格保证 VRRP 通信:确保 VRRP 多播报文在节点间可达,必要时使用独立的网卡或 VLAN 传输心跳。
- 合理设置优先级差:主备节点的 priority 差值建议不小于 5,避免因微小的优先级波动导致切换。
- 使用仲裁脚本:在健康检查脚本中加入对第三方仲裁节点(如网关 IP)的 ping 检测。如果自身存活但无法 ping 通网关,说明自身网络可能出现异常,应主动释放 VIP,避免脑裂。
#!/bin/bash
# 仲裁检测:检查到网关的连通性
GATEWAY="192.168.1.1"
ping -c 2 -W 1 ${GATEWAY} &>/dev/null
if [ $? -ne 0 ]; then
# 网关不通,自身网络可能异常,放弃 VIP
exit 1
fi
exit 0总结
Keepalived 作为一款轻量级、高性能的高可用解决方案,已经广泛应用于各类生产环境中。总结本文的关键要点:
- VRRP 协议是 Keepalived 的基石,通过虚拟 IP 和优先级选举实现透明的故障切换。
- vrrp_script 健康检查机制让 Keepalived 能够感知服务层面的异常,而不仅仅是服务器宕机。
- 双 VIP 主备互切方案在保证高可用的同时,充分利用了硬件资源,适合大多数中小规模部署。
- 结合 Nginx/MySQL 等关键服务时,务必将健康检查脚本与服务实际状态挂钩(如 Nginx 进程检测、MySQL 可写状态检测)。
- 运维层面需关注脑裂防护、网络连通性和防火墙规则,确保 VRRP 协议报文畅通。
合理的 Keepalived 配置加上全面的监控告警体系,能够为你的核心业务构建一道坚实的高可用防线。在生产环境部署前,务必在测试环境中充分验证各种故障场景下的切换行为,做到心中有数,遇事不慌。
本文基于 Keepalived 2.x 版本编写,部分参数在不同版本中可能存在差异,请以官方文档为准。
暂无评论