凌晨两点半,值班手机震了。“你们的服务是不是挂了?”我揉着眼睛登录跳板机看了一眼:后端某台机器其实已经宕机快两小时了,入口请求却一直正常,用户完全无感。那一瞬间我就知道,之前搭的那套高可用负载均衡起作用了。
这套东西在我的运维笔记里编号是2.24,标题就叫“高可用负载均衡”。简单说就是:让流量入口不依赖任何一台单机,即使某一层崩了,请求还能自动绕到健康节点上继续跑。这篇文章不聊云厂商一键购买的那种托管LB,而是从原理到底层配置,完整走一遍Keepalived + HAProxy搭建主备高可用负载均衡的全过程。内容主要面向刚接手后端服务运维、或者想搞明白“负载均衡到底怎么保证自己高可用”的读者,我会把选型逻辑、核心机制、配置文件和踩坑排错一起讲透。
1. 为什么说“负载均衡本身才是最危险的单点”
1.1 没有负载均衡时,故障是怎么扩散的
很多人第一次接触负载均衡,是从“多台后端机器需要统一入口”这个需求开始的。传统架构里,域名DNS直接解析到某一台应用服务器的IP,用户请求全部打到这台机器上。问题很明显:这台机器挂了,整个服务就废了。
更麻烦的是DNS缓存。哪怕你立刻把DNS解析改到另一台机器,由于各地运营商、浏览器、系统解析器都有缓存,TTL没到之前,大量用户依然会访问那个已经宕机的IP。我见过不少小团队因为这个原因,故障恢复时间干到一两个小时以上,不是服务起不来,而是“老地址”的用户进不来。
所以在后端前面加一层负载均衡是第一步:让后端多台机器藏在一个虚拟入口后面,由负载均衡器负责转发流量。后端任何一台挂了,它会被自动摘掉,请求分给其他健康节点。这一步解决的是“后端多机冗余”的问题。
1.2 负载均衡器自己挂了怎么办
问题来了——流量入口从“后端多台机器”收敛到了“一台负载均衡器”。以前是后端某一台挂,影响一部分;现在是负载均衡器挂,影响全部。这就是典型的风险集中:你为了解决单点,自己又造了一个新的、更危险的单点。
我见过最典型的场景:后端Web层做了两台Nginx,前面挂了一台HAProxy做转发,大家觉得高可用已经搞定了。结果某个深夜HAProxy所在机器内存故障重启,整站瘫痪。原因很简单——负载均衡器本身没有做任何冗余。
高可用负载均衡的核心,从来不是“我有多台后端”,而是“入口这一层也必须有多台机器冗余,并且它们之间要能自动切换”。多台负载均衡器共享一个虚拟IP(VIP),平时只有一台在干活,它出问题后另一台立刻顶上,整个切换过程对用户来说几乎无感知。这套机制,就是主备高可用。
1.3 “高可用”落到数字上是什么概念
聊高可用,不能只说“不挂”。业内通常用SLA来衡量:99.9%可用性,意味着一年最多宕机8.76小时;99.99%可用性,一年最多52.56分钟。负载均衡作为流量入口,它本身的可用性指标必须比后端更高,否则整个服务的SLA就卡死在入口这一层。
落到实际参数上,你的故障转移时间由几个环节决定:
- VRRP通告间隔:主备节点之间心跳报文的发送频率,默认1秒;
- 健康检查判定时间:负载均衡发现后端故障的速度,由探测间隔和失败次数共同决定;
- 脚本检测执行周期:检测HAProxy进程的脚本多久跑一次。
这几个值加起来,就是一次故障转移的“理论最短时间”。在我的经验里,尽量把整个切换控制在3~5秒以内,才能谈“高可用”。如果切换要花几十秒,那跟直接宕机其实也没太大区别——用户早就刷新页面失败开始骂人了。
2. 三种主流选型:Nginx、HAProxy、LVS怎么挑
2.1 先分清四层与七层负载均衡
选型之前,必须理解一个基础概念:四层和七层。
四层负载均衡工作在传输层,核心是IP + 端口转发。它不关心传输的内容是什么,拿到数据包就按规则转发,性能很高。
七层负载均衡工作在应用层,可以解析HTTP协议内容,能根据URL路径、域名、请求头、Cookie等做精细化路由。比如同一个入口,/api的请求转发到后端A,/static的请求转发到后端B,只有七层负载均衡能实现。
这里有个常见误区:有人觉得Nginx只能做七层,不能用做四层。其实Nginx有stream模块,完全可以做四层TCP/UDP转发,只是很多人没用到。HAProxy原生就同时支持四层和七层。LVS是个纯粹的流量转发内核模块,主要工作在四层。
2.2 三款软件负载均衡的核心差异
我把经常拿来对比的三款主流软件负载均衡器,按实际使用中的关键维度整理一下:
| 对比项 | Nginx | HAProxy | LVS |
|---|---|---|---|
| 工作层级 | 七层为主,stream模块支持四层 | 四层和七层都支持 | 纯四层 |
| 性能 | 足够高,单机轻松扛数万QPS | 极高,事件驱动模型,连接管理优秀 | 最高,基于内核转发 |
| 配置复杂度 | 熟悉,但内置变量/模块较多 | 简单直观,配置格式统一 | 相对复杂,要理解DR/NAT/TUN模式 |
| 健康检查 | HTTP健康检查强大 | TCP/HTTP都强大,参数精细 | 需要配合脚本或其他工具 |
| 会话保持 | ip_hash、sticky模块 | cookie、source等多样化 | 本身不擅长 |
| 动态摘流 | 需要reload或脚本改配置 | 支持命令行/接口动态调整服务器状态 | 要改ipvsadm规则 |
实际选型的结论是:追求极致性能、场景是海量四层转发,选LVS;团队对Nginx最熟、业务以HTTP为主,选Nginx;需要精细的连接管理、四层七层混合场景、丰富的健康检查策略,选HAProxy非常顺手。
2.3 高可用组合怎么搭
光有负载均衡器还不够,还得让多台负载均衡器完成自动主备切换。最常见的高可用组合有四种:
- Keepalived + Nginx:经典Web架构组合,Nginx扛七层转发,Keepalived负责VIP漂移;
- Keepalived + HAProxy:中间件代理、数据库负载均衡、混合流量场景很合适,HAProxy提供灵活的转发和健康检查;
- Keepalived + LVS:大流量四层入口的标配;
- 云厂商托管LB:云上环境优先考虑,但原理我仍然建议搞懂。
我这次选择的是Keepalived + HAProxy,主要原因是场景比较杂:既有HTTP服务,又有一些TCP协议的中间件需要做端口转发。HAProxy一套配置就能覆盖四层和七层,健康检查的探测逻辑非常细,而且自带的统计页面在排查问题时极其好用。
2.4 为什么不用DNS轮询或者K8s Service替代
有人会问:既然DNS解析可以做多IP轮询,为什么不直接用DNS做高可用?因为DNS缓存是最大的敌人。你把同一个域名解析成多个IP,客户端访问时确实会轮换,但一旦某个IP的机器故障,已经解析到那个IP的客户端还会继续尝试访问,直到缓存过期。切换速度完全不可控,达不到秒级。
至于Kubernetes里内置的Service负载均衡,确实解决了容器场景下的流量分发问题。但如果你维护的是传统虚拟机或物理机架构,或者业务还没容器化,Keepalived配合软件负载均衡依然是低成本、高可控、经过大量生产验证的成熟方案。
3. VIP漂移、健康检查与等开销调度:三个核心机制讲透
3.1 VIP与VRRP:两个节点共享一个“门牌号”
高可用负载均衡最底层的机制是虚拟IP + VRRP协议。
虚拟IP(VIP)是一个不固定绑定在某一台物理机器上的IP地址。两台负载均衡机器组成一个VRRP组,通过优先级选出一台作为Master,VIP由Master持有;Backup节点持续监听Master的心跳报文。
打个比方:小区只有一个门牌号,但门卫室有两间房。平时A房间值班,B房间待命,A房间每隔一秒往公共走廊喊一声“我还在”。一旦A房间没声音了,B房间立刻出来接替值班,把门牌号挂到自己房间门口。
这个过程就是VIP漂移。关键细节在于:VIP漂移不只是“IP地址换了一台机器”,新Master接管VIP后,还会发送免费ARP报文,通知交换机“这个IP对应的MAC地址变了”。否则交换机缓存里还记录着VIP指向旧Master的MAC,流量依然会送错地方。这个细节后面排障还会再提到。
VRRP还有几个参数值得理解:priority是选举权重,范围1~255,值越大越优先;advert_int是心跳报文间隔,默认1秒;preempt决定备节点在恢复后是否主动抢回Master身份。
3.2 健康检查:你以为的“活着”和真正的“活着”是两回事
高可用系统里,健康检查是连接负载均衡器和后端服务的关键桥梁。它解决的问题只有一个:怎么判断一台后端机器真的能处理新请求。
最低级的健康检查是TCP端口探测:只要端口能连上就算健康。但这个方法有盲区——进程还在,端口还开着,不代表服务真的正常。典型场景是应用假死:Nginx进程没退出,但工作进程全卡住了,端口能连上,请求却处理不了。
更可靠的做法是HTTP业务探测:负载均衡定期请求一个专门设计的内置接口,比如GET /healthz,接口内部会检查依赖的数据库连接池、缓存、核心线程池状态,全部正常才返回200。这样“端口活着”和“业务活着”就被区分开了。
健康检查的参数同样重要,主要看三个:interval(探测间隔)、fall(连续失败多少次判死)、rise(连续成功多少次复活)。参数设得太激进,后端一有抖动就被摘掉;设得太保守,故障发现太慢。我的建议是:interval设为3~5秒,fall设为2~3次,rise设为2次,这样单次抖动不会误杀节点,真实故障也能在10秒内被识别。
3.3 等开销调度策略:让后端机器干差不多的活
“等开销负载均衡”这个词近段时间讨论得比较多,它的核心思想容易被人误解。很多新人以为负载均衡就是把请求平均分给每台机器,一人一个,公平合理。实际上,“等开销”追求的不是请求数量相等,而是每台后端机器承担的开销和压力大致相当。
举个例子:两台后端机器,一台4核,一台8核。如果按请求数平均分,4核机器很快被打满,8核机器还有大量余量,整体资源利用率反而不均衡。这时候应该设置权重为1:2,让强机器多吃流量,才是真正的“等开销”。
HAProxy提供了多种调度策略,最常用的有几种:
- roundrobin(加权轮询):按权重轮流分配请求。适合请求处理时间相近、短平快的Web接口,这是最常用的默认策略;
- leastconn(最少连接):优先把新请求分给当前连接数最少的后端。适合长连接、WebSocket、数据库代理这种连接维持时间长的场景,因为它能动态避免某台机器堆积大量连接;
- source:对源IP做哈希,同一个客户端IP总是分到同一台后端。可以天然实现会话保持,但缺点是负载均衡效果受源IP分布影响。
我的选择经验是:如果后端接口都是毫秒级短请求,roundrobin就很好了;一旦有慢请求或长连接混进来,leastconn明显更接近“等开销”的目标。你可以在HAProxy统计页面上观察每台后端的连接数和队列深度,对比两种策略的效果,数据会告诉你答案。
4. 主备架构落地:Keepalived + HAProxy 完整配置与切换验证
4.1 拓扑与IP规划
动手配置之前,先把架构画清楚。这里我以两台负载均衡器、两台后端应用服务器的经典拓扑为例:
| 角色 | 主机名 | IP地址 | 说明 |
|---|---|---|---|
| 负载均衡主节点 | lb-01 | 192.168.10.10 | 平时持有VIP,承担流量转发 |
| 负载均衡备节点 | lb-02 | 192.168.10.11 | 监听心跳,主节点故障时接管VIP |
| 虚拟IP | VIP | 192.168.10.20 | 对客户端暴露的唯一入口 |
| 后端Web节点A | web-01 | 192.168.10.30 | 实际处理业务请求 |
| 后端Web节点B | web-02 | 192.168.10.31 | 实际处理业务请求 |
客户端访问的地址是http://192.168.10.20,这个VIP平时绑定在lb-01上。lb-01挂了,VIP自动漂移到lb-02。后端两台Web节点则通过HAProxy的健康检查自动摘除或恢复。
4.2 Keepalived配置:主节点与备节点
先安装基础组件,CentOS/RHEL系和Ubuntu系命令略有差异,但安装包名称基本一致:
# RHEL/CentOS系 yum install -y keepalived haproxy # Ubuntu/Debian系 apt install -y keepalived haproxy主节点lb-01的Keepalived配置如下,路径是/etc/keepalived/keepalived.conf:
global_defs { router_id LB_MASTER vrrp_skip_check_adv_addr script_user root enable_script_security } vrrp_script check_haproxy { script "/etc/keepalived/check_haproxy.sh" interval 2 fall 2 rise 2 } vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 150 advert_int 1 authentication { auth_type PASS auth_pass 4a2c9f7b } virtual_ipaddress { 192.168.10.20/24 dev eth0 } track_script { check_haproxy } }备节点lb-02的配置基本相似,差异主要有两处:state改为BACKUP,priority改为100。注意virtual_router_id两边必须一致,它是VRRP分组的标识,不一致就无法组成一个主备组。
这里解释一个关键点:vrrp_script check_haproxy段的作用是——Keepalived每隔2秒执行一次检查脚本,如果脚本返回非0(表示HAProxy进程异常),本机优先级自动降低,从而触发VIP切换到另一台节点。这个脚本是所有高可用配置里最容易被遗漏、却又最关键的一环,后面踩坑部分我还会展开讲。
配套的健康检查脚本/etc/keepalived/check_haproxy.sh内容如下:
#!/bin/bash # 检查haproxy进程是否存活 if pgrep -x haproxy > /dev/null; then exit 0 else exit 1 fi记得给脚本加执行权限:
chmod +x /etc/keepalived/check_haproxy.sh4.3 HAProxy配置:前端入口与后端分发策略
HAProxy配置文件路径是/etc/haproxy/haproxy.cfg,完整配置如下:
global log /dev/log local0 log /dev/log local1 notice maxconn 50000 user haproxy group haproxy stats socket /var/run/haproxy.sock mode 660 level admin daemon defaults log global mode http option httplog option dontlognull retries 3 timeout connect 5s timeout client 30s timeout server 30s maxconn 3000 frontend web_front bind *:80 default_backend web_servers backend web_servers mode http balance roundrobin option httpchk GET /healthz server web-01 192.168.10.30:8080 weight 1 check inter 3s fall 3 rise 2 server web-02 192.168.10.31:8080 weight 2 check inter 3s fall 3 rise 2 listen stats bind *:8404 mode http stats enable stats uri /stats stats refresh 5s stats auth admin:admin123几个关键参数逐一说一下为什么这么配:
balance roundrobin:加权轮询,适合大多数HTTP短请求场景。web-01和web-02权重设置成1:2,模拟两台机器性能不同的情况;option httpchk GET /healthz:健康检查探测的是/healthz接口,而不是只测端口。这个接口需要你在后端Web服务里提前实现,返回200表示健康,非200表示不健康;inter 3s fall 3:每3秒探测一次,连续3次失败把节点标记为不可用;weight 2:web-02权重更高,正常状态下会承担更多流量,这正好呼应前面说的“等开销”思路——让性能强的机器多干活;listen stats:暴露一个统计页面,后面压测和观察请求分布全靠它。
如果你的后端混合了TCP协议服务,比如要转发Redis、MySQL等流量,可以在配置里加一个四层转发段:
frontend redis_front bind *:6379 mode tcp default_backend redis_servers backend redis_servers mode tcp balance leastconn server redis-01 192.168.10.40:6379 check inter 3s fall 3 rise 2 server redis-02 192.168.10.41:6379 check inter 3s fall 3 rise 24.4 启动、开机自启与VIP切换验证
配置完成后,启动服务并设置开机自启:
# 两台机器都要执行 systemctl enable keepalived haproxy systemctl start keepalived systemctl start haproxy然后在lb-01上查看VIP绑定情况:
ip addr show eth0正常情况下,192.168.10.20应该出现在eth0网卡上,并标记为eth0:0或直接附加在eth0上。再用ip addr确认一次,Master角色正常。
接着做一次简单的切换验证:在lb-01上停掉keepalived服务(模拟主节点故障)。
systemctl stop keepalived几秒后再看lb-02的网络接口,VIP应该已经漂移过来了:
ip addr show eth0此时用curl http://192.168.10.20/healthz依然能正常返回,说明客户端无感知切换完成。最后重启lb-01上的keepalived,观察VIP是否自动抢回(这取决于preempt策略,默认是抢占模式,Master恢复后会重新抢回VIP)。
4.5 双主架构的扩展思路
主备架构的缺点是:备节点在正常情况下完全不承担流量,资源利用率只有50%。流量规模更大的团队可以做双主方案:两条VIP,lb-01持有VIP1,lb-02持有VIP2,两个VIP分别带一部分后端节点,同时两者互为备份。lb-01挂了,VIP1漂移到lb-02,lb-02同时服务两条VIP;lb-02挂了同理。
域名解析或云解析层面把两个VIP都配上做轮询,流量自然分摊到两台负载均衡器。这套方案把高可用和扩展性结合在了一起,成本只是多算一个VIP,非常值得在架构设计阶段就考虑进去。
5. 故障演练与压测观察:验证高可用的四个动作
5.1 故障演练清单
配置完成不代表高可用生效,必须通过故障演练验证。我维护的每套高可用负载均衡环境,上线前都会做一组模拟故障测试,测试项和预期结果如下:
| 故障动作 | 预期现象 | 验证方式 |
|---|---|---|
| 停掉web-01的Nginx服务 | web-01被健康检查标记为DOWN,流量全部转发到web-02 | 访问VIP,请求全部成功;HAProxy统计页看web-01状态为DOWN |
| 停掉lb-01的HAProxy进程 | vrrp_script检测到HAProxy异常,VIP漂移到lb-02 | lb-02上ip addr能看到VIP;访问VIP正常 |
| 直接关机lb-01 | VIP漂移到lb-02,整个入口不中断 | 备用机上ip addr确认VIP接管 |
| 在后端机器模拟接口变慢(人为延迟) | 健康检查超时,节点被自动摘除,恢复后自动加回 | HAProxy统计页观察状态变化,访问流量始终成功 |
每次演练之后,我都会把实际观察到的切换时间记录下来。从触发故障到VIP完成漂移,理想状态应该在3~5秒内完成,超过这个范围就需要回头检查健康检查参数和VRRP通告间隔。
5.2 压测看调度策略差异
故障演练验证的是“坏节点会被摘掉”,压测则是验证“活着的节点确实在按预期分摊流量”。
压测工具我用的是wrk,比较轻量,也可以直接用ab:
# 压测入口VIP,100并发,总共5万请求 wrk -t4 -c100 -d30s http://192.168.10.20/压测过程中,打开HAProxy统计页面http://192.168.10.20:8404/stats,可以看到web-01和web-02的请求数、当前连接数、队列深度。如果配置的是roundrobin且权重1:2,压测结束后两台后端的请求数比例应该接近1:2——web-01约1.7万,web-02约3.3万。
再用混合长短请求对比一下:把后端一个接口人为加入2秒延迟,压测场景里你会看到leastconn策略下,慢接口所在的机器连接数会被控制住,而roundrobin会把大量请求堆到慢机器上,导致响应时间整体飙升。这个对比很容易直观地感受到“等开销”和“平均分”的差别。
5.3 日常发布:优雅摘流,别让流量在发布瞬间“硬切”
高可用负载均衡不只是故障时的保护伞,日常发布变更时它也是好用的工具。后端服务要重启、发布新版本时,直接在HAProxy里摘掉该节点,等流量归零后再操作,这是标准做法。
传统做法是disable server,把节点立即标记为下线,已经建立的连接会被强制断开。对于长连接场景,这会造成用户侧请求中断。更好的做法是HAProxy 2.2版本开始支持的drain模式——不再向该节点分配新连接,但允许存量连接自然结束。
# 通过stats socket进入管理接口 echo "set server web_servers/web-02 state drain" | socat stdio /var/run/haproxy.sock # 等存量连接结束后,查看节点连接数归零 echo "show servers state" | socat stdio /var/run/haproxy.sock # 发布完成后恢复节点 echo "set server web_servers/web-02 state ready" | socat stdio /var/run/haproxy.sock这套操作流程的意义在于:流量切换不是在瞬间强制切断,而是平滑过渡,配合权重和drain模式,可以让发布过程的流量变化非常平滑。
6. 生产环境四个坑与完整排错思路
6.1 坑一:VIP漂移成功了,流量就是不通——ARP缓存问题
现象:手动停掉主节点Keepalived后,备节点ip addr确实看到了VIP,但客户端访问VIP全部超时。
排查链路:先确认VIP漂移 → 在备节点上检查VIP是否绑定成功 → 在网关或客户端机器上执行arp -a | grep 192.168.10.20,结果发现ARP缓存里记录的MAC地址依然是主节点的网卡MAC。
问题本质:VRRP切换后,新主节点会发送免费ARP来更新交换机的MAC表。但如果网络设备开启了ARP严格学习或MAC表老化时间较长,免费ARP可能没有被正确处理,旧表项迟迟不更新,流量继续被转发到已经下线的旧主节点。
解决办法:配置Keepalived时,在virtual_ipaddress块中显式启用nopreempt配合garp_master_delay参数,或在交换机上手动清一次ARP表。我个人的习惯是:在做VIP漂移验证前,先在交换机上执行clear arp,再观察Keepalived是否自动发送免费ARP报文,这样能快速判断问题方向。
6.2 坑二:健康检查把“慢而健在”的节点误杀
现象:某天业务高峰期,收到后端响应变慢的报警。登录HAProxy统计页一看,一台后端节点被标记成DOWN了,但登录机器检查,CPU、内存都正常,服务进程也没挂。
排查链路:先看后端进程状态 → 手动在负载均衡机器上curl http://192.168.10.30/healthz,发现响应花了4秒多才返回 → 再看HAProxy健康检查参数,inter 3s fall 3,也就是说连续3次探测都超过3秒没响应,节点就被判死了。
问题本质:健康检查的超时时间取决于timeout connect和timeout server,而探测间隔是3秒。后端接口一旦偶发慢查询,连续几次都卡在3秒以上,就会被误杀。这个“慢而健在”的节点被摘掉后,流量全部压到另一台,反而把另一台也拖慢了。
解决办法:把健康检查超时调宽到5~8秒,fall调大到4~5次,给后端足够的抖动容忍度。同时优化/healthz接口本身的查询逻辑,让它只检查核心依赖,绝不执行重查询。健康检查的接口必须“轻”,它只回答一个二进制问题:现在能不能接流量。
6.3 坑三:脑裂——两台机器同时持有VIP
现象:某次网络调整之后,发现VIP在lb-01和lb-02上同时出现了,两边都在对外提供服务,导致后端出现连接混乱、请求超时、日志里出现大量异常的MAC漂移记录。
排查链路:抓包看VRRP报文是否正常到达对端 → 在lb-02上执行tcpdump -i eth0 vrrp,结果20秒内一个VRRP报文都没收到 → 检查网络路径,发现交换机上配置的ACL把VRRP使用的组播地址和协议号拦截了。
问题本质:VRRP依赖心跳报文来维持“主我来当,备你待命”的默契。心跳被防火墙或网络策略阻断后,双方都认为对方已经死亡,于是同时进入Master状态,都绑定VIP,脑裂就发生了。
解决办法:开源Keepalived支持单播VRRP模式,绕过组播的网络限制。在vrrp_instance里配置unicast_peer指向对端IP,同时确保防火墙放行单播报文:
vrrp_instance VI_1 { state BACKUP interface eth0 virtual_router_id 51 priority 100 advert_int 1 unicast_src_ip 192.168.10.11 unicast_peer { 192.168.10.10 } authentication { auth_type PASS auth_pass 4a2c9f7b } virtual_ipaddress { 192.168.10.20/24 dev eth0 } }单播模式比组播模式更可控,排障时也更容易抓包确认:TCPDump过滤对端IP就能看到心跳是否送达。脑裂的最终防线是监控告警脚本,定期检测VIP是否在预期节点上,如果两台同时持有,立即人工介入。
6.4 坑四:Keepalived根本不知道HAProxy已经死了
这个坑我认为是最隐蔽、也最致命的。
现象:某次主节点HAProxy进程因为配置语法错误退出了,但VIP还稳稳地绑定在lb-01上。所有请求都到达了lb-01,却没有任何进程处理转发,整站直接瘫痪。检查lb-01:Keepalived进程活着,VIP也在,心跳正常,备节点完全没有触发切换。
问题本质:默认的Keepalived只负责VRRP心跳和VIP管理,它压根不关心HAProxy进程是否存活。HAProxy虽然死了,但Keepalived自身很健康,它会继续发送“我还活着”的心跳,VIP自然也不会飘走。
解决办法:这正是4.2节里配置vrrp_script check_haproxy的原因。检查脚本确保HAProxy进程异常时,本机VRRP优先级自动降低,强制触发VIP切换。这个脚本必须配合track_script一起使用,两者缺一不可。还要注意:脚本里不能只写进程检查,更完善的做法是同时用haproxy -c -f /etc/haproxy/haproxy.cfg校验配置,或者用socat请求HAProxy的socket接口做一次真实探活。
到这里,这套高可用负载均衡体系的原理、落地、验证和坑点基本都覆盖了。我自己的习惯是每次新环境搭完,都会重新读一遍这几页笔记,逐个坑对照检查一遍再交付。如果只留三条最核心的建议,我会说:先写好vrrp_script再谈高可用;健康检查宁可宽容不要激进;任何变更之后都跑一遍故障演练——这三点做到了,负载均衡这一层基本就稳了。