生产环境里最怕什么不是流量大也不是业务复杂而是某个核心服务半夜悄悄挂了等用户发现的时候已经在群里炸锅了。我前几年被这种单点故障坑过好几次后来把所有关键服务都做了高可用改造用到的核心工具就是 Keepalived。这玩意儿看着不起眼但在 Linux 服务器的故障切换、虚拟 IP 漂移这块绝对是老兵级别的存在稳定可靠部署起来也不复杂。这篇内容我不打算照抄官方文档而是把我在实际项目中安装、配置、启动 Keepalived 的完整过程连同踩过的坑和验证方法一起写出来。不管你是用 CentOS、Ubuntu 还是 Other 发行版只要跟着操作再加上最后的故障排查清单基本能搞定绝大部分场景。1. 为什么选择 Keepalived单点故障的解决办法1.1 从一次生产事故说起有一年我们线上有个核心支付服务跑在一台物理机上服务本身很稳结果凌晨四点多机房那台机器因为内存故障直接重启了。等我们赶到业务已经断了快四十分钟那一次损失的不只是钱还有客户信任。事后复盘的时候大家达成一个共识必须给核心服务做高可用当时列了几个方案最后选的就是 Keepalived。Keepalived 能在 Linux 环境中提供高可用能力核心原理是 VRRP 协议虚拟路由冗余协议。简单说它让两台机器像一对“双胞胎”共享一个虚拟 IP对外只用这个 VIP 提供服务。正常时只有一台机器MASTER持有 VIP 并处理流量另一台BACKUP在后台待命。一旦 MASTER 挂了或者服务异常BACKUP 会立刻顶上把 VIP 抢过来继续提供服务。整个过程对外几乎是透明无感的用户还是访问同一个 IP业务不会中断。Keepalived 的高可用方案之所以在 Linux 下面特别流行一是因为它轻量不依赖额外的分布式协调组件不像 etcd、Consul 这类还要维护一个集群二是因为它配置直白核心就是一个 keepalived.conf 文件没有太多弯弯绕绕的学习成本三是因为它的故障切换速度快配合健康检查脚本几秒钟内就能完成主备切换很多业务都能接受这个时间窗口。如果你的核心业务也没到需要复杂分布式共识算法的程度Keepalived 绝对是性价比最高的选择。1.2 VRRP 协议与 Keepalived 的工作机制要理解 Keepalived先要懂一点 VRRP 协议。VRRP 的初衷是为了解决路由器单点故障的问题它把一组路由器编成一个虚拟路由器组组内的路由器通过多播报文组播地址 224.0.0.18互相通告状态。组里有一个 MASTER其他都是 BACKUP。MASTER 会定期发送 VRRP 通告报文声明“我还活着”。BACKUP 收到报文后就知道 MASTER 正常自己不抢 VIP。如果 MASTER 超过一定时间没发报文BACKUP 就会认为 MASTER 挂了开始选举新的 MASTER并接管虚拟 IP。Keepalived 把这套机制从路由器搬到了 Linux 服务器上。每一台运行 Keepalived 的 Linux 主机都会周期性地发送和监听 VRRP 多播报文。你可以把 Keepalived 想象成一个“状态广播器”加“IP 管家”MASTER 和 BACKUP 之间靠 VRRP 报文来同步状态VIP 的漂移则通过内核接口配置来完成。用户请求到达交换机时交换机并不知道 VIP 在哪个物理机上它只是按 VIP 把数据包送进来而 VIP 所在的机器会响应 ARP把流量接收到对应的网络接口上。谁持有 VIP谁就承担流量。这里有个细节容易忽略VIP 虽然通常只配置在一个网卡上但 VRRP 的报文是通过物理网卡广播出去的。两台机器必须在同一个二层网络里而且组播报文不能被防火墙拦截。这就是很多人配置完成后发现 VIP 不生效的一个重要原因。关于防火墙的问题我在后面的故障排查部分会专门讲。1.3 适用场景与方案选型对比Keepalived 常见的使用场景有三类第一类是给 Nginx、HAProxy 这些负载均衡器做高可用两台机器上面各跑一套负载均衡Keepalived 保证 VIP 在主备之间切换第二类是给 MySQL、Redis 这类数据库服务做主从切换时的 IP 漂移客户端只需要记住一个 VIP数据库在主从之间切换时VIP 自动绑定到新的主库业务代码不需要改第三类是和 LVS 结合做负载均衡集群的“调度器”这也是 Keepalived 最初最经典的用法通过 LVS 分发流量到后端的真实服务器。我整理了一个简单的对比表方便你在做技术选型的时候参考方案核心协议/机制适用场景优点短板KeepalivedVRRP双机热备、VIP 漂移、网关高可用轻量、配置简单、切换快速只能做 2 台到多台主备不能做大规模集群HAProxyTCP/HTTP 代理七层/四层负载均衡功能丰富、支持健康检查、ACL自身也有单点需要配合 KeepalivedLVS内核级负载均衡高吞吐量的四层负载性能极高、稳定部署复杂需要维护调度器和后端etcd/Consul分布式共识服务注册发现、分布式锁强一致性、自动化程度高部署重、需要多个节点、维护成本高如果只是做基础的“双机互备”“主备切换”Keepalived 绝对是首选它不需要额外引入一堆依赖组件部署成本极低。尤其是当你的系统已经跑了一堆业务想在不改动业务代码的前提下引入高可用Keepalived 是最快的路径。2. 安装前的准备环境检查与网络规划2.1 服务器环境要求与版本选择在动手安装之前先要把环境摸清楚。Keepalived 对硬件要求极低哪怕是 1 核 1G 的虚拟机也能跑得很欢快但有一个关键前提两台机器的系统架构和内核版本不能差得太离谱否则 VRRP 报文的处理可能会有兼容问题。我实际部署过 CentOS 7 搭配 keepalived-1.3.5也部署过 Ubuntu 20.04 搭配 keepalived-2.0.20两者都稳定运行。具体到 Linux 发行版Debian/Ubuntu 系列和 CentOS/RHEL 系列在安装命令上有明显差异一个用 apt一个用 yum/dnf。如果你的系统是国产 Linux比如麒麟、统信 UOS大部分底层还是基于 Debian 或 CentOS 的你可以先用cat /etc/os-release看一下系统版本再选择对应的包管理器。如果包仓库里的 keepalived 版本太老或者安装不上那就直接走源码编译这条路后面我会详细讲。版本选择上我个人建议不用一味的追新。Keepalived 1.3.x 和 2.x 在基础功能上差别不大最核心的 vrrp_instance 配置格式基本一致。生产环境选 2.0.20 以上的版本比较保险因为一些早期 2.0 版本的 bug 已经在后续版本修复了。如果是新装系统直接用系统默认软件源的版本即可除非你需要某些新特性比如更细粒度的健康检查能力才考虑源码编译。2.2 IP 地址规划与虚拟 IP 设计网络规划这一步很多人会跳过觉得无足轻重其实这是后面配置里最容易出错的地方。我见过不少同事把 VIP 和业务 IP 规划在同一个网段导致交换机 ARP 表混乱出现 VIP 冲突。正确的做法是两台服务器的物理 IP 在同一个网段VIP 也使用这个网段的地址但一定要确保 VIP 没被其他设备占用。举个例子假设两个节点信息如下节点角色网卡物理 IP虚拟 IPnode1MASTEReth0192.168.1.101192.168.1.200node2BACKUPeth0192.168.1.102192.168.1.200此时 VIP 是 192.168.1.200两台服务器的物理 IP 分别 .101 和 .102。VIP 一开始绑在 node1 上node1 挂掉后VIP 自动切到 node2。这里需要注意VIP 最好不要做成 DHCP 分配最好是从静态 IP 池里单独预留一个出来。如果网络里已经有人用 .200 当固定 IP你把它配置成 VIP 就会冲突业务会被莫名其妙地被拦腰切断。所以我每次都会在部署前用ping 192.168.1.200测一下延迟和通断确认这个 IP 当前是空闲状态。记录网络信息的配置文件应该始终保留一份比如/etc/hosts或内部 CMDB。Keepalived 的配置文件里不直接写主机名映射也能工作但加上主机名会方便后面维护和排查日志。别问我怎么知道的当你有几十台 Keepalived 主机没标注的时候看日志简直是噩梦。2.3 关闭防火墙干扰与配置放行规则防火墙这一步是安装配置前很重要的事情但经常被忽略。VRRP 报文走的是 IP 协议号 112不是常见的 TCP/UDP 端口Linux 防火墙很多时候默认会拦掉这类静悄悄的多播协议。别着急直接systemctl stop firewalld生产环境直接关防火墙是要背责任的。正确做法是放行 VRRP 协议相关流量。如果是 CentOS/RHEL 7 系使用 firewalld可以用以下命令放行firewall-cmd --direct --permanent --add-rule ipv4 filter INPUT --protocol vrrp --in-interface eth0 --action accept firewall-cmd --reload注意这个命令里--in-interface eth0要换成你机器上实际的网卡名可以用ip addr查看。如果机器上的网卡是 ens33、enp0s3 这类名字就直接替换。如果是 Debian/Ubuntu 系的 ufw操作更简单ufw allow in on eth0 proto vrrp ufw reload这里有个小陷阱某些版本的 ufw 对 proto vrrp 支持得不好写不进去。遇到这种情况可以改用 iptables 直接添加规则iptables -A INPUT -p vrrp -i eth0 -j ACCEPT把这条命令写入 /etc/rc.local 或 ufw init 脚本里让它开机自动加载。我在 Ubuntu 20.04 上就遇到过 ufw 死活认不了 vrrp 协议最终就是直接用 iptables 解决的。除了防火墙也许需要看一下 SELinux 的状态。CentOS 7 默认开启 SELinux某些版本下会阻碍 Keepalived 的操作。最简单的办法是把 SELinux 设置为 permissive但不建议直接 disabled因为 disabled 需要重启系统。关于 SELinux 的具体策略配置我在第 6 部分的故障排查里会展开说明这里先提个醒。2.4 时间同步与基础依赖安装时间同步在分布式环境里是铁律Keepalived 虽然不像数据库日志那样对时间极度敏感但主备两台机器如果时间相差太大排查日志和定位切换问题时会出现误导。建议两台机器都配置 NTP 或 chrony 同步保持时间一致。如果是内网环境就搭一台内部时间服务器或者用其他来源确保时间源稳定。基础依赖方面如果用包管理器安装Keepalived 会自动拉取依赖不需要额外准备。唯一要注意的是如果后面准备做健康检查脚本某些脚本里用到的命令比如 curl、nc、mysqladmin 等需要提前装好。比如要检查 MySQL 是否存活就得先有 mysql 客户端工具。这不是 Keepalived 的依赖但它是你脚本的依赖别等到写脚本的时候才发现机器上没装。3. 安装 Keepalived二进制包与源码编译双路走3.1 使用包管理器快速安装CentOS / Ubuntu最快的方式就是使用操作系统的包管理器直接安装没问题。对于 CentOS/RHEL 系列yum install -y keepalived如果需要 epel 源支持可以先执行yum install -y epel-release。安装完成后可以通过rpm -qa | grep keepalived确认安装版本也可以通过keepalived --version或者keepalived -v查看。CentOS 8 以上用的是 dnf命令上基本兼容直接dnf install -y keepalived即可。Ubuntu/Debian 系列apt update apt install -y keepalived安装完成之后确认一下版本号keepalived --version系统软件源里的版本可能不会特别新但胜在方便稳定。对于生产环境来说稳定第一我经常看到很多人喜欢装最新版但除非新版本修复了你遇到的问题否则没必要费这个劲。官方软件源版本经过长时间测试和系统里其他库的兼容性通常也是最好的。3.2 源码编译安装从官网下载到 make install有时候官方源里的 Keepalived 版本太老或者你需要自定义编译参数那就走源码编译这条路。编译之前需要先安装依赖又是 Debian/Ubuntu 和 CentOS 不同的地方。CentOS 上先执行yum install -y gcc openssl-devel libnl3-devel net-snmp-devel # libnl 和 snmp 是很多 keepalived 功能可选的依赖Ubuntu 上执行apt install -y build-essential libssl-dev libnl-3-dev libnl-genl-3-dev libsnmp-dev libpopt-dev然后下载源码包。Keepalived 的源码可以从官网 GitHub Release 页面下载也可以在 Linux 官网镜像站找。以 2.2.8 版本为例wget https://github.com/acassen/keepalived/archive/refs/tags/v2.2.8.tar.gz tar -zxvf v2.2.8.tar.gz cd keepalived-2.2.8 ./configure --prefix/usr/local/keepalived make make install编译的时候./configure会输出很多检测信息比如“Use IPVS Framework: No”“Use SNMP: Yes”等。如果某些库没找到对应的特性就会被禁用但不影响基本功能。编译完成之后二进制默认安装在/usr/local/keepalived/sbin/keepalived配置文件在/usr/local/keepalived/etc/keepalived/keepalived.conf。需要自己手动把它链接到系统标准路径或者直接用绝对路径启动。我习惯的做法是ln -s /usr/local/keepalived/sbin/keepalived /usr/sbin/keepalived mkdir -p /etc/keepalived cp /usr/local/keepalived/etc/keepalived/keepalived.conf /etc/keepalived/同时把 service 文件放到 systemd 目录下。源码包里一般会带一个keepalived.service文件它可能在keepalived-2.2.8/keepalived/etc/目录里复制到/usr/lib/systemd/system/即可。编译安装的好处是版本可控、路径可控坏处是后续升级和维护都要自己管。如果你不是对 Keepalived 版本有特殊要求我实际测试下来还是建议直接用系统包管理器装省心。源码编译适合那些确实需要定制特性的场景。3.3 安装验证查看版本与服务状态不管用哪种方式安装装完之后都要做一次基础验证。第一步看版本确认可执行文件能跑起来keepalived --version keepalived -v如果输出了一堆编译参数和版本信息说明二进制安装成功。第二步看帮助文档确认命令参数可用keepalived --help第三步在配置还没有写好的情况下不要急着启动服务否则会看到一堆配置加载失败的报错。可以先看一下服务文件是否存在Ubuntu 上用systemctl list-unit-files | grep keepalivedCentOS 上一样。如果系统没有自动创建 systemd unit 文件编译安装的话就要手动创建使用包管理器安装一般会自动创建好。这一步确认完就说明安装阶段已经结束了。接下来进入最核心的部分配置。4. 核心配置解析从全局到实例的完整写法4.1 配置文件结构与三大模块Keepalived 的配置文件默认在/etc/keepalived/keepalived.conf。整个配置文件本质上可以按功能切分为三块全局配置global_defs、VRRP 实例配置vrrp_instance、虚拟服务器配置virtual_server。对于只做双机热备和 VIP 漂移的场景我们用前两块就够了virtual_server 是给 LVS 负载均衡用的这里先不做展开。配置文件的结构非常亲民有点像 INI 和 C 语言嵌套结构体的结合体。每一层用花括号包起来配置项之间用空格或缩进区分。需要注意的是Keepalived 对格式要求严格一个花括号的位置错了后面的配置可能直接加载失败。我见过很多人把配置写完结果 Keepalived 报错说unknown keyword最后排查下来就是括号不匹配或者某一行多了一个 Tab。比较稳妥的习惯是所有配置项全部对齐花括号的前半部分写在配置项名字同一行后半部分单独一行。这样不仅可读性好也方便用no去临时注释某段配置来排查故障。4.2 全局配置global_defs与日志优化global_defs是整个 Keepalived 进程的全局参数它不像 VRRP 实例那样直接关系到主备切换但是写好了能让运维在排查问题时轻松许多。一个生产环境可用的 global_defs 大约是下面这个样子global_defs { notification_email { opsexample.com } notification_email_from adminexample.com smtp_server 127.0.0.1 smtp_connect_timeout 30 router_id LVS_NODE1 vrrp_skip_check_adv_addr vrrp_strict vrrp_garp_interval 0 vrrp_gna_interval 0 }其中notification_email和smtp_server是配置邮件告警的Keepalived 在发生状态切换时会发送邮件通知。不过现在很多运维已经不用这个了因为邮件延迟较大而且需要本地有可用的 SMTP 服务配置起来麻烦。更常见的做法是利用 notify 脚本或微信/webhook 告警后面的部分我会介绍。router_id是一个字符串它唯一标识运行 Keepalived 的这台主机在 VRRP 组内必须保证每台机器有独立的 router_id。比如 node1 叫LVS_NODE1node2 就叫LVS_NODE2。如果不设置Keepalived 会默认取主机名。这里还有两个重要的 vrrp 选项vrrp_skip_check_adv_addr表示跳过通告报文中的源地址校验vrrp_strict则会让 Keepalived 遵循更严格的 VRRP 规范这个选项在某些场景下会导致 VIP 无法 ping 通我一般建议如果不了解后果就别开启 vrrp_strict开着默认就好。4.3 VRRP 实例配置MASTER 与 BACKUP 的完整示例VRRP 实例就是主备切换的具体实现。它的核心字段是state、interface、virtual_router_id、priority、advert_int、authentication和virtual_ipaddress。先看一个经典的 MASTER 配置vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 150 advert_int 1 nopreempt authentication { auth_type PASS auth_pass 1234 } track_script { chk_nginx } virtual_ipaddress { 192.168.1.200/24 dev eth0 } notify_master /etc/keepalived/notify.sh master notify_backup /etc/keepalived/notify.sh backup notify_fault /etc/keepalived/notify.sh fault }对应 BACKUP 节点的配置整体结构一模一样只有几处需要改把state MASTER改成state BACKUPpriority改成比 MASTER 低的值比如 100。virtual_router_id必须保持一致auth_pass也必须一致否则两台机器无法成为同一个 VRRP 组的成员主备之间互相不认识就会出脑裂问题。具体字段解释一下state这是实例的初始状态告诉 Keepalived 启动时先按 MASTER 还是 BACKUP 跑。但要注意它只是初始状态真正谁成为 MASTER 是由 priority 决定的不要以为设置了 MASTER 就永远不受影响。interfaceVIP 绑定的网卡必须和物理网卡名一致。virtual_router_idVRRP 组识别号范围是 0 到 255。这个 ID 在同一网段内不能冲突否则多个 Keepalived 组会互相干扰。例如你网段里有多组高可用集群建议使用不同的 virtual_router_id比如 51、52、53。priority优先级范围 1 到 254数字越大越容易成为 MASTER。advert_intVRRP 通告间隔单位是秒默认 1 秒。MASTER 每隔 1 秒发一次通告BACKUP 如果在 3 倍时间3 秒内没收到通告就会抢占成为新 MASTER。authentication认证信息PASS 表示简单密码认证下面auth_pass是密码。两台机器必须完全一致。virtual_ipaddress虚拟 IP 列表可以写多个 VIPKeepalived 会在成为 MASTER 时自动配置切换时自动删除并绑定到新 MASTER 上。注意一个容易踩的坑auth_pass在 PASS 方式下只使用前 8 位字符如果你写了一个超过 8 位的密码超过部分会被忽略两台机器之间只要前 8 位一致就可以通信但这个行为很容易让你误解“我密码明明改了啊为什么两台还能互通”进而怀疑配置有问题。生产环境建议直接写 8 位以内的密码省得踩这个坑。4.4 健康检查脚本服务挂了自动切换VRRP 协议本身只检查主机存活状态也就是说只要 Keepalived 进程还活着即使上面的 Nginx 已经挂了MASTER 也不会甩掉 VIP。这就失去了高可用的意义。所以我们还需要一层业务层面的健康检查也就是track_script。健康检查的思路很简单写一个脚本检查被保护的服务比如 Nginx 或 MySQL是否正常。如果正常脚本返回 0如果不正常脚本返回非 0。然后把脚本路径写到 track_script 模块里Keepalived 会周期性地执行它如果发现脚本返回非 0就会认为当前节点的业务已经不可用主动降低优先级甚至退出 MASTER 状态把 VIP 让给 BACKUP。一个常用的 Nginx 存活检测脚本如下#!/bin/bash # /etc/keepalived/check_nginx.sh if kill -0 $(pgrep nginx | head -1) /dev/null; then exit 0 else exit 1 fi如果有多个 Nginx 进程pgrep nginx | head -1取出第一个进程号kill -0 只是探测进程是否存在不会真的发送信号。如果直接使用 systemd 管理的服务也可以用systemctl is-active nginx来检测但要注意 nginx 的 systemd unit 是否配置正确否则is-active的结果不可靠。把这个脚本保存好并赋予执行权限chmod x /etc/keepalived/check_nginx.sh然后在 vrrp_instance 段顶部或者配置文件中加入track_script { chk_nginx }这里的chk_nginx是一个脚本名需要和脚本内容所在的位置对应。Keepalived 的 track_script 配置有几种写法一种是直接把脚本路径写到脚本标签里另一种是在较新版本中直接指定路径。比如这样vrrp_script chk_nginx { script /etc/keepalived/check_nginx.sh interval 2 weight -20 fall 2 rise 2 }其中interval 2表示每 2 秒执行一次weight -20表示脚本返回非 0 时优先级减 20 分fall 2表示连续失败 2 次才认为服务不可用rise 2表示连续成功 2 次才认为服务恢复。这样就能有效避免瞬时抖动造成的误切换虽然会稍微牺牲切换速度但换来了稳定性。我在实际操作中还会额外加一个逻辑如果 Nginx 挂了不要光等 Keepalived 切到 BACKUP还可以尝试自动拉起 Nginx。脚本可以做成先检测如果挂掉就尝试重启服务重启失败再返回非 0让 Keepalived 切换。这样一个简单的自愈脚本能解决很大一部分夜间无人值守的问题。4.5 一个可以直接抄作业的双机配置示例把上面这些内容拼起来我给你一套完整可用的配置。假设是两台 NGINX 服务器做高可用VIP 是 192.168.1.200MASTER 机器node1的/etc/keepalived/keepalived.confglobal_defs { router_id LVS_NODE1 } vrrp_script chk_nginx { script /etc/keepalived/check_nginx.sh interval 2 weight -20 } vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 150 advert_int 1 authentication { auth_type PASS auth_pass 1234 } track_script { chk_nginx } virtual_ipaddress { 192.168.1.200/24 dev eth0 } }BACKUP 机器node2的/etc/keepalived/keepalived.confglobal_defs { router_id LVS_NODE2 } vrrp_script chk_nginx { script /etc/keepalived/check_nginx.sh interval 2 weight -20 } vrrp_instance VI_1 { state BACKUP interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1234 } track_script { chk_nginx } virtual_ipaddress { 192.168.1.200/24 dev eth0 } }两张配置唯一区别就是 state 和 priority。把两份配置分别放到两台主机的/etc/keepalived/keepalived.conf然后启动服务。日常维护中如果需要主动切换最粗暴的方式是临时把 MASTER 的 Keepalived 停掉让它变成故障状态VIP 自然切到 BACKUP更加平滑的方式是写一个脚本降低 MASTER 的 priority 再通知 Keepalived 重新加载。注意一个细节两台机器上的check_nginx.sh脚本都要提前放好并赋予执行权限。否则 track_script 报错Keepalived 可能无法正常进入 MASTER 状态或者反复重启。5. 启动服务、开机自启与主备切换验证5.1 启动 Keepalived 服务与查看运行状态配置写好之后先做个配置文件语法检查。Keepalived 本身没有像 nginx -t 那样特别完善的检查参数但我们可以用keepalived -t或者keepalived --config-test检查配置。如果版本较老可能不支持-t那就直接启动试试看日志输出。我实际使用中keepalived -t在 2.0.20 和 2.2.8 上都能正常支持建议在启动前执行一遍keepalived -t -f /etc/keepalived/keepalived.conf如果输出Configuration file syntax is OK说明配置没有语法问题。注意-f参数是指定配置文件路径默认就是/etc/keepalived/keepalived.conf可以不写。然后启动服务systemctl start keepalived systemctl enable keepalived systemctl status keepalivedenable这一步千万别省否则机器重启后 Keepalived 不会自动拉起VIP 也不会回来你的高可用就变成“手动可用”了。我刚入行时就在这上面吃过亏后来把所有节点都改成开机自启才安心。启动之后查看日志和 VIP 状态journalctl -u keepalived -f ip addr show eth0如果一切正常MASTER 机器的 eth0 上应该能看到 VIP 192.168.1.200BACKUP 机器上只看得到物理 IP。日志里会打印类似Entering MASTER STATE的字样。如果 VIP 没出现先别急继续往下看排查清单。5.2 验证虚拟 IP 是否绑定、主备是否正常验证步骤我建议分成三层第一层是看 Keepalived 进程状态第二层是看 VIP 是否绑定第三层是实际访问 VIP 上面的服务。先看进程ps -ef | grep keepalived正常会有 3 个进程父进程、VRRP 子进程、健康检查子进程分别对应 Keepalived 的守护进程、VRRP 模块和 check 模块。再看 VIP 绑定ip addr show eth0在 MASTER 节点上能看到类似inet 192.168.1.200/24 scope global secondary eth0的输出说明 VIP 绑定成功。这时从局域网内其他机器ping 192.168.1.200应该能通。如果 ping 不通优先检查防火墙规则确认 VIP 相关的流量没有被拦。最后是业务层验证如果 VIP 后面是 Nginx直接访问 VIP 的 80 端口如果是 MySQL用 mysql 客户端连接 VIP。这一步的意义在于有时候 VIP 能 ping 通但后端的服务没起来用户请求照样失败。只有业务层验证通过才算真正的高可用。5.3 模拟主备切换手动故障演练高可用系统最怕“纸上谈兵”配置完一定要做一次故障演练。最简单的演练方式就是停掉 MASTER 的 Keepalived 服务systemctl stop keepalived然后到 BACKUP 机器上看它的状态正常情况下几秒内它就会成为新的 MASTERVIP 会出现在它的网卡上ip addr show eth0 # 在 BACKUP 上执行接着从客户端访问 VIP业务应该仍然正常。再把 MASTER 的 Keepalived 启动起来观察 VIP 是否会切换回来。关于回来这件事需要看你是否配置了nopreempt。如果没有nopreempt默认情况下 BACKUP 在抢到 MASTER 之后一旦原来的 MASTER 恢复优先级高的机器会立刻抢回 VIP也就是会再次发生切换导致业务出现两秒钟的抖动。如果配置了nopreempt原来的 MASTER 恢复后不会立即抢占需要等到 BACKUP 主动让位或故障时才会切换回来。这个特性对于需要避免频繁切换的场景非常有用但要注意nopreempt只在state BACKUP的节点上配置才有效如果两台都是 MASTER 初始状态行为会有些差异。实际生产环境我更推荐配置nopreempt减少无意义的切换。演练过程中用journalctl -u keepalived -f跟踪日志可以看到状态切换的完整过程BACKUP 收到 MASTER 停止通告进入竞选状态然后成为 MASTER绑定 VIP。这些日志是后面排查问题和理解机制的第一手资料。6. 常见问题与排查技巧实录6.1 VIP 不浮动/不生效的常见原因这是 Keepalived 部署中最常见的问题表现是两台机器都启动了VIP 却始终没有出现在任何一台机器的网卡上或者 VIP 在 MASTER 上但停掉 MASTER 后 VIP 没有转移到 BACKUP。我遇到的情况大致有这些第一防火墙拦了 VRRP 报文。这个问题在文章前面的环境准备部分已经提过排查的时候先在两台机器上执行tcpdump -i eth0 vrrp如果能抓到 VRRP 多播包说明报文在网络上流通如果什么都抓不到多半是防火墙拦截或者网卡没加入多播组。按上面的防火墙放行规则加好规则再试实在不行先临时systemctl stop firewalld做测试确认是这个原因后再精细化放行。第二virtual_router_id不一致。两台机器的 vrrp_instance 的 ID 必须一致这个 ID 在网段内不能和别的集群冲突。检查方法很简单比对两份配置逐行 diff。第三auth_pass不一致。前 8 位不一致会导致两台机器互相不认为对方是同一个 VRRP 组的成员即使偏要“互相认领” VIP也会出现交换信不过的问题。解决方法是严格统一密码。第四网络二层隔离问题。VRRP 使用组播如果交换机启用了组播过滤或者端口隔离多播包可能到不了对端。这种情况在云环境比较少见在物理机或者混合网络下要重点检查。处理方案是不使用多播模式改用单播模式在 vrrp_instance 里配置unicast_peer。这个能力 Keepalived 是支持的部分云平台下 VIP 是虚拟出来的还得配合厂商的 ARP 配置才能完美工作。6.2 脑裂问题两台机器同时持有 VIP脑裂是集群高可用方案里必须警惕的故障。当主备节点之间的通信链路出了问题或者 VRRP 报文被隔离BACKUP 因为长期收不到 MASTER 的通告也会在超时之后把自己提升为 MASTER两台机器同时绑定同一个 VIP流量就会乱套。它不仅会造成服务异常还会让写请求同时打到两个主库上引发数据不一致。防止脑裂的办法有几层。第一层是配置合理的 authentication确保只有合法节点才能加入 VRRP 组。第二层是在配置里加上nopreempt可以减少恢复时的切换抖动但并不能根治链路断开的问题。第三层是在业务层面做一些检测比如两个节点都去写一个共享的锁或数据库记录保证同一时刻只有一个主节点。我见过不少比较严苛的环境会在业务代码里再加一层控制Keepalived 只负责 IP 漂移业务层自己也有选举机制。如果怀疑出脑裂最快的判断方法是在两台机器上同时执行ip addr show | grep 192.168.1.200如果两台都显示有这个 IP那基本就是脑裂了。接着查看各自日志分析是谁先抢的 VIP再回头查物理链路、修防火墙配置。6.3 配置格式错误括号、缩进和空格问题Keepalived 对配置文件的格式要求很严格我见过不少人在手写配置时把virtual_ipaddress写成了virtual_ipaddress {}的嵌套结构或者漏了一个花括号结果 Keepalived 启动报错。常见错误包括花括号不匹配、配置项拼写错误、多余的空格和 Tab 混用。排查方法是先用keepalived -t检查语法然后逐个模块注释排查。启动时报错会在日志里明确说明“parse error”和具体行号仔细看日志通常能定位到问题。也可以用tcpdump辅助判断配置是否真的生效如果 Keepalived 正常运行但没有输出 VRRP 报文多半是配置里的 interface 写错了网卡名。另外一个不太显眼的问题是auth_pass包含特殊字符。如果密码里有!、#等特殊符号在某些 shell 环境下会被解释导致实际密码和配置文件里的不一样。建议密码只用数字和字母长度控制在 8 位以内省去无谓的麻烦。6.4 内核日志、SELinux 与云环境的兼容提醒Keepalived 和 SELinux 的兼容性是个常被忽视的问题。在 CentOS 7 上默认 SELinux 开启时Keepalived 可能无法正常绑定 VIP日志里会看到类似Cannot assign requested address的报错。这时候可以临时测试关闭 SELinuxsetenforce 0如果服务立刻正常说明就是 SELinux 的锅。生产环境不建议长时间关闭 SELinux更好的办法是为 Keepalived 定制策略或者将相关端口和协议加入白名单。如果对 SELinux 定制不熟悉至少把 SELinux 设置为 permissive既能保证系统安全基线又不影响服务运行。云环境下的 Keepalived 需要注意另一个问题部分公有云平台不支持自定义 VIP或者说 VIP 只能通过平台的负载均衡服务来实现。因为公有云上通常没有“两者的物理网卡在同一个二层网络”这个前提多播和 ARP 行为也会被虚拟化网络限制。所以在云平台上使用 Keepalived 之前一定要先和平台确认清楚是否支持。如果不支持可以考虑用云平台自带的 SLB、CLB、负载均衡产品替代效果是一样的只是实现上不听你指挥而已。7. 实操心得与进阶建议最后说一点我在实际运维中的体会也给刚接触 Keepalived 的朋友一些可操作的进阶建议。配置文件中我强烈建议把健康检查脚本和 keepalived.conf 纳入 Git 管理。这个习惯让我在多次节点扩容和环境迁移时省了大量时间——新机器直接拉代码、装依赖、跑脚本就行不用两台机器对着配置反复比对。另一个经验是不要让 Keepalived 节点只有“活着”和“挂掉”两种状态一定要配合业务层面的健康检查。VRRP 协议本身只关心 Keepalived 进程除非你写了 track_script否则 Nginx 挂了你都不知道。我见过一些团队部署完 Keepalived 就不管了等业务报警才发现后端服务已经挂了半小时VIP 却还留在那个坏节点上。这个教训成本太高了。如果是在更大型的场景里使用 Keepalived可以考虑多实例配置。比如一个节点上同时跑两个 vrrp_instance一个做 Nginx 的 MASTER另一个做 Redis 的 BACKUP这样两台机器都能发挥余热实现真正的互备而不是一台常年空闲。这种配置并不复杂相当于把两份 vrrp_instance 写进同一个配置文件只要注意 virtual_router_id 不同就行。还有一个小技巧在 vrrp_instance 里配置notify_master、notify_backup、notify_fault脚本。状态切换时自动执行脚本把切换消息推送到钉钉、企业微信或者短信网关。这样无论什么时候发生切换你都能第一时间知道不用等用户来投诉。我当时写了一个简单的 notify 脚本接收状态参数然后调用 webhook整个过程不过 20 行 shell 代码但收益非常大。Keepalived 这个工具虽然已经有年头了但在 Linux 高可用方案里依然非常能打值得花一天时间好好研究透。你按照上面这套流程部署一遍再模拟几次主备切换基本就能掌握核心用法。往后的日子里不管机器如何重启、网络如何抖动你的服务都有一个可靠的 VIP 在背后撑腰。