资讯动态

Keepalived高可用实战:VRRP协议原理与虚拟IP漂移配置详解

发布时间:2026/10/12 21:18:23 来源:尧图企业网站定制
1. 先搞清楚 Keepalived 到底解决了什么问题在高可用架构的选型清单里Keepalived 是我长期保留的工具它的名字每次都会被频繁搜索但很多人其实没真正搞懂它和 Nginx、HAProxy 的区别。简单说Keepalived 本身不处理业务流量它只做两件事一是通过 VRRP 协议管理一组服务器上的虚拟 IP二是对后端服务做健康检查。当某个节点挂了Keepalived 会自动把虚拟 IP 从故障节点漂移到一个健康节点外部访问的入口 IP 不变服务却悄悄完成了接管。很多刚接触的朋友容易产生一个误区以为 Keepalived 是个负载均衡器。不是的Nginx、HAProxy 干的是“把请求分发到多台后端”而 Keepalived 干的是“保证入口 IP 永远可用”两者完全是不同层面的问题。打个比方业务请求进大楼负载均衡器是前台分诊台把客人分给不同的窗口Keepalived 则是大楼的备用电力系统主路断电时自动切换客人不会察觉灯灭过。那它适合谁来学如果你正在维护 Nginx、MySQL、Redis、PostgreSQL 这类状态敏感的服务需要给它们做主备高可用或者你在搭一套双机热备环境Keepalived 基本是绕不开的选项。即使是单机玩一玩学会它也能让你理解虚拟 IP、VRRP、状态机这些高可用核心概念。2. 安装 Keepalived不同系统下的完整步骤安装环节看着简单但版本差异和依赖缺失是很多人掉坑的开始。我用过 CentOS、Ubuntu 和源码编译三种方式分别说说实操中的细节。2.1 CentOS/RHEL 系安装CentOS 7、8 的官方源里其实自带 Keepalived只不过版本可能偏老。直接用系统源装是最快的yum install -y keepalived装完之后先别急着启动确认一下版本和命令路径keepalived --version which keepalived如果你用的 CentOS 8 或 Stream 版本建议先开启 EPEL 源再装因为基础 AppStream 源里的版本往往比较旧有些新配置文件里的选项不支持。网络环境如果有限制也可以先下载 RPM 包再离线安装yum install -y keepalived-*.rpm我在 CentOS 7 上装过 1.3.5也装过 2.0 以上的新版本配置文件基本兼容但新版对配置校验更严格很多旧的裸配置在新版里会直接报错。这个后面排错环节会详细说。2.2 Ubuntu/Debian 系安装Ubuntu 用 apt 安装更加省事apt update apt install -y keepalived这里有个容易踩的坑Ubuntu 默认可能没有装iproute2或者ipvsadm相关的包Keepalived 的 LVS 管理功能和 IP 地址操作需要这些工具的支持强烈建议一起装上apt install -y keepalived iproute2 ipvsadm tcpdumpUbuntu 装完后配置文件目录是/etc/keepalived/keepalived.conf如果你之前接触过 /etc/init.d 下的服务脚本会发现 systemd 接管之后启动方式有点区别后面我会演示怎么用 systemd 管理。2.3 源码编译安装当系统源里的版本太老或者你需要开启某些自定义编译参数时源码编译是最可靠的方式。我个人用源码装过 2.2.7过程不算复杂但很吃依赖安装编译依赖yum install -y gcc openssl-devel libnl3-devel net-snmp-devel # Ubuntu 上则是 # apt install -y build-essential libssl-dev libnl-3-dev libnl-genl-3-dev libsnmp-dev下载源码并解压wget https://keepalived.org/download/keepalived-2.2.7.tar.gz tar -zxvf keepalived-2.2.7.tar.gz cd keepalived-2.2.7配置编译选项./configure --prefix/usr/local/keepalived --enable-snmp make -j4 make install--enable-snmp适合需要接入监控系统的场景如果不需要就省掉。源码编译后要手动拷贝配置文件和启动脚本不是所有版本都会自动帮你做这一步mkdir -p /etc/keepalived cp keepalived/keepalived.conf /etc/keepalived/ cp /usr/local/keepalived/sbin/keepalived /usr/sbin/2.4 安装后快速验证无论哪种方式装完先用下面这组命令确认它能不能跑起来systemctl start keepalived systemctl enable keepalived systemctl status keepalived如果状态里出现active (running)说明服务正常但这时候没有配置文件它也会退出很多版本启动后如果找不到有效配置会直接报错。别慌先看日志tail -f /var/log/messages # 或者 Ubuntu 下 journalctl -u keepalived -f安装只是第一步真正让 Keepalived 产生价值的是配置。下一节我把 VRRP 协议和配置文件的对应关系拆开讲理解了原理配置就是照着填参数的事。3. VRRP 协议与高可用核心原理Keepalived 的灵魂是 VRRP不把这个协议弄明白配置出现问题时候你很难定位根因。3.1 VRRP 到底是什么VRRPVirtual Router Redundancy Protocol虚拟路由冗余协议是一个网络层的标准协议最初是路由器厂商为了解决单点故障设计的。它的核心思路是把多台物理设备虚拟成一台逻辑设备对外只暴露一个虚拟 IP。参与这台虚拟路由器的多台物理设备中优先级最高的会成为 Master负责处理请求其他的作为 Backup 待命。Keepalived 做的就是用软件把这个协议实现在 Linux 主机上。正常工作时Master 上会绑定虚拟 IP比如 192.168.1.100所有客户端访问这个 IP。Master 会周期性向组播地址发送 VRRP 广播报文告诉其他 Backup “我还活着”。如果 Backup 连续多次收不到报文就会认为 Master 挂了自动进入 Master 状态把虚拟 IP 绑到自己身上。这个过程在整个集群里是以秒级完成的对客户端来说是透明的这是它能广泛用于各种高可用场景的根本原因。3.2 优先级与状态机VRRP 的选举规则很简单实例的 priority 数值越大越有机会成为 Master。默认优先级是 100取值范围在 1 到 254 之间。通常我们让主机的优先级设成 150备机设成 100正常情况下主机会一直抢占虚拟 IP。注意几个细节报文每 1 秒发送一次vrrp_interval如果 3 秒内没有收到具体看配置的 advert_int就触发切换。抢占模式nopreempt默认开启意味着当原来挂掉的主机恢复后它会抢回 Master 身份。某些场景你可能想关闭抢占这样故障恢复后不立即切换避免抖动这在数据库主从切换时需要仔细考量。Keepalived 内部维护着一个状态机包括 INIT、BACKUP、MASTER 三个状态配置检查、脚本监测都在不同状态触发。3.3 虚拟 IP 漂移的完整过程咱们用一个实际例子演示漂移。两台机器主机 A192.168.1.11优先级 150主机 B192.168.1.12优先级 100虚拟 IP192.168.1.100正常时A 是 Master虚拟 IP 192.168.1.100 绑定在 A 的 eth0 网卡上。B 是 Backup不停监听组播报文。当 A 宕机注意是整机宕机不是 Keepalived 进程崩溃A 不再发送报文B 等待 3 秒后判断 Master 失联自动绑定虚拟 IP接管服务。这个接管过程不依赖任何第三方协调组件完全由对端机器自己决定所以非常可靠。如果只是 Keepalived 进程被杀掉而不是整机宕机它退出之前会主动发送一个优先级为 0 的报文告诉 Backup “我要走了你顶上”这样切换速度比超时等待更快。搞清楚原理之后配置就不再是死记参数了。下一节我们进入实战配置。4. 配置文件深度解析与主备实战配置Keepalived 的配置文件在/etc/keepalived/keepalived.conf它由全局定义global_defs、VRRP 实例vrrp_instance、脚本声明vrrp_script三大部分组成。我先逐块拆解再给一个完整可直接使用的配置。4.1 global_defs 全局配置全局配置影响运行级别和通知方式常用的选项有这些global_defs { router_id LVS_DEVEL vrrp_skip_check_adv_addr vrrp_strict vrrp_garp_interval 0 vrrp_gna_interval 0 }router_id是标识这台机器的字符串不强制唯一但对排错有用建议写成有业务含义的名称。vrrp_strict是很多排错问题的根源它在严格模式下会限定 VRRP 报文只能走指定的网卡如果配置不当会造成报文无法发出。如果你并不需要多严格的安全策略我建议去掉它很多莫名其妙的故障都是它引起的。4.2 vrrp_instance 实例配置一个实例代表一个虚拟路由器核心是先明确网卡、虚拟 IP 和优先级vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 150 advert_int 1 authentication { auth_type PASS auth_pass 1234 } virtual_ipaddress { 192.168.1.100/24 dev eth0 } }这里每个字段都有讲究state MASTER初始化状态。注意它不是选举的硬性依据真正决定谁是 Master 的是 priority只是一般约定主机写 MASTER、备机写 BACKUP。interface eth0VRRP 报文发送的网络接口必须和服务网卡一致。virtual_router_id同一组主备必须完全一致如果两台机器的这个数字不一致它们不会认为属于同一个虚拟路由器。priority优先级主机大于备机。advert_int报文发送间隔单位是秒默认 1 已经够快不建议小于 0.5 秒否则容易误判。authentication认证密码同一组必须一致最简单的是 PASS 类型另有 AH 类型但已不推荐。virtual_ipaddress要绑定的虚拟 IP 和掩码可以写多个用空格和 dev 指定不同的网卡。4.3 vrrp_script健康检查脚本虚拟 IP 漂移只解决“机器挂了”的问题但业务进程挂了、卡死了机器本身还活着VRRP 是感知不到的。这时候就需要健康检查脚本。典型的用法是为 Nginx 或 MySQL 写一个检查脚本vrrp_script chk_nginx { script /etc/keepalived/check_nginx.sh interval 2 weight -20 fall 2 rise 1 }脚本的返回值决定健康状态返回 0 表示正常非 0 表示异常。interval 2表示每两秒执行一次weight -20的含义要特别注意脚本失败时当前节点的优先级会下降 20。如果一个 MASTER 的优先级从 150 降到 130备机如果有 140 就会顶替它。这种设计是为了实现更平滑的切换。检查脚本需要可执行权限我一般这样写#!/bin/bash if [ -z $(pgrep nginx) ]; then exit 1 else exit 0 fi也可以做得更精细检查端口和服务响应#!/bin/bash curl -s -I http://127.0.0.1/health | grep 200 OK exit $?4.4 一份完整的主备配置案例假设我们要为两台 Nginx 做高可用主机 IP 是 192.168.1.11备机是 192.168.1.12虚拟 IP 是 192.168.1.100我直接把线上验证过的配置贴出来。主机/etc/keepalived/keepalived.confglobal_defs { router_id NGINX_MASTER vrrp_skip_check_adv_addr } vrrp_script chk_nginx { script /etc/keepalived/check_nginx.sh interval 2 weight -20 fall 2 rise 1 } vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 150 advert_int 1 authentication { auth_type PASS auth_pass 1234 } virtual_ipaddress { 192.168.1.100/24 dev eth0 } track_script { chk_nginx } }备机/etc/keepalived/keepalived.confglobal_defs { router_id NGINX_BACKUP vrrp_skip_check_adv_addr } vrrp_script chk_nginx { script /etc/keepalived/check_nginx.sh interval 2 weight -20 fall 2 rise 1 } vrrp_instance VI_1 { state BACKUP interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1234 } virtual_ipaddress { 192.168.1.100/24 dev eth0 } track_script { chk_nginx } }唯一明显的区别是 state 和 priority。加上track_script后Keepalived 会周期性执行检查脚本脚本失败就会扣减优先级从而触发切换。4.5 Nginx Keepalived 联动部署细节配置好之后还要在备机上考虑一个问题正常情况下备机没有虚拟 IPNginx 提供的服务是完全不可达的。但备机依然需要启动 Nginx因为一旦它接管虚拟 IP必须立刻对外提供服务。所以高可用服务不能做“故障时再启动业务进程”这种操作进程必须常驻Keepalived 只负责切换网络入口。我在实际部署中还发现一个容易忽略的点需要开启内核的 IP 非本地绑定这样 Nginx 才能监听虚拟 IP 上的端口而不报错sysctl -w net.ipv4.ip_nonlocal_bind1 echo net.ipv4.ip_nonlocal_bind1 /etc/sysctl.conf这个参数的含义是允许进程绑定本机不存在的地址针对的就是虚拟 IP 这种场景。备机没有虚拟 IP但 Nginx 也要提前监听 80 端口没有这个参数listen 虚拟 IP 或者 *:80 时会有问题。在使用 wildcard listen 的默认配置下影响不大但一旦你指定监听虚拟 IP这个参数是必须的。5. 虚拟 IP 漂移测试与故障切换验证配置完成后不能直接上线你得先做故障演练。不演练的高可用等于没有高可用这句话我在生产环境吃了亏之后才真正信了。5.1 测试前的检查清单先确认两台机器的 Keepalived 都正常启动systemctl status keepalived ip addr show eth0正常情况下主机上应该能看到虚拟 IP 192.168.1.100 已经绑定备机上没有。然后从任意客户端 ping 虚拟 IP确认通了。调用一次ip addr show在主机上的输出大概像这样eth0: BROADCAST,MULTICAST,UP,LOWER_UP mtu 1500 inet 192.168.1.11/24 brd 192.168.1.255 scope global eth0 inet 192.168.1.100/24 brd 192.168.1.255 scope global secondary eth05.2 手动模拟故障第一种做法停掉主机的 Keepalivedsystemctl stop keepalived正常切换到备机后等待大约 3 秒在备机上执行ip addr show eth0你应该能看到备机多出了 192.168.1.100。这种模拟的是进程级故障也是最容易测试的。第二种做法模拟业务进程故障。停掉主机 Nginxsystemctl stop nginx这时 track_script 检查脚本发现 Nginx 挂了会触发优先级降低把虚拟 IP 切换到备机。注意这里有个微妙之处检查脚本失败后权重扣减导致主机的优先级变为 130150 - 20小于备机的 100 吗并不会。你可能会发现切换没发生。这就是我要特别强调的weight的数值不是随便填的。主备切换的逻辑是“自己扣减后的优先级与对端当前优先级比较”。如果备机是 100主机 150 扣 20 变成 130仍然比 100 高不会切换。必须设置 weight 为 -50让主机的优先级降到 100 以下或者让备机的优先级设置为 120 以上这样才能保证切换发生。所以一个更合理的配置是主机 priority 150备机 priority 120weight -40这样主机扣减后为 110备机 120 就比它高了。或者主机 150备机 100weight -60。总之要保证“扣减后的优先级 对端优先级”这个不等式成立。5.3 切换过程中的观测手段推荐在备机上开一个实时监控窗口watch -n 1 ip addr show eth0 | grep 192.168.1.100同时另一个终端看日志tail -f /var/log/messages切换后日志里能看到类似下面这样的关键行Keepalived_healthcheckers: TCP connection to [192.168.1.11]:80 failed Keepalived_vrrp: VRRP_Instance(VI_1) entering MASTER STATE Keepalived_vrrp: VRRP_Instance(VI_1) using locally configured address 192.168.1.100看到entering MASTER STATE或transition to MASTER基本就说明切换成功了。有些版本还会打印VRRP_Instance(VI_1) Received higher prio advert这是主机恢复后抢占回去的日志。6. 常见报错排查实录keepalived exited with permanent error config这个报错是搜索量最高的 Keepalived 词条之一也是所有人最初遇到最多的拦路虎。Keepalived 在启动阶段如果发现配置有问题会直接退出并且日志里打出一句类似Keepalived: Starting Keepalived v2.0.10 Keepalived_healthcheckers: Initializing Keepalived_vrrp: VRRP is disabled or there is no valid vrrp instance defined Keepalived: Stopped Keepalived v2.0.10或者keepalived exited with permanent error config. Terminating看到 permanent error 这类字眼不要慌它的意思只是“配置不合法导致进程无法继续运行”不是系统崩溃。最常见的几个原因我一个个列出来。6.1 配置文件语法错误Keepalived 对书写格式要求很严格非常容易出问题的地方是遗漏括号、分号或者缩进错误。注意它不是用缩进表达层级而是用大括号{}包裹括号必须严格配对。一个典型错误是vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 150 }如果这里某一行忘了加分号比如interface eth0写成了interface eth0直接报错。排查最有效的方法是让 Keepalived 自己检查配置keepalived -t -f /etc/keepalived/keepalived.conf它会打印每一条配置项的校验结果错误行号直接给出来这是我最常用的排错命令。6.2 认证方式不匹配两台机器的auth_pass不一致或者authentication配置格式写错也会导致 VRRP 报文无法互相识别虽然不一定导致启动退出但会导致双方都认为自己是 Master产生 VIP 冲突。这个错误排查起来相对隐蔽因为它不是立即挂掉而是在日志里反复出现VRRP_Instance(VI_1) Dropping received VRRP packet如果出现这样的日志请第一优先检查两台机器的 virtual_router_id、auth_pass、interface 是否完全一致。6.3 virtual_router_id 不匹配这个值必须在 0 到 255 之间而且是同一组主备共享的。如果两台机器一个用 51、一个用 52它们根本不在同一个虚拟路由器里永远无法互相感知故障时备机不会接管 VIP。我遇到过一个现场配置都正常但切换就是无效排查半天发现小哥把备机的 virtual_router_id 从 51 改成了 50。6.4 vrrp_strict 模式导致的问题vrrp_strict启用后Keepalived 会丢弃非 VRRP 协议报文同时会要求报文严格遵守 RFC 标准。在多数业务环境里交换机或云平台可能不转发组播报文或者有其他特殊配置这会导致 Keepalived 无法接收对端消息出现脑裂split-brain两台机器同时持有虚拟 IP。我的建议是除非你对网络安全有明确要求否则不要轻易开启 vrrp_strict。在很多云主机环境里组播是默认不通的必须使用单播模式unicast_peer这个配置项也要仔细匹配。6.5 权限不足导致脚本无法执行跟踪脚本执行失败也容易误判成配置错误。检查脚本文件时要注意chmod x /etc/keepalived/check_nginx.sh很多初次使用的人只写了脚本内容忘了设置执行权限结果 Keepalived 每次执行脚本都得到非零返回值导致服务反复切换。我遇到过最夸张的一次是脚本里用了pgrep命令但脚本的 PATH 环境变量里没有包含/usr/bin导致一直提示 command not found解决方法是脚本内显式指定命令全路径。6.6 日志排查的完整命令当拿到 permanent error 提示后完整的排查链条是查看服务状态和日志:systemctl status keepalived journalctl -u keepalived -n 100手动校验配置keepalived -t -f /etc/keepalived/keepalived.conf前台调试运行不写成 daemonkeepalived -n -l -D -f /etc/keepalived/keepalived.conf-n表示不 fork-l表示日志输出到控制台-D打印更详细的信息。这条命令能让你在终端里实时看到所有 VRRP 报文收发情况和配置错误位置排查效率极高。抓包验证 VRRP 报文如果条件允许tcpdump -i eth0 vrrp -nn正常情况下每 1 秒应该能看到一条 Master 发送的 VRRP 报文方向是从主机到组播地址 224.0.0.18。如果什么都抓不到说明报文发不出去问题多半在网络侧或配置 interface 不对。6.7 其他常见问题速查表我这里把实践中遇到的高频问题整理成一个速查表方便你快速定位症状最可能原因排查命令/方法启动即退出 permanent error配置语法错误、括号不匹配keepalived -t -f看错误行两边都持有 VIP脑裂、认证不匹配、interface 不一致对比两台机的 virtual_router_id、auth_pass切换后服务访问不通业务进程未提前启动确认 Nginx/MySQL 常驻运行检查脚本触发切换失败weight 设置太小、脚本权限不足验证脚本手动执行 exit codeVRRP 报文无法互达云平台禁组播改用 unicast_peer 单播模式系统重启后 Keepalived 不启动未设置开机自启systemctl enable keepalived7. 实操细节与经验心得最后分享几个我在多套生产环境里沉淀下来的经验这些不是文档上能查到的但往往能帮你少走很多弯路。7.1 脑裂问题的极端解法脑裂是高可用里最害怕的问题两台机器同时持有虚拟 IP请求被分到两台机器如果后面是 MySQL两个写入就会产生数据错乱。VRRP 本身只是尽力避免不能完全杜绝。我通常的做法是在检查脚本里增加一个“对端 IP 存活检测”的逻辑脚本不仅检查本机服务还要 ping 对端物理 IP如果对端响应正常而本机不是 Master说明 VRRP 通信出现了故障这时候主动降低本机优先级或者干脆释放 VIP避免脑裂。下面是一个简化的思路放在检查脚本里#!/bin/bash # 检查对端物理IP是否可达 if ping -c 3 -W 1 192.168.1.11 /dev/null 21; then exit 1 fi # 检查本机Nginx if [ -z $(pgrep nginx) ]; then exit 1 fi exit 0注意这里有个逻辑悖论如果对端物理 IP 可达但虚拟 IP 却还在本机说明你可能是 Backup 抢成了 Master而原 Master 还活着。这种情况下退避是合理的。当然这种脚本要结合具体的网络环境调整不能照抄。7.2 切换体验优化VRRP 默认的切换时间在 3 到 5 秒之间对于一般应用完全够用。如果是数据库主从切换能接受这个冷备时间就没问题。如果你需要更快的体验可以把 advert_int 从 1 调整为 0.5 或更低Keepalived 官方推荐范围是 0.5 到 1太低的间隔会给 CPU 带来无谓消耗而且容易误判网络抖动。对于有状态的服务比如 Redis 主从、MySQL 主从切换后还要考虑数据同步。Keepalived 本身不解决这些问题它只负责把 IP 漂移过去。所以一定要在备机上配合好同步机制或者启动脚本否则切换到备机后业务依然不可写。我在 MySQL 高可用里见过很多次“VIP 已经漂移过去但数据库不能写”的案例根因就是忽略了数据同步。7.3 日志与监控的落地生产环境里Keepalived 的切换事件要第一时间通知到人。可以用 vrrp_instance 里的 notify_master 和 notify_backup 钩子来触发告警脚本notify_master /etc/keepalived/notify.sh MASTER notify_backup /etc/keepalived/notify.sh BACKUPnotify.sh 里可以写钉钉或企业微信的 webhook 推送把事件实时发给值班人员。这类事件是可观测的高可用切换信号比事后看到服务不可用再排查要强得多。7.4 配置变更的规范我现在每次改 keepalived.conf 都遵循一个固定流程先备份cp keepalived.conf keepalived.conf.bak.$(date %F)用keepalived -t校验配置。平滑重启而不是 stop 再 start。Keepalived 支持 SIGHUP 重载但说实话我更喜欢直接systemctl reload不支持的版本就用 restart。在双机环境下注意先改备机后改主机避免重启过程中窗口期的风险。观察切换是否发生在预期时间。这套流程虽然看起来死板但真的能帮你规避大量低级事故。高可用系统最怕的不是故障而是故障时人为操作引入的新故障。8. 结尾一次真实故障切换的复盘有一次半夜业务方反馈网页时好时坏让排查 Nginx 是否又挂了。我看了一眼 Keepalived 的状态发现日志里出现了频繁的 MASTER 切换间隔大约每五分钟一次。进一步查才发现检查脚本里用curl -s -I探测一个后端健康接口那个接口偶尔会突破 2 秒超时脚本干脆直接超时判定失败导致主备来回漂移。那次事故之后我把所有健康检查脚本都统一成“先本地快速检查再后端慢检测”的两段式结构并且把超时时间调大配合fall 2的两次失败判定。从那以后Keepalived 的切换记录基本都发生在真正的故障降级或者机房割接时。说实话Keepalived 这个工具技术含量不算高但它承载的“入口 IP 永不失效”这个理念是所有高可用架构的地基。它本身轻量、成熟、稳定只要你还做服务器运维就有很大的概率遇到它。希望这篇文章能帮你把它的原理、配置和排错串成一条完整的线让你从“抄配置”变成“懂配置”真到故障发生的时候能多一份从容。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