
聊到 nginxkeepalived 高可用很多运维同行第一反应是“这不就是经典主备嘛”。但真到生产环境落地主备切换、健康检查、脑裂规避很多细节都容易踩坑。这篇文章我把自己在 Linux 环境基于 nginx keepalived 搭建高可用的完整过程写下来包括主备模式和双主模式两套方案以及配置里的各种关键参数、切换验证和排错经验。适合刚接触这块的 Linux 运维新人也适合已经搭过但被 VIP 漂移、脚本误判折磨过的同学参考。整套方案解决的核心问题很简单nginx 前面的流量入口不能挂。无论是 Web 站点、反向代理还是统一入口一旦 nginx 进程死了或者整台机器宕了业务就断了。nginx keepalived 通过虚拟 IP 漂移来保证入口不中断挂了一台另一台自动顶上。理解这套机制比背配置更重要所以我先花一点篇幅把原理讲透再上实际配置最后是问题排查和我的真实使用体会。1. 项目概述与方案选型1.1 主备模式和双主模式的核心区别主备模式是最常见的玩法。两台机器配置成一个 VRRP 组平时一台作为 MASTER 持有虚拟 IPVIP所有流量都打到它身上另一台作为 BACKUP 处于待命状态接收 MASTER 的心跳报文但不抢 VIP。一旦 MASTER 故障BACKUP 收不到心跳会在极短时间内接管 VIP对外表现为 IP 不变但实际流量已经切到了另一台机器。双主模式则是把两台机器的资源都用起来。做法是配置两个 VRRP 实例每个实例各有一个 VIP每台机器在一个实例里是 MASTER在另一个实例里是 BACKUP。简单说VIP1 和 VIP2 平时分别落在两台机器上流量被分散到两台机器处理。当其中一台故障这台机器上的 VIP 会漂移到另一台另一台临时扛起两份流量。主备模式适合业务量不大、只想保证高可用的场景双主模式适合两台机器都要承担业务、不想让任何一台闲着的情况。但双主不是白捡一份算力它要求单台机器在故障发生时能扛住另一台的流量否则切换过去会把服务器压垮反而比主备更危险。1.2 为什么选 nginx keepalived 而不是其他组合市场上做高可用的方案不少LVS keepalived、HAProxy、云厂商的 SLB、K8s 的 Service 都能解决入口高可用。但在传统 Linux 服务器场景nginx keepalived 仍然是最直接、最容易维护的一套。LVS keepalived性能确实强四层转发能力比 nginx 高但配置复杂而且 LVS 本身不解析协议无法做路径级别、域名级别的转发。如果后面跑的是大量动态请求你还需要额外再叠一层 nginx 做七层处理。HAProxy七层代理能力很强但对配置格式有学习成本而且它本身不提供高可用通常也要配 keepalived 或类似工具等于绕了一圈。云厂商 SLB在云环境里最省心但前提是你愿意接受绑定自建机房或混合云环境往往还是要靠 keepalived 这套。nginx keepalived 的组合本质是“业务前置工具 高可用协议”的搭档。nginx 负责负载均衡、反向代理、静态资源处理这是它最擅长的keepalived 只负责 VIP 漂移和健康检查职责单一。两者部署简单、排错容易社区资料也多是落地成本最低的方案。1.3 实验环境规划我这次用的两台虚拟机来演示操作系统是 CentOS 7.9软件版本分别为 nginx 1.20.2 和 keepalived 2.2.7。下面的 IP 规划直接套用到双主模式也是可以的。服务器IP主备模式角色双主模式角色VIPnode01192.168.1.10MASTERVI_1 主 / VI_2 备VIP1: 192.168.1.100node02192.168.1.11BACKUPVI_1 备 / VI_2 主VIP2: 192.168.1.101生产环境强烈建议用固定 IP不要依赖 DHCP否则 VIP 漂移后地址解析会乱套。主机名最好也规范一下比如 ha-node01、ha-node02后面的配置里 router_id 可以直接用主机名来做标识排错时看日志能一眼分清是哪个节点。2. 基础环境准备与软件安装2.1 系统初始化与防火墙放行两台机器先做基础初始化。我习惯第一步就把防火墙和 SELinux 的坑避开不然后面会出现“keepalived 明明起来了VIP 却一直不漂移”的奇怪问题。# 两台机器都执行 setenforce 0 sed -i s/^SELINUXenforcing/SELINUXdisabled/ /etc/selinux/config systemctl stop firewalld systemctl disable firewalld如果你不想直接关防火墙就一定要放行 VRRP 协议。keepalived 默认走的是 VRRP 组播目标地址是 224.0.0.18IP 协议号是 112不能在防火墙里简单放一个 UDP 端口就完事。CentOS 7 上可以这样放行firewall-cmd --permanent --add-rich-rulerule protocol value112 accept firewall-cmd --reload如果配置的是单播模式两个节点之间还需要放行单播 VRRP 包规则同样是基于协议 112。我建议生产环境优先用单播后面配置部分会说明为什么。主机名和时间同步也别忽略。keepalived 的日志会记录节点标识主机名清晰能减少排错负担时间不同步会导致日志分析困难且 VRRP 报文本身对时间敏感度不高但业务日志对照会乱。时间同步直接用 chrony 或 ntpdate 都行。2.2 安装 nginxnginx 的安装方式无非两种EPEL 源直接 yum 装或者源码编译。实验环境我用 EPEL 源几条命令就能装完。yum install -y epel-release yum install -y nginx systemctl enable nginx systemctl start nginx装完可以先访问一下本机 IP看到 nginx 默认欢迎页就说明基础环境没问题。如果编译安装注意 configure 的时候加上--with-http_stub_status_module和--with-http_ssl_module这两个常用模块后面做健康检查页面和 HTTPS 转发都用得上。编译参数里具体要带哪些看你实际业务需求但这两块建议默认加进去。2.3 安装 keepalivedkeepalived 在 EPEL 源里也有直接装yum install -y keepalived keepalived --version配置文件默认在/etc/keepalived/keepalived.conf日志默认输出到/var/log/messages保持默认即可。我要强调一点keepalived 的版本不要选太老的。CentOS 7 自带的 keepalived 可能比较旧如果后面你想用单播配置旧版本对unicast_peer的支持不够好建议装完检查版本太老就通过源码或第三方源升级一下。我实验用的是 2.2.7配置语法和新特性都比较稳定。3. 主备模式实现VIP 自动漂移3.1 VRRP 协议与 VIP 漂移原理拿主备模式为例node01 和 node02 组成了一个虚拟路由器对外只暴露一个 VIP。keepalived 通过 VRRP 协议让两台机器每隔一个固定时间间隔互发心跳报文这个间隔就是配置里的advert_int默认 1 秒。MASTER 节点正常时会周期性发出 VRRP 通告BACKUP 节点收到后知道主节点还活着就不去争抢 VIP。一旦 MASTER 故障或者网络隔离BACKUP 在连续若干个通告周期内收不到报文就会认为 MASTER 已经挂了开始按照自己的优先级参与竞选最终接管 VIP。这就是平时说的“VIP 漂移”。可以把 VRRP 理解成一个“班长选举”机制班长定期喊一嗓子“我还在”副班长听到就老老实实待着哪天听不到班长声音了副班长就开始行使班长权力把值班电话VIP接管过来。这个机制非常成熟对上层业务来说访问的 IP 始终没变变化的只是背后真实的处理机器。3.2 keepalived 核心配置逐行拆解先看 node01 的完整配置。这里我拆开写后面再解释每个参数的含义! Configuration File for keepalived global_defs { router_id HA_NODE01 enable_script_security } vrrp_script check_nginx { script /etc/keepalived/check_nginx.sh interval 3 weight -20 fall 3 rise 2 } vrrp_instance VI_1 { state MASTER interface ens33 virtual_router_id 51 priority 100 advert_int 1 unicast_src_ip 192.168.1.10 unicast_peer { 192.168.1.11 } authentication { auth_type PASS auth_pass 123456 } virtual_ipaddress { 192.168.1.100/24 dev ens33 label ens33:1 } track_script { check_nginx } }node02 的配置大部分相同区别就是router_id、state、priority、unicast_src_ip和unicast_peer对调一下state写成BACKUPpriority写成 90。其余参数保持一致。重点说几个容易出问题的参数。router_id当前节点的标识没有严格的格式要求但建议两台机器用不同的名字日志排查时更容易定位。state初始状态。很多新手以为这里写了 MASTER 就一定持有 VIP其实不对。最终谁持有 VIP 是由优先级和竞选结果决定的。哪怕两个节点都写 MASTER只要优先级低的那台先启动它可能先成为 MASTER但高优先级节点启动后会自动抢占。priority优先级范围 0-255数值越大越容易成为 MASTER。主备模式下主节点优先级必须高于备节点且这个差值要结合后面脚本的 weight 一起考虑。virtual_router_idVRRP 组 ID范围 0-255。同一个局域网内如果有多套 keepalived 组这个 ID 不能重复否则会相互冲突。advert_int心跳报文发送间隔单位秒。默认 1 秒一般不用改动。设置太短会增加系统负担设置太长会导致故障切换变慢。authentication认证方式和密码。两台机器必须完全一致否则认证不通过keepalived 会以为对方异常。virtual_ipaddressVIP 配置。192.168.1.100/24表示 VIP 是 1.100掩码 24 位label ens33:1表示在 ens33 网卡上添加一个别名接口。生产环境可以直接用 CIDR 写法比旧式的192.168.1.100 netmask 255.255.255.0更清晰。我在配置里用了unicast_src_ip和unicast_peer这是把 VRRP 报文从默认的组播模式改成了单播模式。生产环境里同网段如果有多个独立 keepalived 组组播报文容易互相干扰如果网络设备配置了组播过滤也会导致心跳异常。单播模式只和指定的节点通信更可控。不过要注意并不是所有旧版本 keepalived 都支持这两个配置项用之前确认版本。3.3 健康检查脚本nginx 挂了必须让它“让位”很多人的 keepalived 配置里没有track_script这样即使 nginx 进程已经崩溃keepalived 依然认为节点健康VIP 不会漂移。真正的生产环境必须做健康检查而且是针对 nginx 的业务可用性做检查不只是ps看进程。我常用的脚本如下#!/bin/bash PATH/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin # 检查 nginx 进程是否存在 if pgrep -x nginx /dev/null 21; then exit 0 fi # 进程不存在先尝试拉起 systemctl start nginx sleep 2 # 拉起失败返回非 0让 keepalived 降低优先级 if pgrep -x nginx /dev/null 21; then exit 0 else exit 1 fi这个脚本的关键在于它先尝试把 nginx 拉起来只有拉起失败才让 keepalived 降权。为什么这么做因为 nginx 进程突然死掉很多情况下只是临时故障比如被 OOM Killer 干掉能起回来的话就没必要切换 VIP切换毕竟会造成秒级业务抖动。如果你对业务可用性要求更高可以再用 curl 检查本地端口响应#!/bin/bash if curl -I -s --connect-timeout 2 --max-time 3 http://127.0.0.1/health_check /dev/null 21; then exit 0 fi systemctl restart nginx sleep 3 if curl -I -s --connect-timeout 2 --max-time 3 http://127.0.0.1/health_check /dev/null 21; then exit 0 else exit 1 fi这里面有个容易被忽略的坑keepalived 执行脚本时的环境变量和交互式 shell 不一样systemctl可能找不到路径。所以脚本第一行我先把 PATH 设置成常见路径这是我在生产环境踩过坑后养成的习惯。脚本写好还要加执行权限chmod x /etc/keepalived/check_nginx.shvrrp_script 里我配置了三个关键参数interval 3表示每 3 秒执行一次脚本fall 3表示连续 3 次失败才算节点故障rise 2表示连续 2 次成功才算恢复。这个组合能有效防止偶发网络抖动导致的误切换。3.4 weight 值计算与主备抢占关系我在脚本里设置weight -20这个值不是随便写的它和优先级差有直接关系。keepalived 的规则是脚本执行失败时会在节点当前优先级的基础上加上这个负的 weight。node01 的基数是 100脚本失败后优先级变成 100 (-20) 80。node02 的基数是 90它收到 node01 状态异常后由于自己的优先级 90 大于 80于是接管 VIP。所以 weight 的绝对值必须大于主备优先级差值。如果只差 5比如 node01 是 100node02 是 95weight 设置 -3那 node01 故障后优先级变成 97仍然比 node02 的 95 高VIP 就不会切走这在高可用场景里是要命的。我一般建议 weight 的绝对值比优先级差至少大 10留出余量。另外注意weight 如果是 0脚本失败时会直接把节点状态切到 FAULT效果是 VIP 立即漂移但没有降权这么平滑。我更喜欢用负值降权因为这样给网络抖动留了缓冲。3.5 启动、验证和故障切换测试配置都写好后先做语法检查再启动 keepalivedkeepalived -t -f /etc/keepalived/keepalived.conf systemctl start keepalived systemctl enable keepalived启动后看 VIP 状态ip addr show | grep 192.168.1.100正常情况下 VIP 会出现在 node01 的ens33:1接口上。然后手动模拟故障# 方法一直接停掉 node01 的 keepalived systemctl stop keepalived # 方法二模拟 nginx 进程崩溃 pkill -9 nginx观察 node02 上的日志和 VIPtail -f /var/log/messages ip addr show | grep 192.168.1.100node02 日志里会出现 “STATE MASTER” 的记录说明 VIP 漂移成功。如果我用的是方法二由于脚本会先尝试拉起 nginx所以理论上 node01 的 nginx 会被拉起来VIP 可能不会切走。这正是健康检查脚本的容错机制。要验证真正的故障切换应该把 nginx 和 keepalived 同时停掉或者直接把 node01 关机。3.6 抢占模式与 nopreempt 的选择主备模式默认是抢占模式主节点恢复正常后因为 priority 更高会主动把 VIP 抢回来。这个行为在大多数场景里没问题但有个隐患主节点恢复时会再次触发一次 VIP 漂移业务会经历一次短暂中断。如果主节点出现反复的抖动VIP 就会在主备之间来回飘这就是脑裂之外的另一种不稳定。要避免来回抢可以在主节点的 vrrp_instance 里加一行nopreempt同时把两台机器的 state 都设成 BACKUP只靠 priority 来区分主次。这样高优先级节点恢复后不会主动抢回 VIP直到低优先级节点再次故障或停止服务VIP 才可能漂回去。我没有在配置里默认加nopreempt因为牺牲了自动回切能力。如果业务能接受切换后的短暂流量不均建议还是保留默认抢占模式如果追求稳定尽量让 VIP 少漂移那么非抢占模式更合适。4. 双主模式实现一台机器都不歇4.1 双主架构与 VRRP 实例拆解双主模式并不是什么黑科技它就是在同一台机器上跑了两个 vrrp_instance。每个实例对应一个 VIP两个实例的角色正好相反。实例 VI_1VIP1 192.168.1.100node01 是 MASTERnode02 是 BACKUP。实例 VI_2VIP2 192.168.1.101node02 是 MASTERnode01 是 BACKUP。平时 VIP1 走 node01VIP2 走 node02两台机器的 nginx 都在处理请求。node01 挂了之后VI_1 的 VIP1 漂移到 node02同时 node01 在 VI_2 里的 BACKUP 身份也无法维持所以 node02 会同时持有 VIP1 和 VIP2。整台机器只剩 node02 在扛这个场景就要求 node02 的性能余量能覆盖故障节点的业务量。双主模式最大的价值是资源利用率高。主备模式下备机常年空闲对很多线上业务来说有点浪费。双主模式下两台机器同时扛流量成本没有增加但要命的场景是如果 node02 本身就跑了 70% 的负载node01 一挂所有流量全部压到 node02直接被打爆。所以评估双主时一定要先算好容量留足故障余量。4.2 双主模式的完整配置node01 的/etc/keepalived/keepalived.conf! Configuration File for keepalived global_defs { router_id HA_NODE01 enable_script_security } vrrp_script check_nginx { script /etc/keepalived/check_nginx.sh interval 3 weight -20 fall 3 rise 2 } vrrp_instance VI_1 { state MASTER interface ens33 virtual_router_id 51 priority 100 advert_int 1 unicast_src_ip 192.168.1.10 unicast_peer { 192.168.1.11 } authentication { auth_type PASS auth_pass 123456 } virtual_ipaddress { 192.168.1.100/24 dev ens33 label ens33:1 } track_script { check_nginx } } vrrp_instance VI_2 { state BACKUP interface ens33 virtual_router_id 52 priority 90 advert_int 1 unicast_src_ip 192.168.1.10 unicast_peer { 192.168.1.11 } authentication { auth_type PASS auth_pass 123456 } virtual_ipaddress { 192.168.1.101/24 dev ens33 label ens33:2 } track_script { check_nginx } }node02 的配置只需要把两个实例的状态和优先级互换VI_1 改成 BACKUP、priority 90VI_2 改成 MASTER、priority 100。同时router_id、unicast_src_ip、unicast_peer要对应修改。这里要注意virtual_router_id必须区分开。VI_1 用 51VI_2 用 52同一台机器上两个实例不能共用一个 router_id否则 keepalived 内部也会冲突。认证密码也要保持一致两组实例的 auth 配置都可以相同但不能和其他 keepalived 组撞。4.3 双主模式的流量接入方式两个 VIP 都配置好了具体怎么把用户流量分到 VIP1 和 VIP2 上取决于你的前端入口方式。最简单的场景是一个域名做 DNS 轮询解析到两个 VIP或者两台机器上有多个站点站点 A 指到 VIP1站点 B 指到 VIP2互不干扰。如果前面还有硬件负载均衡设备或云上负载均衡直接把两个 VIP 配成后端源站即可。我这里补充一个常见误区不要以为双主模式下两台机器各绑定一个 VIPkeepalived 会自动做负载均衡。keepalived 只会保证 VIP 落在其中一台机器上流量怎么分配是你的事。真正把流量分散到两个 VIP 上靠的是 DNS、SLB 等上层调度这层逻辑千万别搞混。4.4 双主切换验证思路双主模式的验证和主备类似但要看两个 VIP 的移动情况。初始状态下# node01 上应看到 VIP1 ip addr show | grep 192.168.1.100 # node02 上应看到 VIP2 ip addr show | grep 192.168.1.101模拟 node01 故障systemctl stop keepalived此时 node02 上应该能看到 VIP1 和 VIP2 两个地址。恢复 node01 后根据配置的不同可能会自动抢回 VIP1。如果你不想让 VIP 来回飘也可以给两个实例都加上nopreempt但要记住双主模式下非抢占的细节配置比主备更麻烦需要把所有实例都设置为 BACKUP 初始状态再配合优先级选举。如果按照我上面的配置node01 恢复且脚本连续 2 次检查通过后VI_1 实例的优先级回到 100会从 node02 手里抢回 VIP1VI_2 实例由于是 BACKUP 且优先级 90 低于 node02 的 100VIP2 会继续留在 node02。这种“各自回位”的表现是符合直觉的。5. 健康检查脚本的进阶与业务联动5.1 脚本既要“准”也要“稳”健康检查脚本是整个高可用方案的“眼睛”眼睛要是瞎了整个切换逻辑就白搭。脚本要回答三个问题nginx 进程在不在、端口通不通、业务响应是否正常。进程检查用pgrep -x nginx端口检查可以用ss -ltn | grep :80 业务响应检查用 curl。生产环境我一般是三级一起做进程没了先拉起拉起后端口通了再看 HTTP 状态码最后才判断节点是否健康。这个链路虽然长一点但避免了“进程在但业务卡死”的漏判。脚本本身也要注意性能。interval 设置为 3 秒那么脚本最长执行时间不能超过 3 秒否则会重叠执行。curl 里必须加--connect-timeout 2 --max-time 3这样的超时参数否则网络黑洞时脚本会卡住后续的 fall 计数也会失真。5.2 fall 和 rise 参数的调优经验fall和rise是 keepalived 2.0 之后引入的参数用来控制阈值判断。fall 3连续 3 次脚本失败节点才被判定为 Down。rise 2连续 2 次脚本成功节点才被判定为恢复。我在主备演示配置里 interval 是 3 秒fall 是 3意味着 9 秒左右才会触发一次切换。这个延迟对大部分 Web 业务是可接受的。如果你的业务对中断非常敏感可以把 interval 调到 2fall 调到 2这样约 4 秒内完成切换。但不要盲目追求快interval 太小会让 keepalived 频繁执行脚本白白浪费 CPU而且网络抖动时更容易误判。5.3 脑裂的预防手段脑裂是指两台机器同时认为自己才是 MASTER同时持有同一个 VIP。脑裂的后果比普通故障更严重因为两台机器同时对外提供服务业务流量会被网络设备送到不同后端状态不一致严重时甚至数据错乱。脑裂最常见的诱因是心跳链路故障。主备之间心跳断了BACKUP 以为 MASTER 挂了于是夺权但 MASTER 其实还活着两个节点就同时持有 VIP。使用单播模式能减少一部分组播环境下的干扰但不能完全避免网络分区。生产级别的防御方式是加“仲裁机制”在健康检查脚本里除了检查 nginx 本身还要去 ping 网关或一个第三方仲裁节点。如果 ping 不通说明本机网络可能已经异常即使 keepalived 还活着也应该主动降级防止争抢 VIP。示例脚本片段如下#!/bin/bash # 先检查 nginx 进程 if ! pgrep -x nginx /dev/null 21; then systemctl start nginx sleep 2 fi # 再检查仲裁网关 if ! ping -c 2 -W 2 192.168.1.1 /dev/null 21; then exit 1 fi # 最后检查本地端口 if curl -I -s --connect-timeout 2 --max-time 3 http://127.0.0.1/health_check /dev/null 21; then exit 0 fi exit 1注意ping 仲裁网关这个动作要小心使用。如果两边都 ping 不通网关两边都会降级VIP 就没人接了业务会中断但不会脑裂。对比一下脑裂的危害远大于短暂断网所以“宁可不服务也不能双活”。这个取舍在配置高可用时一定要明确。6. 常见问题与排查技巧实录6.1 问题速查表下面这张表是我在实际维护中经常遇到的场景整理成速查表方便你对照排查。现象可能原因排查命令 / 处理方式两台机器都没有 VIPkeepalived 没启动、配置语法错误systemctl status keepalived、keepalived -t -f /etc/keepalived/keepalived.confVIP 一直不漂移state/priority 设置不满足切换条件、脚本权重不够检查优先级差值是否大于 weight 绝对值用journalctl -u keepalived看日志两台机器同时持有 VIP心跳不通、防火墙拦截、认证不一致ping对端 IP检查防火墙是否放行协议 112确认auth_pass一致脚本执行了但 keepalived 不降权脚本权限不够、脚本超时、track_script 没配置chmod x、手动执行脚本看返回码、确认 vrrp_instance 里引用了脚本nginx 已经挂了但业务还通nginx 没有真正挂或者检查的是进程而非业务用curl访问本地端口查看nginx -t配置是否正确日志报 unknown keywordkeepalived 版本太老不支持单播等新参数升级 keepalived 到 2.0重新keepalived -t校验6.2 核心日志在哪里看keepalived 默认把日志写到 syslogCentOS 7 上通常就是/var/log/messages。排查切换问题时不要只盯系统日志还要结合journalctl看服务状态。journalctl -u keepalived -f tail -f /var/log/messages日志里重点看几类信息VRRP_Script开头的表示健康检查脚本状态VRRP_Instance开头的表示实例状态变化STATE MASTER表示该节点成为了主节点。看到Entering BACKUP STATE或类似的报文说明节点主动让出了 Master 角色。6.3 我踩过的三个坑第一个坑是脚本没有执行权限。第一次搭的时候配置写得很完美keepalived 也重启了但脚本永远不会生效。后来才发现check_nginx.sh没有加执行权限keepalived 执行脚本时直接 Permission denied。所以写完脚本一定要第一时间chmod x并且手动执行一下确认返回码为 0。第二个坑是 systemctl 启动 nginx 卡住。在健康检查脚本里如果 nginx 配置本身有语法问题systemctl start nginx会一直等待甚至卡死。后来我在脚本里加了超时和日志记录把 nginx -t 也放到脚本里检查避免因为配置错误导致脚本卡住。第三个坑是双主模式下选中了同一个 virtual_router_id。当时在 node02 上复制配置时忘了改结果两个节点在同一个 router_id 上互相竞争VIP 在两个机器之间来回跳。把 VI_2 的 virtual_router_id 改成 52 之后问题立刻消失。这个坑很隐蔽如果你发现 VIP 不停抖动优先检查两台机器上每个实例的virtual_router_id是否对应一致且不同。6.4 日常维护时的高效验证清单我每次改完 keepalived 或 nginx 配置不是直接 restart 了事会按顺序做几件事先nginx -t检查 nginx 语法再keepalived -t -f /etc/keepalived/keepalived.conf检查 keepalived 语法。手动执行一遍健康检查脚本确认返回 0 或 1 符合预期。重启 keepalived 后用ip addr show确认 VIP 在当前节点正常绑定。最后才做一次真实的切换演练比如停掉 keepalived观察另一个节点是否在预期时间内接管 VIP。这份清单虽然简单但在生产环境里能省下很多不必要的故障时间。高可用方案不是配完就完事要定期演练确保切换链路随时可用。7. 实际项目落地中的心得与扩展方向说点比较实在的体会。nginx keepalived 这套方案在中小规模业务里非常实用我经历过的几个项目都是用它扛住了入口流量。它不像 K8s 那套东西学习成本高也不需要额外引入依赖两台普通的 Linux 服务器就能搭得很稳。但前提是你真正理解 VIP 漂移背后的机制而不是把配置抄完就以为万事大吉。我个人在生产环境里坚持几个原则keepalived 的心跳尽量用单播健康检查脚本里一定要加超时和路径fall和rise不能省每次配置变更都做语法检查和切换演练。这些小习惯看起来不起眼但在凌晨三点被报警叫醒的时候能让你少踩一半的坑。这套方案的扩展方向也很多。如果后面业务量大了可以在 nginx 层加 upstream 轮询或者把 nginx 改成 L4 L7 的两级架构再配合多组 keepalived 做流量入口的横向扩展。如果系统里跑的是数据库或消息队列也可以用同样的思路做服务端高可用只是健康检查脚本要针对具体进程定制。最后分享一个小技巧配置变更之前先备份当前生效的配置然后用keepalived -t做语法检查确认没问题再重新加载。重启 keepalived 之前最好再手动跑一次健康检查脚本避免脚本本身有问题导致 VIP 刚起来就被切走。这么一套流程走下来nginx keepalived 的高可用基本不会再给你添麻烦。