☰
keepalived 1.2.13 高可用实践:VRRP原理与配置避坑指南
2026/10/16 2:46:07 网站建设 项目流程

简介:Keepalived 1.2.13 源码包,面向 Linux 运维工程师、网络架构师及高可用方案学习者,用于实现基于 VRRP 与 LVS 的服务高可用与负载均衡,解决主备切换和服务连续性保障问题。压缩包共收录 188 个文件,整体仅 334KB,以 C 语言源码为主(62 个 .h、61 个 .c),并包含配置模板、man 手册(keepalived.conf.5、keepalived.8)、安装脚本、README、PEM 证书及 LVS 相关示例,便于从源码阅读到实际部署全流程参考。源码中 vrrp.c、check_snmp.c、vrrp_snmp.c 等模块清晰展示了 VRRP 状态机、健康检查与 SNMP 监控的具体实现,配合 virtual server group 配置示例可快速理解抢主、选举和流量切换逻辑。已有 368 人学习,适合希望深入掌握 Keepalived 内部机制、进行二次开发或精准排查生产环境故障的工程师,也可作为学习 VRRP 协议落地实现的高质量代码样本。

1. keepalived 1.2.13 是什么:把「故障转移」变成自动化动作的守护进程

某天凌晨我负责的一台业务虚机毫无征兆地宕机,SSH 连不上,业务群已经开始刷屏。幸好那台机器上提前跑着 keepalived,VIP 在不到两秒内漂移到备用节点,整个过程用户完全无感。从那以后,「keepalived 是花最小成本拿到高可用」这句话在我心里就有了具体的说服力。

keepalived 1.2.13 是 VRRP 协议的开源实现,它解决的核心问题,是把「IP 地址归谁」变成一个可以自动转移的状态:主节点健康时 VIP 住在主节点,主节点故障后备用节点自动接管 VIP,并在恢复后按策略回切。它可以配合 LVS 做四层负载均衡的 Director 高可用,也能独立使用,给一组后端节点提供稳定的虚拟 IP。你只需要两台同网段、能互通的机器,不引入额外的负载均衡硬件,就能给服务加一道自动保险。适合刚接触高可用、想把这套机制从原理到配置完整走一遍的从业者,也适合想确认这个版本语法边界的老手。

2. 从源码包到可运行服务:编译安装的三个关键步骤与参数细节

keepalived 1.2.13 是 2013 年左右的版本,但它的 configure / make / make install 三件套思路和后续版本基本一致。编译环节是环境问题最多的地方,依赖缺一个、参数多一个都会在 make 阶段翻车。先把这块走通,后面出问题才好定位是配置问题还是环境问题。

2.1 依赖环境与 configure 参数

编译 keepalived 1.2.13 需要三个基础库,缺任何一个都会在 configure 阶段报错或编译到一半中断。popt 负责命令行参数解析,openssl 用于 VRRP 报文认证(配置里的 auth_type PASS 依赖它计算报文摘要),libnl 是内核 netlink 通信的封装,keepalived 通过它和系统的 IP 地址、网卡状态交互。

我一般先装好这三个再跑 configure,避免编译到一半缺头文件的尴尬:

# Debian/Ubuntu 系列 apt-get install -y libpopt-dev libssl-dev libnl-dev # RHEL/CentOS 系列 yum install -y popt-devel openssl-devel libnl-devel

configure 参数里真正值得关注的只有几个,关键参数如下:

参数作用我的习惯
--prefix=/usr/local/keepalived指定安装目录,配置文件会跟随 prefix推荐指定,方便以后整体卸载
--disable-lvs关闭 LVS 相关模块只做 VIP 高可用时建议关掉
--disable-vrrp关闭 VRRP,只保留 LVS大多数场景用不到,千万别关
--with-debug编译调试版本,日志更详细排查问题时再开,日常不推荐

