Nginx+Keepalived高可用架构实战:从原理到配置全解析

📅 发布时间:2026/10/11 6:15:25
Nginx+Keepalived高可用架构实战:从原理到配置全解析
深夜两点的告警电话估计不少运维兄弟都经历过。我那次是公司线上的Nginx入口机挂了整个前端入口全部瘫痪所有请求打不进去。折腾到天亮才恢复从那以后就下定决心必须把Nginx的高可用安排上。后来我用 Keepalived Nginx 这套组合方案在多个项目里落地实测下来非常稳今天把完整的搭建过程、原理和踩过的坑都整理出来希望能帮你少走弯路。这篇文章适合谁看正在用Nginx做入口负载均衡、但又担心这台机器挂掉导致全站不可用的运维或后端开发以及想给现有Web架构加一层高可用保障、但不想引入太重方案的同学。读完你会明白Keepalived到底是怎么抢IP的、健康检查脚本该怎么写才算靠谱、主备节点配置差在哪几个关键字段以及我踩过的那些日志报错和脑裂问题该怎么定位。1. 单点故障的惨痛教训为什么最终选了Keepalived Nginx1.1 一个让人后背发凉的深夜告警先说那次事故。公司线上架构其实不算简单后端有五六台应用服务器数据库做了主从但入口层只放了一台Nginx。当时觉得Nginx性能好、稳定性高一台顶得住就没多想。结果那台服务器半夜硬件报警直接重启Nginx没起来前端页面全部打不开。客户端请求进来没有入口接待后面应用再健壮也白搭。这就是典型的单点故障SPOF。Nginx本身是反向代理和负载均衡的好手能帮你把流量分发到多台后端但它自己也是运行在一台机器上的进程。机器宕了、系统崩了、机房交换机出问题Nginx就跟着没了。更尴尬的是像LVS这类四层负载方案虽然也很强但配置和架构复杂度高对于很多业务场景来说有点杀鸡用牛刀。我们当时需要的是一个轻量、能快速落地、不用改造现有架构的方案。后来我调研和实测下来最终选了 Keepalived Nginx 这个组合。Keepalived的核心能力是提供虚拟IPVIP同一组机器对外只暴露一个IP谁存活谁就持有这个IP。Nginx继续干它最擅长的反向代理和负载均衡Keepalived负责看住Nginx的命。这套方案最打动我的一点是对业务方完全透明客户端不需要任何改动只需要访问那个虚拟IP。1.2 高可用方案横评一堆方案里为什么是它我当时认真对比过几种常见的高可用实现方式列了个表格这样大家好理解取舍逻辑。方案核心思想优点缺点DNS轮询同一个域名解析出多个IP客户端随机选一个最简单无需额外软件故障切换依赖客户端缓存和TTL生效慢无法保证立即切换硬件负载均衡F5等专用设备做入口性能强、功能全价格贵普通项目用不起LVS Keepalived四层转发Keepalived做VIP漂移性能极强适合大规模流量配置复杂转发规则要仔细设计HAProxy Keepalived七层代理Keepalived做VIP漂移丰富的七层路由能力需要额外引入HAProxy对纯Nginx团队有学习成本Nginx KeepalivedNginx做七层代理Keepalived做VIP漂移复用现有Nginx架构上手快成本低Nginx四层能力受限极端高并发场景不如LVS说白了我们团队本来就是Nginx重度用户已经有Nginx配置和经验积累。在此基础上叠加Keepalived只是增加一个进程不用改任何业务逻辑。这不是说其他方案不好而是团队技术栈 改造范围 成本三个维度综合下来Nginx Keepalived是性价比最高的。从分工角度看这两者各管一段Nginx管流量怎么分发Keepalived管如果Nginx挂了怎么让别人顶上。这两件事必须掰开理解很多人配置出问题就是因为把这两个职责搞混了。后面我讲的配置和脚本其实都是在围绕这个分工展开。2. 虚拟IP漂移的原理Keepalived是怎么把IP抢过来的2.1 VRRP协议一群路由器选老大的机制Keepalived的实现基础是一个叫VRRP的协议全称是Virtual Router Redundancy Protocol虚拟路由冗余协议。这个协议最初是给路由器做冗余用的思路特别朴素把一组路由器划分成一个虚拟路由组对外统一使用一个虚拟IP但同一时刻只有一台路由器在真正干活这个干活的角色叫MASTER其他机器叫BACKUP。你可以把它想象成小区门口的两个保安。平时只有一个人当值住户认门牌号VIP进出不用在意今天具体是哪个保安在。如果当值保安突然生病了另一个立刻顶上门牌号不变住户一点感觉都没有。VRRP就是靠这套选老大的机制保证的每台参与选举的设备都会定期发送通告报文MASTER活着的时候BACKUP不敢造次MASTER超过一定时间不发声BACKUP就自动升级成MASTER。Keepalived就是VRRP协议在Linux上的一个优秀实现。它不关心你的Nginx配置了什么规则只关心我这个节点该不该持有VIP。所以理解Keepalived核心就两件事一是VRRP怎么选主二是VIP怎么转移。2.2 MASTER与BACKUP优先级决定身份Keepalived的配置文件里有几个关键字段直接把主备关系写死了state、priority、virtual_router_id。state是初始状态一个是MASTER一个是BACKUP但这只是启动时的一个身份标签真正决定谁能当老大的是priority优先级。优先级高的节点在竞选时会胜出胜出后持有VIP然后以MASTER身份持续发送VRRP通告报文。正常情况下MASTER节点每秒钟advert_int参数默认1秒发送一次组播通告告诉同组的其他节点我活着你们都老实待着。BACKUP节点收到通告后会重置自己的定时器继续保持候补状态。一旦MASTER挂了BACKUP在通告超时时间一般是advert_int的3倍也就是3秒左右内没收到任何通告立刻竞选升级为MASTER绑定VIP并对外宣告。有个细节必须注意VRRP通告报文默认是组播形式地址是224.0.0.18协议号112。如果你在防火墙里没有放行这个协议两个节点根本通信不了两边都会认为自己才是MASTER这就引出了后面要讲的脑裂问题。另外主备切换之后新的MASTER会发送免费ARPGratuitous ARP通知整个局域网这个VIP的MAC地址已经变了你们赶紧刷新缓存。这也是为什么VIP漂移后客户端还能继续访问的关键机制。2.3 健康检查Keepalived如何知道Nginx还活着VRRP本身只能保证Keepalived进程活着但Keepalived活着不代表Nginx活着。这就需要引入健康检查机制配置里的vrrp_script和track_script干的就是这件事。Keepalived会周期性执行一个脚本比如检查Nginx进程是否存在然后根据脚本的返回结果决定要不要调整本节点的优先级。这里有个非常巧妙的参数叫weight比如脚本检查失败时给当前节点优先级扣50分。假设MASTER节点的priority是100Nginx挂了脚本返回失败优先级被扣成50BACKUP节点原本priority是90一看对方分数比自己低了就升级成MASTER。这样VIP就从故障节点转移到了健康节点上。理解了这个机制你就明白为什么有人只写健康检查脚本而不检查后端应用时会出事。因为你只检查Nginx进程万一Nginx进程活着但上游应用服务已经挂了Nginx依然返回502Keepalived不会感知到不会切换客户端照样打不开页面。想做到更细的故障检测可以在健康检查脚本里用curl去请求本机Nginx的回环接口甚至请求一个后端健康检查URL只有拿到预期状态码才认为服务可用。这样高可用的边界就从进程级延伸到了服务级。3. 环境准备与安装细节Nginx和Keepalived的工程化落地3.1 测试环境与版本选择开始动手之前先把环境说清楚。我这里用的是两台CentOS 7.9服务器生产建议同样使用稳定的Linux发行版。节点信息如下节点IP地址角色Node1192.168.1.10Nginx Keepalived MASTERNode2192.168.1.11Nginx Keepalived BACKUPVIP192.168.1.200对外提供服务的虚拟IPNginx版本建议使用官方稳定版我用的1.24.0Keepalived建议使用2.2.7以上版本。有一个容易忽略的点两台机器的Keepalived版本尽量保持一致因为早期版本和2.x版本在配置语法和协议行为上有差异混搭版本容易踩到奇怪的兼容问题。3.2 Nginx编译安装与常用模块Nginx建议编译安装这样可以把需要的模块一次性编进去后面再加就麻烦了。我用的是这套配置# 安装编译依赖 yum install -y gcc gcc-c make pcre-devel zlib-devel openssl-devel # 下载官方稳定版源码 wget http://nginx.org/download/nginx-1.24.0.tar.gz tar zxvf nginx-1.24.0.tar.gz cd nginx-1.24.0 # 编译安装 ./configure --prefix/usr/local/nginx \ --with-http_ssl_module \ --with-http_stub_status_module \ --with-http_gzip_static_module \ --with-stream \ --with-http_v2_module make -j4 make install这里有几个模块是我特别关注的。--with-http_ssl_module用来支持HTTPS证书--with-stream是四层TCP/UDP代理模块虽然高可用本身用不到但后面如果有需求可以直接在同台机器上做四层转发不用再折腾其他组件。--with-http_v2_module则是HTTP/2支持。编译完记得把nginx命令放到PATH里ln -s /usr/local/nginx/sbin/nginx /usr/sbin/nginx nginx -t # 验证配置 nginx # 启动两台机器都装好Nginx各自准备好一个测试页面最好能在页面上标出当前机器的主机名或IP后面测试切换效果时会非常直观。3.3 Keepalived安装yum还是编译Keepalived在CentOS的epel源里就有直接装很方便yum install -y epel-release yum install -y keepalived keepalived -v # 查看版本如果你需要更新的版本或者定制编译参数也可以去官网下载源码编译编译依赖主要是openssl-devel、libnl3-devel这些。但我个人实测下来对于大多数场景yum安装的版本完全够用没必要自己编译。重点是把配置写对而不是纠结版本号。3.4 防火墙和系统参数提前处理好装完软件先别急着配先把网络层面的前置条件做好。Keepalived默认走组播通告所以两台机器都要放行VRRP协议。用firewalld的话就是firewall-cmd --permanent --add-rich-rulerule protocol valuevrrp accept firewall-cmd --reload如果你用的iptables对应放行protocol 112即可。这一步漏掉的后果非常严重我先说结论两边互收不到通告都会认为自己是MASTER就出现双主——脑裂。这在第7节我会单独展开讲排查过程。另外如果你的网络环境比较复杂比如跨交换机、交换机禁组播、云厂商安全组不支持组播那么组播方式就会失灵。生产环境的推荐做法是用单播模式。在vrrp_instance配置块里显式指定单播源地址和对端地址就能绕过组播依赖vrrp_instance VI_1 { unicast_src_ip 192.168.1.10 unicast_peer { 192.168.1.11 } }这组配置在Master和Backup上正好是我和你互换。实测下来单播模式在网络管控严格的环境下要稳定得多。4. Nginx健康检查脚本写得糙一点,切换就会漏一次4.1 一个真正能用于生产的检查脚本Keepalived的健康检查脚本我在不同项目里迭代过好几版。最粗糙的版本只查进程#!/bin/bash pidof nginx || exit 1 exit 0这个脚本有个问题Nginx进程还在但工作进程卡死或者端口无法响应时它检查不出来。切换逻辑不会触发服务照样是坏的。所以我后来在线上用的是一套组合检查同时覆盖进程和HTTP层的连通性#!/bin/bash # /usr/local/nginx/check_nginx.sh # 1. 先检查 nginx master 进程是否存在 if ! pgrep -x nginx /dev/null 21; then exit 1 fi # 2. 再通过本机回环地址发起 HTTP 请求确认服务真的能响应 # 注意这里判断的是能正常返回响应状态码范围可根据业务调整 code$(curl -s -o /dev/null -w %{http_code} --connect-timeout 3 --max-time 5 http://127.0.0.1/ 2/dev/null) if [ $code 000 ] || [ -z $code ]; then exit 1 fi # 3. 两项都通过才算健康 exit 0这个脚本对业务页面的状态码要求放得很宽只要不是连接失败就算健康。如果想做更严格的检查可以把返回码列表明确写出来比如只要200/301/302其他都视为异常。curl里的--connect-timeout和--max-time是防脚本卡死的兜底配置Keepalived调用脚本是有间隔的脚本本身不能阻塞太久否则检查会失去意义。写完之后记得赋执行权限确保root能运行chmod 755 /usr/local/nginx/check_nginx.sh /usr/local/nginx/check_nginx.sh echo healthy || echo unhealthy4.2 脚本参数调优:interval、weight、fall与rise脚本本身写好后还要在Keepalived配置里把它管起来。vrrp_script块里有几个参数理解了它们就好办了vrrp_script chk_nginx { script /usr/local/nginx/check_nginx.sh interval 2 weight -50 fall 2 rise 1 }interval是执行间隔单位秒我建议2到3秒。太短会增加系统开销切换过于敏感太长故障感知时间就变长用户体验差。weight是脚本失败时对优先级的调整值默认是-2但我通常设成-50确保主节点一旦失守优先级能被明显拉低让备节点有把握地接管。fall表示连续失败几次才认定故障默认是1我习惯设2避免偶尔一次网络抖动就触发切换rise表示连续成功几次才恢复健康设1即可尽快恢复标记。这里有个反直觉的设计要提醒你脚本失败扣减MASTER的优先级后如果MASTER的分数仍然高于BACKUP则不会切换。所以weight的绝对值最好大于MASTER与BACKUP的优先级差值。打个比方MASTER优先级100BACKUP优先级90差值10weight如果只设-5MASTER失败后变95还是高于90切换永远不触发。这是最坑的配置陷阱之一。4.3 证书和配置同步切换成功不等于服务正常还有一件事我吃过亏也得在这个环节就叮嘱主备两台Nginx的配置和证书文件必须保持一致。VIP漂移过去之后流量落到了BACKUP节点。如果这台机器的Nginx配置是旧的证书没拷贝过来用户访问时直接看掉证书错误、路由失效、页面404。热搜词里经常有人问nginx替换ssl证书不生效多半就是只改了当前节点而另一台完全没有同步。我的习惯是写一个简单的同步脚本在每次变更配置后手动执行或配合定时任务执行。比如用rsync把主节点的配置和证书推送到备节点rsync -avz /usr/local/nginx/conf/ 192.168.1.11:/usr/local/nginx/conf/ rsync -avz /etc/ssl/nginx/ 192.168.1.11:/etc/ssl/nginx/ ssh 192.168.1.11 nginx -t nginx -s reload生产环境强烈建议引入配置管理工具或者说自动同步机制不要让配置漂移变成高可用链路里的隐形杀手。5. Keepalived配置逐行拆解主备节点只差三个字段5.1 MASTER节点的完整配置文件这是我在生产环境用的配置模板先把MASTER的全貌摆出来再逐块讲解。注意把配置里的注释看仔细这些都是实战总结。! /etc/keepalived/keepalived.conf global_defs { router_id LVS_NODE1 } vrrp_script chk_nginx { script /usr/local/nginx/check_nginx.sh interval 2 weight -50 fall 2 rise 1 } vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 123456 } unicast_src_ip 192.168.1.10 unicast_peer { 192.168.1.11 } virtual_ipaddress { 192.168.1.200/24 dev eth0 label eth0:1 } track_script { chk_nginx } }一个个说关键字段。router_id只是本节点的标识相当于给Keepalived进程起个名字可以随便取但建议有辨识度。interface表示VRRP通告走哪块网卡必须和实际业务网卡名一致别想当然用eth0现在很多机器是ens33、ens160用ip addr看一眼再填。virtual_router_id是整个虚拟路由组的ID两台机器必须一致它决定了VRRP报文属于同一个组我建议用有意义的编号比如51避免和同网段其他VRRP组冲突。priority是优先级MASTER设100BACKUP设90。authentication这块是VRRP报文认证PASS方式就是个明文的密码两台必须完全一致否则互相认证失败。它防的是误加入的设备不防恶意攻击别把它当安全机制。virtual_ipaddress就是VIP地址后面可以接多个格式上写清楚子网掩码、网卡设备和label。label是给VIP绑定的虚拟网卡接口名写上eth0:1方便后面用ip addr show eth0:1精准查看VIP状态。track_script是关键中的关键它把上面定义的健康检查脚本chk_nginx和VRRP实例绑定起来。脚本失败时Keepalived会自动扣减本节点优先级这是从进程高可用到服务高可用的桥梁。5.2 BACKUP节点的差异化配置BACKUP的配置和MASTER几乎一样只有三个地方要改router_id换成LVS_NODE2state改成BACKUPpriority改成90unicast_src_ip换成自己的IPunicast_peer里写上MASTER的IP。其余字段尤其是virtual_router_id、advert_int、authentication、virtual_ipaddress必须一模一样。! /etc/keepalived/keepalived.conf global_defs { router_id LVS_NODE2 } vrrp_script chk_nginx { script /usr/local/nginx/check_nginx.sh interval 2 weight -50 fall 2 rise 1 } vrrp_instance VI_1 { state BACKUP interface eth0 virtual_router_id 51 priority 90 advert_int 1 authentication { auth_type PASS auth_pass 123456 } unicast_src_ip 192.168.1.11 unicast_peer { 192.168.1.10 } virtual_ipaddress { 192.168.1.200/24 dev eth0 label eth0:1 } track_script { chk_nginx } }很多新手会纠结一个问题priority到底哪个高、state该填什么。记住一个原则就稳了state只是启动时的初始身份priority才是真正的竞选依据。哪怕两台都写BACKUPpriority高的那台最终也会成为MASTER。所以在实际生产里我甚至建议两台都写成BACKUP加不同的priority这样重启时谁抢到VIP完全由优先级决定少一些我以为我是主的错觉。5.3 配置上线前的自检手段配置写完之后千万别直接重启服务先用Keepalived自带的自检命令扫一遍语法keepalived -t -f /etc/keepalived/keepalived.conf如果输出里出现Keepalived exited with permanent error config.说明配置文件有语法层面的大问题最常见的就是括号没闭合、字段拼写错误、或者vrrp_instance名字不一致。这个报错我在第7节会展开讲一次完整的排查过程。自检通过后在主备两台机器分别启动Keepalived然后立刻看VIP在哪台机器上systemctl start keepalived ip addr show | grep 192.168.1.200正常情况下VIP会出现在MASTER节点上。如果你发现两台机器都绑定了VIP先别急着继续往下走这个问题不解决后面所有测试都没意义。可以先检查是不是防火墙拦了VRRP或者配置文件里的virtual_router_id、认证密码不一致。6. 故障切换实测从我kill掉Nginx开始,到服务自动恢复6.1 正常态与首个故障场景:keepalived进程被kill配置上线并且VIP正常绑定后就该做故障注入测试了。这个测试一定要做不做你永远不知道配置是不是真的生效。先确认常态从客户端机器ping一下VIP或者在浏览器里访问VIP的测试页面页面应该显示MASTER节点的主机标识。然后在MASTER节点上手动停止Keepalivedsystemctl stop keepalived模拟的是Keepalived进程挂了的故障。观察BACKUP节点大约3秒后advert_int * 3它应该自动升级为MASTER并绑定VIP。此时回到客户端再次ping VIP和访问测试页面确认业务没有中断或者只有极短暂的抖动。从日志时间线能看得更清楚。BACKUP节点上tail /var/log/messages会看到类似这样的记录从进入BACKUP状态变成收到更优通告或进入MASTER状态然后绑定VIP、发送免费ARP。这一步观察的重点是切换到底花了几秒、客户端是否能感知。6.2 更贴近实战的故障:只kill Nginx,keepalived还活着真实线上更容易出现的情况是Keepalived进程活得好好的Nginx进程莫名其妙死了。如果健康检查脚本没配置到位这种故障恰好就是最隐蔽的VIP不漂移、客户端请求全部失败、你还在远程排查为什么Nginx挂了。用我们的配置来模拟在MASTER节点上执行nginx -s stop然后观察VIP状态。因为我们的track_script里的chk_nginx脚本每2秒检查一次连续失败2次后触发weight扣减MASTER优先级从100降到50低于BACKUP的90BACKUP自动接管VIP。实测切换时间大约在5到8秒之间这个时间窗口主要由interval和fall参数决定在我的配置里就是2秒乘以2次失败加上竞选和VIP绑定时间。这里有一个非常容易判断错误的点如果你只配置了脚本检查Nginx进程但没扣足够的分比如前面说的weight只设了-5那Nginx挂掉后主节点优先级变成95还是高过BACKUP的90VIP不会漂移。所以测试时不要只看有没有切换成功还要回头看日志和优先级的变化确认切换原因是自己预期的那条链路。6.3 失败后的恢复VIP会不会自动回到原主故障恢复也是高可用的关键场景。把MASTER节点上的Nginx重新启动再启动Keepalived会发生什么默认情况下MASTER进程起来后会立即参与VRRP竞选由于它的priority是100高于BACKUP当前的90所以它会把VIP抢回来。这就是抢占模式preempt也是Keepalived的默认行为。但自动抢回不一定是好事。如果MASTER是因为偶发故障重启它的服务刚起来还没完全热身此时抢回VIP可能引发一次短暂的服务波动。有些场景希望保持当前节点继续服务等下次维护时再切换回去那就需要在配置里加一行vrrp_instance VI_1 { nopreempt }注意nopreempt只在state BACKUP节点上配置才有效果MASTER节点配了也没用。我个人的习惯是如果应用启动很快用默认抢占模式就好逻辑简单行为可预期如果应用启动慢或者故障恢复后需要较长时间预热的给BACKUP节点加上nopreempt让VIP留在当前健康节点上。恢复测试的操作也一样简单。在MASTER节点启动Nginx、启动Keepalived然后观察VIP状态变化。默认抢占模式下VIP会在几秒内回到MASTER非抢占模式下VIP继续留在BACKUP上。这两种行为都符合预期关键是你要理解自己配置的是哪一种别到时候我以为会切回去却一直没动静。7. 踩坑实录permanent error、脑裂、双主我一条条帮你排7.1 keepalived exited with permanent error config 的根因定位这个报错在社区里出现频率相当高很多人在改完配置重启Keepalived时发现服务起不来日志里就这一句Keepalived exited with permanent error config.这句英文看着吓人翻译过来的意思是配置文件存在永久性错误进程拒绝启动。我遇到过的案例绝大多数是配置语法层面的问题。第一位是括号没配对。Keepalived配置文件层级分明global_defs一层、vrrp_script一层、vrrp_instance一层每个块都有开有合。多一个花括号、少一个花括号都会触发这个报错。第二位是字段拼写错误把interface拼成interfance、把priority写成prioraty这类低级错误自检时一眼就能抓到。第三位是配置项位置放错了比如把track_script写到了global_defs里或者把script路径写成一个不存在的文件。排查的正确姿势是先跑语法检查keepalived -t -f /etc/keepalived/keepalived.conf它会精确指出第几行附近有错误。然后再看journal日志journalctl -u keepalived -n 50两个工具配合基本能锁定99%的问题。这里多说一句这种permanent error级别的报错反而是好事因为它很直接不藏着掖着。怕的是配置能启动但行为不对比如VIP不生效、主从不切换那才需要花时间慢慢薅头发。7.2 脑裂现象两台机器同时持有VIP的灾难现场脑裂Split-Brain是高可用方案里最可怕的故障状态没有之一。现象很直观两台机器同时绑定了VIP客户端请求被负载均衡或者交换机导到两台机器上流量混乱、状态错乱、日志稀碎。更麻烦的是如果后端服务是状态型的两边同时写入就会产生数据不一致衍生出一堆后续问题。我排查过的脑裂案例里最常见的原因就是VRRP通告不通。防火墙没放行协议112、云安全组默认禁组播、交换机配置了组播过滤、两台机器分隔在不同二层网络这些都会导致BACKUP收不到MASTER的通告。收不到通告BACKUP就以为MASTER死了开始竞选——于是双主诞生。排查命令也很直白。先看两台的VIP状态ip addr show | grep 192.168.1.200然后抓VRRP报文看是不是真的在互发互收tcpdump -i eth0 vrrp -nMASTER节点上应该能看到持续输出的VRRP通告BACKUP节点上也应该能看到这些报文。如果BACKUP完全抓不到网络路径基本就是问题所在。解决思路有两条放行防火墙里的协议112或者干脆禁用组播走单播。我在生产环境里的推荐是配置单播因为云环境、容器环境、VLAN环境对组播的支持参差不齐单播的可控性要高出很多。7.3 主备Nginx配置不一致:切换成功却依旧打不开网站有一种高可用故障比Keepalived本身出问题更隐蔽VIP漂移成功了Keepalived日志一切正常但用户访问VIP就是打不开。我排查过一次这样的线上事故折腾了半天最后发现是备份节点Nginx配置里的SSL证书文件根本没放。原因很简单主节点挂了之后流量切到备节点备节点的Nginx配置是上周的老版本证书路径指向一个不存在的文件所以Nginx进程直接启动失败或者拒绝加载该站点配置。Keepalived在外面看着以为是好的脚本也检查Nginx进程了但Nginx进程失败可能导致检查脚本直接退出1这会循环触发切换或者更糟——VIP虽然在备节点上但备节点Nginx完全没法服务。这件事的教训就是高可用不是只把Keepalived配置好就完事还要确保每台机器的上层应用配置完全同步。证书文件、Nginx配置、站点根目录、依赖的目录结构全都得保持一致。所以我前文才反复强调配置同步机制和变更流程一定别偷懒。我自己现在任何变更都是先在测试机验证然后推到主节点再同步到备节点最后Nginx reload。7.4 那些让人崩溃的小细节脚本权限、SELinux、网卡名最后一类问题单个看都不大但组合起来特别折磨人。先提脚本权限。Keepalived健康检查脚本如果没有执行权限或没有root运行权限脚本执行一直失败Keepalived会一直认为节点不健康优先级被扣到负数甚至触发直接退出。我刚才给的脚本写好之后一定要chmod 755并手工执行验证。再提SELinux。CentOS上如果你是默认的Enforcing模式Keepalived调用自定义脚本可能被SELinux策略拦截。排查时看看/var/log/audit/audit.log里有没有相关拒绝记录。如果确定是被SELinux拦了要么调整策略要么临时setenforce 0测试但我还是建议能用策略解决就尽量别全局关SELinux。还有网卡名。不同系统、不同虚拟化平台网卡名可能叫eth0、ens33、ens160或者eno1。Keepalived配置里的interface字段一旦写错VRRP通告根本不会从正确网卡发出去。最坑的是配置不报错因为语法没错只是逻辑不对。所以上线前一定用ip addr确认网卡名别想当然。最后一个容易被忽略的是脚本的换行符。如果你在Windows上编辑过脚本再上传Linux脚本可能会带着CRLF换行符执行时直接报/bin/bash^M: bad interpreter健康检查永远失败。用sed -i s/\r$//清理一下就好。这类小问题每一条单看都简单但在实际排障中会消耗大量时间提前写下来能帮后来人省很多事。我在实际项目中把这套Keepalived Nginx的组合跑了很多年从最初的四台服务器小集群到后来几十个节点的入口层基本全靠它顶着。每次改配置我都坚持一个习惯改完必自检、自检完必做一次故障切换演练亲眼看到VIP漂移、服务恢复才算这次变更真正结束。稳定的高可用不是写在文档里的架构图而是你在凌晨的告警电话里能不能安心说一句让它切吧没问题。希望这篇文章能帮你在搭建高可用的路上少踩几个坑。