一个常见的误解是给 1.2.13 加--with-kernel参数。这个参数在很早期的 keepalived 里用于指定内核源码路径,因为当时需要编译内核补丁模块。1.2.13 已经全面转向 netlink 接口,不再依赖内核模块,加了这个参数也不会生效,纯属给自己找不痛快。

2.2 编译安装命令与常见报错

依赖装好、configure 参数定下来后,剩下的就是标准三连:

# 进入解压后的源码目录 cd keepalived-1.2.13 # 配置阶段:只保留 VRRP,去掉 LVS 模块,编译产物更干净 ./configure --prefix=/usr/local/keepalived --disable-lvs # 并发编译:-j 后面的数字不要超过 CPU 核数,否则会因内存不足报错 make -j4 # 安装到 /usr/local/keepalived make install

configure 阶段关掉 LVS 是为了缩小二进制体积,也让后续日志里少一些用不到的模块输出。make -j4里的 4 是编译并行度,如果机器运行内存小于 2G,建议改成-j2,否则 gcc 进程会互相抢内存,报错信息通常是virtual memory exhausted。

编译时常见的报错有三个。第一个是popt.h: No such file or directory,原因就是没装 popt-devel,回去补依赖再重新 configure 即可。第二个是libnl/Netlink.h: No such file,这是 libnl 版本过旧或没装 libnl-devel,装了之后如果还报,检查是不是系统里同时存在 libnl1 和 libnl3,需要 unset 掉旧版本的头文件路径再配。第三个是Package libnl was not found in the pkg-config search path,这是 pkg-config 找不到库文件,用export PKG_CONFIG_PATH=/usr/lib/pkgconfig:$PKG_CONFIG_PATH指一下路径就行,属于血泪经验。

2.3 安装后的文件布局与前台调试

安装完成后,关注三个位置。二进制文件在/usr/local/keepalived/sbin/keepalived,配置文件在/usr/local/keepalived/etc/keepalived/keepalived.conf,启动脚本在/usr/local/keepalived/etc/rc.d/init.d/keepalived。如果你 configure 时没加 prefix,默认会装到/usr/local,配置文件就在/usr/local/etc/keepalived/keepalived.conf。

我第一次装完直接执行keepalived命令,结果它去读默认路径没读到配置,静默退出了。后来习惯先用前台模式验证配置:

# -f 指定配置文件,-D 前台运行并把日志打到终端,-S 把日志写到系统日志 /usr/local/keepalived/sbin/keepalived -f /usr/local/keepalived/etc/keepalived/keepalived.conf -D -S

前台跑起来能看到完整的启动过程,包括 VRRP 实例初始化、网卡绑定、VIP 添加等日志。确认无报错后,再按 Ctrl+C 退出,改用 init 脚本后台启动。验证安装是否成功最直接的方法是看版本号:

/usr/local/keepalived/sbin/keepalived --version

能正常输出版本号和编译参数,说明二进制没问题。这个时候配置还没写,先别急着启动服务,下一章内容才是真正决定高可用行为的部分。

3. 核心配置实战:实例、虚拟 IP、健康检查脚本的正确写法

keepalived 1.2.13 的配置核心就一个文件,但里面每段都有讲究。配置想清楚,后面故障切换基本不用操心;配置想不清楚,两台机器可能井水不犯河水地各持一个 VIP,那还不如不配。

3.1 一个最小可用的 keepalived.conf

最简单的双机高可用配置,只需要一个vrrp_instance段。主节点配置如下:

global_defs { notification_email_from admin@example.com # 告警邮件来源,可留空 router_id LVS_DEVEL # 路由标识,仅用于日志识别,两端可不同 } vrrp_instance VI_1 { state MASTER # 本机初始角色 interface eth0 # 承载 VIP 的物理网卡 virtual_router_id 51 # 两端必须一致,同一二层网络内别冲突 priority 150 # MASTER 优先级高于 BACKUP advert_int 1 # VRRP 通告间隔,单位秒 authentication { auth_type PASS auth_pass 8chars # 认证口令,长度不能超过 8 位 } virtual_ipaddress { 10.0.0.100/24 dev eth0 # VIP 地址,/24 掩码要跟实际网络一致 } }

备用节点除了state BACKUP、priority 100,其余内容完全一致。这里有个关键点:auth_pass最长 8 个字符,这是 VRRP 协议报文头本身的约束,不是 keepalived 的限制,写长了会在启动时直接报参数错误。virtual_router_id在同一个二层网络中不要和别人的实例重复,否则两台无关联的机器会互相抢 VIP,出现你最不想见到的脑裂。

virtual_ipaddress里的掩码必须跟业务网段一致。如果 VIP 写的是10.0.0.100/32,keepalived 会给它单独建一个主机路由,外部设备很可能无法正常访问这个地址;写/24才会走物理网卡的广播域。我一开始习惯性写了/32,结果切换后客户端全连不上,排查了半天才发现掩码问题。

3.2 vrrp_instance 关键参数表与抢占机制

vrrp_instance的参数决定了故障切换的粒度,几个核心参数值得逐个过一遍:

参数取值范围作用
stateMASTER / BACKUP初始角色,真正决定角色的是 priority
priority1 ~ 254数值大者胜出,本机 VRRP 状态机的核心依据
advert_int秒,常用 1MASTER 发送 VRRP 通告的间隔
virtual_router_id1 ~ 255实例标识,两端一致才属于同一个虚拟路由器
nopreempt无值禁止高优先级节点抢占已生效的 BACKUP
garp_master_delay秒VIP 生效后发送免费 ARP 的延迟

抢占机制是 keepalived 新手最容易理解反的地方。默认情况下,只要 BACKUP 节点的 priority 比当前 MASTER 高,它就会立即接管 VIP,这叫抢占模式。这里有个踩坑点:抢占不是瞬间发生的,MASTER 恢复后要等3 * advert_int时间才会回切,这是 VRRP 协议里 MASTER_DOWN 定时器的设计,1.2.13 没有参数可以缩短这个时间,只能接受。

如果业务不希望主节点恢复后回切(比如主节点每次重启都要重建一批缓存),可以在两端都加上nopreempt。注意是两端同时加,只加一端的话,另一端依然会发起抢占,配置不会按你想象的方式工作。这个细节我翻车过一次,双端配置不一致导致来回切换,日志里全是状态翻转。

3.3 track_script 健康检查:不只是 ping 一下

state和priority只管 VRRP 层面的协商,但业务层面的健康得靠track_script来盯。keepalived 1.2.13 里一个vrrp_script定义一个检查动作,一个track_script把它挂到实例上。先写一个检查脚本:

#!/bin/bash # 健康检查脚本:检查 nginx 进程是否存在 # 返回 0 表示健康;返回非 0 表示不健康,keepalived 将按 weight 调整本机优先级 if pgrep -x nginx > /dev/null 2>&1; then exit 0 fi exit 1

脚本写好记得加执行权限:chmod +x /etc/keepalived/chk_nginx.sh。然后把它挂进配置:

vrrp_script chk_nginx { script "/etc/keepalived/chk_nginx.sh" interval 2 # 每 2 秒执行一次 timeout 3 # 脚本执行超 3 秒视为不健康,避免脚本卡死阻塞状态机 weight -20 # 脚本失败时 priority 减 20 } vrrp_instance VI_1 { ...省略前面基础参数... track_script { chk_nginx } }

weight的语义是:脚本返回非 0 时,机器当前的 priority 加上 weight 作为参与选举的临时优先级。负值意味着「失败降权」,MASTER 挂了检查会主动把 priority 从 150 减到 130,低于 BACKUP 的 100 吗?如果原本就高于 BACKUP,降权后仍然高,那这台机器依然持有 VIP 不切换——所以 weight 值要参考对端 priority 来定,不是随便写一个负值就行。这里的原则是:本机 priority - weight 的结果要小于对端 priority,切换才会发生。

interval和timeout的比例也很重要。脚本如果执行时间超过 interval,keepalived 会认为状态机被阻塞,直接标记不健康。常见做法是让 interval 至少是 timeout 的两倍,给脚本留足执行余量,也避免频繁 fork 子进程造成不必要的上下文切换。

3.4 notify 通知脚本的正确姿势

故障切换发生时,keepalived 会调用notify_master、notify_backup、notify_fault三段回调脚本。很多人只配置了 VIP 漂移,切换后备用节点上的服务没起来,等于高可用了个寂寞。通知脚本就是用来干这个的。

#!/bin/bash # 通知脚本:接收状态参数 MASTER / BACKUP / FAULT # 传参格式:脚本名 状态 实例名 STATE=$1 INSTANCE=$2 case $STATE in MASTER) # 成为主节点后,拉起业务进程 systemctl start nginx ;; BACKUP) # 退为备用节点,停止业务进程,避免双活冲突 systemctl stop nginx ;; FAULT) # 进入故障状态,可做告警,但不要在这里重启服务 logger -t keepalived "instance ${INSTANCE} entered FAULT" ;; esac

这段脚本注意两点。第一,脚本必须幂等,systemctl start对已启动的服务是无害的,所以用 start/stop 会比 restart 安全得多。第二,不要在通知脚本里做sleep或者重启 keepalived 服务本身。我在一次演练中,MASTER 通知脚本里加了systemctl restart keepalived,结果每次切主都会触发新一轮状态机初始化,VIP 频繁抖动,日志刷屏到把磁盘写满,这个教训相当深刻。

4. 避坑排查手册:防火墙、抢占、脚本超时与配置文件陷阱

keepalived 配置能跑通不代表高可用就稳了。以下五条是实操中反复遇到的坑,每一条都是真实环境里踩出来的,按「现象 → 原因 → 解决」记录。

4.1 现象:两台机器同时持有 VIP,客户端请求一会儿通一会儿不通

这就是典型的脑裂。最直接的原因是 VRRP 组播报文被防火墙丢弃,或者两端的virtual_router_id不一致,导致两边各自认为自己是 MASTER。排查时先看两端是否同时持有 VIP:ip addr show确认10.0.0.100出现在两台机器上。

原因是 VRRP 使用的组播地址是 224.0.0.18,协议号 112。很多默认防火墙策略只放行 TCP/UDP,把协议 112 的组播直接丢弃了。解决方法是放行该协议:

iptables -I INPUT -p vrrp -j ACCEPT

放行后两端的 VRRP 报文才能互通,状态机才能正确处理优先级。另外确认两端配置里的virtual_router_id、auth_pass完全一致,缺一个都会导致对端报文被当作非法数据。

4.2 现象:MASTER 恢复后 VIP 迟迟不回来,业务一直由备用机扛着

这种「主不回来」的玄学问题,多半是抢占配置问题。先确认两端是否都配了nopreempt,如果原来加过这个参数后忘了删,MASTER 恢复后即使 priority 更高也不会主动回切。解决方式是去掉两端nopreempt并重启 keepalived 让配置生效。

另一种可能是等待时间不够。VRRP 协议规定 MASTER 恢复后要等待3 * advert_int秒才会发起抢占,advert_int配的 2 秒就要等 6 秒。这不是故障,是协议设计。如果你需要回切更快,把advert_int调成 1,同时两端同步修改。

4.3 现象:健康检查脚本明明没问题,却频繁触发主备切换

脚本单独执行只要 0.1 秒,但 keepalived 日志里script timeout刷个不停。原因是脚本里做了阻塞操作——比如curl检查一个慢接口,或者sleep等待某个条件。keepalived 默认给脚本的执行时间很短,超过timeout就直接判定失败。

解决方法是把脚本拆成两层:外层只做进程和端口检查,内层如果需要网络探测,把interval调大到 5 秒、timeout放到 3 秒,保证超时时间大于脚本最坏执行时间。注意timeout不能大于interval,否则状态机还没拿到结果就要开始下一次轮询。

4.4 现象:VIP 漂移成功了,但客户端依然连不上

这种情况最隐蔽。VIP 出现在备机上,本机ping 10.0.0.100也通,但外部客户端访问就是超时。检查发现 VIP 绑定的网卡是eth0,但客户端所在的业务网段走的是eth1,跨网段通信没有路由。

原因是virtual_ipaddress里的 VIP 配了/32掩码,keepalived 只添加了主机路由,没有把 VIP 放进正确网段的广播域。解决方法是把掩码改成实际业务网段的掩码,例如/24,并显式指定网卡:10.0.0.100/24 dev eth0。配置修改后需要重启 keepalived 或执行keepalived -n重新加载,VIP 才会重新绑定。

4.5 现象:启动时日志报unknown keyword后直接退出

这是版本语法差异导致的。网上很多教程写的是 1.3.x 或 2.0.x 的配置,里面的vrrp_unicast_peer、vrrp_version、enable_vrrp_checksums这些关键字在 1.2.13 里根本不存在,keepalived 会在解析配置文件时直接拒绝启动。

解决方法是严格使用 1.2.13 的语法。这个版本支持的是vrrp_instance、vrrp_sync_group、virtual_ipaddress、track_script这些基础关键字,不支持单播模式,也不支持 VRRPv3。如果你从高版本配置迁移过来,先对照官方文档过一遍关键字,把不支持的删掉再启动。也可以先用keepalived -t做配置语法检查,它会明确告诉你第一处解析错误在哪一行。

5. 验证与进阶:抓包确认 VRRP 报文、时延测量与控制回切

配置写完、服务启动、VIP 正常出现,这只是第一步。真正验证 keepalived 有没有生效,靠的是抓包确认 VRRP 报文的交换,以及主动触发一次切换测量时延。

5.1 抓包确认 VRRP 状态机

在主备两台机器上同时抓 VRRP 报文,能看到状态机的全貌:

tcpdump -i eth0 vrrp -n -v

正常情况下,备份节点能持续收到主节点的 VRRP 通告,输出里能看到vrid 51、priority 150、advertise interval 1s。当你手动停掉主节点的 keepalived 时,这个输出会立刻中断,几秒后备份节点的抓包结果里出现priority 100的通告——说明它已经提升为 MASTER 并开始对外发送报文。

抓包不仅用于确认状态机,还能帮你确认advert_int是否按预期工作。如果抓包看到通告间隔抖动明显,比如从 1 秒跳到 3 秒,说明主节点负载过高或网卡有丢包,这种环境下的高可用是不稳固的,需要先解决网络问题再谈切换。

5.2 时延测量与主动回切验证

我曾经只确认 VIP 能漂移就收工,后来手动演练才发现切换耗时接近 10 秒,原因是脚本超时配置不当加上抢占等待。从那以后,每次部署完都会跑一遍完整的切换演练:停掉主节点服务,记录从「VIP 消失」到「备用节点开始响应」的间隔,命令如下:

# 在备用节点上持续探测 VIP 的响应时间,模拟客户端视角 while true; do curl -s -o /dev/null -m 1 -w "%{time_total}\n" http://10.0.0.100/health sleep 0.5 done

正常情况下的响应时间在 0.05 秒以内,切换发生时,这里会出现一个连接超时或失败,随后在 2 秒内恢复正常响应。这个 2 秒包含了 VRRP 的 MASTER_DOWN 定时器、脚本检查周期和 VIP 重新绑定的时间,属于正常范围。如果超过 5 秒,回头检查脚本interval和timeout的值。

主动回切验证的技巧是:临时把主节点配置里的 priority 从 150 改成 90(低于备用节点),重启 keepalived 让它自己退出 MASTER 角色,确认 VIP 自动漂到备机后再改回来。这样能验证抢占方向和链路是否通畅,比拔网线演练安全得多。

从那以后,我每次做完一套 keepalived 配置,都会强制走一遍抓包 + 主动降权回切验证,而不是只看两台机器同时起来了就收工。这能确认配置真的按预期工作,而不是靠默认值硬撑。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询