做高可用实验最怕的不是装不起来,而是你花了一晚上把 Keepalived 和 Haproxy 都装好,看到 VIP 落在某台机器上,就理所当然地认为实验成功了。我最初也是这么想的,直到在测试环境里故意把主节点的 haproxy 进程停掉,发现 VIP 纹丝不动地停在原地,外部请求还是全部打到旧节点上,才意识到这套系统里最关键的其实不是安装配置,而是"故障到底怎么被感知、怎么被转移"。
这篇文章是我整理的一份 Keepalived+Haproxy 高可用集群实验记录。实验主线是用两台虚拟机搭建负载均衡层,一台 Keepalived 负责 VIP 漂移和节点选举,一台 Haproxy 负责七层流量分发,然后完整验证主节点进程被杀、主机宕机、节点恢复抢占这几个常见故障场景。适合刚接触高可用集群、或者准备在生产环境落地 Keepalived+Haproxy 方案的运维朋友参考,内容会从架构选型一路讲到故障实测,再讲到几个我踩过的坑和对应的排查思路。
1. 为什么下决心做Keepalived+Haproxy这个组合
很多人在做负载均衡高可用实验时,第一反应是 Keepalived 直接配合 Nginx,或者干脆用 LVS 加 Keepalived。我不能说这些方案不对,但如果你和我一样,想"在一个可控的实验环境里把故障转移机制看得清清楚楚",Keepalived+Haproxy 这套组合确实有它独特的优势。
1.1 市面上常见的三条技术路线
先聊一下我在选型时对比过的三条路线。
第一条是 LVS+Keepalived,这也是老牌高可用架构。LVS 跑在四层,转发性能非常强,适合超高并发场景。但 LVS 的 DR 模式要求后端服务器也需要绑定 VIP、抑制 ARP 响应,后端节点要额外做一堆网络层配置;TUN 模式又要处理隧道问题。做实验时这些细节很容易把注意力从"高可用原理"拉走,变成网络调优排错。
第二条是 Keepalived+Nginx。Nginx 的配置大家很熟,拿来做反向代理没有任何心理负担。但 Nginx 更擅长的是 Web 服务本身,作为一个"纯负载均衡代理",它的健康检查能力、后端状态可视化不如 Haproxy 直观,尤其是想在实验里实时看到某个后端节点从 UP 变成 DOWN,Haproxy 的 stats 页面要比 Nginx 的日志检查方便好几个量级。
第三条就是这篇实验的主角,Keepalived+Haproxy。Keepalived 管 VIP、管节点状态选举,Haproxy 管后端的流量分发和健康检查。两层职责非常清晰,实验时你可以单独操作任何一层来观察另一层的反应。对于理解高可用集群来说,这种"模块边界清晰"的架构是最好的教科书。
1.2 这套组合要解决的问题
从实际工作角度看,这套组合解决的是"接入层单点故障"的问题。我有两台负载均衡器,它们共同对外提供一个虚拟 IP,用户只需要访问这个 VIP,而不需要关心当前流量到底由哪台机器处理。正常情况下主节点承载流量,当主节点整体宕机,或者主节点上的 Haproxy 进程异常退出时,Backup 节点需要无缝接管 VIP,继续对外提供服务。
注意这里我刻意区分了"整机宕机"和"服务进程异常"两种情况。Keepalived 本身作为一个进程,它天然能感知到对端 Keepalived 是否还活着;但它不会主动去感知你机器上的 Haproxy 是否健康。这个差异就是实验里最大的价值点——如果不做额外配置,主节点的 Haproxy 挂掉,VIP 并不会漂移,对外服务照样会中断。这个结论我在不少团队里看到有人误判过,所以这篇记录里会用专门一节展开讲。
实验最终验证的目标有三个:正常情况下流量能通过 VIP 均匀分发到后端;主节点任意一种故障出现时,VIP 能在几秒内漂移到备用节点;主节点恢复后,集群状态能回到预期设计,并且不会因为频繁抢占造成服务抖动。
2. 实验前置:节点规划、初始化和后端准备
实验环境不复杂,但要先把网络规划和基础状态理清楚,否则后面排查问题时根本分不清问题是出在 Keepalived、Haproxy 还是后端 Web 上。
2.1 实验拓扑与IP地址分配
我用两台虚拟机做负载均衡节点,两台虚拟机做后端 Web 节点。操作系统用的是 RHEL 系发行版的最小化安装,虚拟机网络全部放在同一个虚拟网段,保证二层互通。具体规划如下:
| 节点角色 | 主机名 | IP地址 | 部署组件 |
|---|---|---|---|
| 负载均衡主节点 | lb01 | 192.168.56.101 | keepalived + haproxy |
| 负载均衡备节点 | lb02 | 192.168.56.102 | keepalived + haproxy |
| VIP(虚拟IP) | - | 192.168.56.100 | 随主备节点状态漂移 |
| 后端Web节点1 | web01 | 192.168.56.20 | httpd/nginx |
| 后端Web节点2 | web02 | 192.168.56.21 | httpd/nginx |
之所以把两台负载均衡节点和两台后端放在同一个网段,是因为 Keepalived 的 VRRP 协议默认通过组播方式交换心跳,组播包在同一个二层网段里最稳定。如果你在实验环境里划分了复杂 VLAN,那就要额外考虑组播穿越的问题,这个我放到第六部分里单独讲。
2.2 两台负载均衡节点的初始化清单
两台 LB 节点的初始化动作完全一致,我建议你全部做完再开始配置,避免后面出现"一边能通、一边不能通"的玄学问题。
首先关闭 SELinux,实验环境里不关会引入很多权限层干扰,尤其是脚本可执行权限和目录上下文问题。生产环境当然不能用这种方式处理,但实验阶段图的是快速定位问题。
setenforce 0 sed -i 's/^SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config然后是防火墙。实验环境我直接关闭了 firewalld,原因是 VRRP 组播包和 Haproxy 的健康检查请求经常会被防火墙策略挡住,对新手来说排查起来很绕。生产环境不要照抄这个操作,正确做法是放行 VRRP 协议和 80/443 端口。
systemctl stop firewalld systemctl disable firewalld接下来同步时间。Keepalived 对时间同步不是特别敏感,但如果你后面要用证书、审计日志对比节点事件,时间不一致会让排查非常痛苦。顺手装一个常用工具包,探活脚本里要用到 killall。
yum install -y ntpdate psmisc ntpdate pool.ntp.org2.3 后端Web服务准备
后端起一个简单的静态页面服务就行,目的是让 Haproxy 的健康检查有明确目标。两个节点的内容要有区分度,比如 web01 的 index.html 内容写入web01,web02 写入web02,这样通过 curl 访问 VIP 时能直观看到轮询效果。
我建议在后端增加一个独立健康检查文件,路径为/var/www/html/health,内容只是一个状态关键词。为什么不直接检查/路径?因为根路径可能受首页程序逻辑影响,比如动态页面响应慢或者返回 500,导致健康检查误判后端故障。独立的/health页面最稳定,能明确表示"这台机器的 Web 服务本身还活着"。
两个后端节点准备好后,先在本地验证一下:
curl -s http://127.0.0.1/ curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1/health看到各自标识和200状态码,后端部分就算准备好了。
3. Keepalived配置拆解:VRRP通告、抢占策略和健康检查
Keepalived 的核心作用不是负载均衡,而是通过 VRRP 协议维护一个集群视角的 VIP。理解它的状态机是写配置的前提。
3.1 主备节点配置对比
先在主节点 lb01 上安装并编辑配置:
yum install -y keepalived vim /etc/keepalived/keepalived.conf主节点一份比较完整的配置长这样:
global_defs { router_id LB01 } vrrp_script chk_haproxy { script "/etc/keepalived/check_haproxy.sh" interval 2 weight -20 rise 2 fall 3 } vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 123456 } virtual_ipaddress { 192.168.56.100/24 dev eth0 label eth0:1 } track_script { chk_haproxy } }备用节点 lb02 的配置结构完全一样,区别只在四行:router_id改成 LB02,state改成 BACKUP,priority改成 90,然后去掉virtual_ipaddress里的 tower 需求? 不对,两台机器都要保留virtual_ipaddress这一整段,VIP 是集群共享的,只是平时由 MASTER 持有。
这里你要理解 VRRP 的几个核心参数。virtual_router_id是虚拟路由器编号,同一个 VRRP 组里的所有节点必须一致,不能和网段内其他集群冲突。priority是选举依据,数字越大越优先成为 MASTER。advert_int是心跳间隔,单位秒,MASTER 每隔 1 秒往组播地址224.0.0.18发送 VRRP 通告,Backup 节点连续三次没有收到通告,就会认为 MASTER 失联,然后按优先级重新选举。默认的抢占策略是:优先级高的 BACKUP 一旦出现,就会立刻抢占当前 MASTER,这个行为在生产环境中不一定友好,后面第七部分会讲怎么改成非抢占。
auth_pass在实验环境里只是个轻量校验,并不是安全机制。真实的 VRRP 报文中这串口令会以明文方式参与 HMAC 校验,但它不能防止同网段内其他设备伪造 VRRP 报文,只能挡一下配置粗心的误入者。
3.2 check_haproxy.sh:为什么探活脚本不能省略
这是整个实验里最容易被忽略,也最值得反复强调的部分。Keepalived 只检查对端 Keepalived 进程,它根本不关心你的 Haproxy 是活着还是死了。如果不做track_script,就一定会出现"主节点 Haproxy 挂了,VIP 却不走"的问题。
我的探活脚本放在/etc/keepalived/check_haproxy.sh:
#!/bin/bash if ! killall -0 haproxy 2>/dev/null; then systemctl restart haproxy 2>/dev/null sleep 2 if ! killall -0 haproxy 2>/dev/null; then exit 1 fi fi exit 0脚本的逻辑是先检查 haproxy 进程是否存在。killall -0不是杀掉进程,而是发送空信号检测进程状态,存在返回 0,不存在返回非 0。如果进程不存在,先尝试自动拉起,等待 2 秒后再检查一次;如果拉起失败,才返回退出码 1,这个退出码会驱动 Keepalived 的权重切换机制。
配合weight -20来看:正常情况下主节点优先级是 100,当脚本检测失败时优先级变成 80,低于备用节点的 90,于是备用节点抢占 VIP,完成故障转移。这种做法的好处是 Keepalived 自身没有退出,节点还处于集群内,只是优先级被降级,恢复后还能继续参与选举;相比直接在脚本里systemctl stop keepalived,这种方式更平滑,也不会因为 Keepalived 崩溃造成日志和状态混乱。
记得给脚本加上执行权限,否则track_script会静默失败:
chmod +x /etc/keepalived/check_haproxy.sh3.3 启动前必做检查
配置文件改完,不要直接systemctl start keepalived,先用语法检查命令过一遍:
keepalived -t -f /etc/keepalived/keepalived.conf这条命令会解析配置并提示语法错误。Keepalived 的配置对关键字大小写敏感,比如state必须是大写 MASTER/BACKUP,interface必须和系统实际网卡名一致,这些错误通常不会在启动时报得很明显,但会导致状态不正常。
确认没问题后启动服务并设置开机自启:
systemctl enable --now keepalived systemctl status keepalived然后重点看一下 VIP 是否已经挂在主节点上:
ip addr show eth0正常情况主节点会出现eth0:1和192.168.56.100/24,备用节点不会出现这个地址。只有确认 VIP 归属符合预期,后面做故障转移实验才有基准。
4. Haproxy负载均衡配置:从前端到后端的一站式细节
Keepalived 把 VIP 保持在了当前 MASTER 节点上,那用户访问 VIP 的流量谁来处理?Haproxy 就是干这个的。两个 LB 节点都要安装 Haproxy,并且配置保持一致,因为主节点故障后备用节点要能立刻提供同样的服务。
4.1 一段能直接用的haproxy.cfg
安装 Haproxy 后,主配置文件在/etc/haproxy/haproxy.cfg,我实验用的配置模板如下:
global maxconn 4096 log 127.0.0.1 local0 warn user haproxy group haproxy defaults mode http option httplog option redispatch timeout connect 3s timeout client 30s timeout server 30s frontend web_front bind *:80 default_backend web_back backend web_back balance roundrobin option httpchk GET /health server web01 192.168.56.20:80 check inter 3s fall 2 rise 3 server web02 192.168.56.21:80 check inter 3s fall 2 rise 3 listen stats bind *:9999 mode http stats enable stats uri /stats stats refresh 5s stats auth admin:lb123456这里几个关键点分别说。bind *:80用的是通配地址,而不是直接绑定 VIP 的192.168.56.100:80。这样设计的好处是,当 Keepalived 切换、VIP 还没落到本机时,Haproxy 进程不会因为绑定失败而崩溃,也不需要额外开启ip_nonlocal_bind。备机平时虽然没有 VIP,但 Haproxy 进程照常运行,一旦接管 VIP,服务立即生效。
option httpchk GET /health是健康检查方式。Haproxy 会每隔inter 3s向后端节点的/health路径发一次请求,连续成功rise 3次标记为 UP,连续失败fall 2次标记为 DOWN。后端被标记为 DOWN 后,Haproxy 不会再把新请求转发过去,这比 TCP 端口检测可靠得多,因为端口通并不代表业务可用。
balance roundrobin是轮询算法,适合后端能力相近的场景。如果你的后端机器性能差异大,后续可以换成leastconn或source等算法,实验阶段轮询最直观。
监听 9999 端口的listen stats段是 Haproxy 的统计页面,访问http://192.168.56.100:9999/stats能看到后端节点实时状态。这个页面在实验里几乎是必需的,因为你能直接看到 web01、web02 是绿色 UP 还是红色 DOWN,不需要反复 curl 去猜。
配置好后启动 Haproxy:
systemctl enable --now haproxy systemctl status haproxy4.2 健康检查路径和轮询结果验证
在两个 LB 节点上都启动 Haproxy 后,先在主节点上验证后端 IP 是否正确:
curl -s http://127.0.0.1/health正常情况下返回后端的 health 文件内容。然后再通过 VIP 访问:
for i in $(seq 1 10); do curl -s http://192.168.56.100/ | grep -o "web[0-9]*" done你会看到结果交替出现web01和web02,说明轮询生效了。这时候顺手打开统计页面,确认两个后端都是 UP。如果出现某个后端一直是 DOWN,别急着调 Keepalived,先去检查后端节点的/health文件权限和路径,这个排查方向在第七部分我会再次强调。
5. 故障转移实验实录:杀进程、断电、恢复抢占
配置全部就绪后,就到了最有意思的部分:故障注入实验。这部分我会按照"实验前状态快照、进程级故障、整机故障、节点恢复"四个步骤来记录,每一步都给了验证命令和观察结果。
5.1 实验前的状态快照
做故障实验前,先把集群的基准状态记录下来,后面所有变化才有对照基础。
在主节点 lb01 上查看:
ip -brief addr show systemctl status keepalived haproxy确认结果是:lb01 持有192.168.56.100,Keepalived 和 Haproxy 都是 active 状态。备用节点 lb02 上确认没有 VIP,Keepalived 和 Haproxy 也都是 active 状态。这两台机器的 Haproxy 进程同时都在跑,只是备用节点因为 VIP 不在本机,暂时不接收来自 VIP 的流量而已。
如果想看得更深入,可以在两台机器上抓一下 VRRP 报文:
tcpdump -i eth0 host 224.0.0.18主节点方向能看到周期性的 VRRP 通告报文,间隔正好 1 秒;备用节点方向能看到它在持续监听这些报文。这一步可以让你从报文层面理解 Keepalived 的心跳机制,比只看进程状态要扎实得多。
5.2 第一轮实验:主haproxy进程被杀
第一轮模拟的是最常见的"进程级故障":主节点的 Haproxy 挂了,Keepalived 还在跑。这时探活脚本就派上了用场。
在主节点上执行:
systemctl stop haproxy然后立即观察集群变化。由于check_haproxy.sh会尝试自动重启 Haproxy,所以实际效果取决于脚本逻辑。在我这个配置里,手动systemctl stop haproxy后,脚本会在下一个检测周期发现进程不存在,然后拉起 Haproxy。如果进程被手动 stop 后可以正常被 systemd 拉起来,你会看到 Haproxy 状态又恢复 active。为了真正模拟"起不来的故障",可以改成直接 kill 掉进程,或者把 Haproxy 服务设置为 masked,让脚本重启失败。
我更推荐直接模拟脚本重启失败的场景,因为你最终关心的是 VIP 会不会转移。操作如下:
systemctl mask haproxy pkill -9 haproxy大概 4 到 6 秒后,观察 VIP 归属:
ip -brief addr show你会看到 lb01 上的192.168.56.100消失,lb02 上出现了这个地址。同时从任意客户端访问http://192.168.56.100/,请求依然能被 web01、web02 轮询回应,说明 VIP 故障转移过程中服务没有中断。Haproxy 的统计页面这时也会正常展示 UP 的后端节点。
这个实验的关键结论是:Keepalived 的探活不是开箱即用的,它需要你明确告诉它什么叫做"主节点不健康"。vrrp_script的行权机制让故障转移不再依赖"进程崩溃"这种极端事件,而是把业务进程的健康状态纳入到了集群选举的权重体系里。
5.3 第二轮实验:直接关掉主节点
第一轮是"进程挂了",第二轮是"整机宕机"。这个场景最直接,也最容易理解——主节点彻底不工作了,备用节点必须通过 VRRP 通告超时来感知故障。
我先恢复第一轮的现场:把 Haproxy 解除 mask,确认主节点重新抢回 VIP,集群回到初始状态。然后直接给主节点虚拟机执行关机命令,模拟宕机:
poweroff此时主节点不再发送任何 VRRP 通告。备用节点连续三个心跳周期没有收到通告,master_down_timer 超时,就会从 BACKUP 切换到 MASTER。我在实验里观察到的漂移时间大概在 3 到 5 秒左右,符合advert_int 1、连续丢失 3 个通告的设计预期。
切换完成后在备用节点上执行:
ip -brief addr show journalctl -u keepalived -f可以看到 VIP 挂到了 eth0 上,keepalived 日志会出现VRRP_Instance(VI_1) entering MASTER STATE的记录。这时候你从客户端访问 VIP,服务依然可用。
这里要注意一个细节:Haproxy 的option redispatch配置在这种切换场景下很有帮助。它允许当某个后端连接出现问题、服务器没有及时响应时,Haproxy 把请求重新分配给其他后端。故障转移瞬间如果有客户端恰好处在长连接上,连接会被重置,但新连接完全不受影响。
5.4 第三轮实验:主节点恢复后的抢占观察
主节点重新开机后,两台机器的 Keepalived 会重新通信。由于我配置里state MASTER和priority 100默认启用抢占策略,lb01 一旦回来就会立刻抢占回 VIP,lb02 会从 MASTER 重新降回 BACKUP。
我在恢复主节点电源后等了两分钟,然后分别查看两台机器的 VIP 归属,发现 VIP 已经回到 lb01 上。lb02 的日志里会出现VRRP_Instance(VI_1) entering BACKUP STATE,一切正常。
但这个"一切正常"里藏着一个生产环境常见的问题:抢占往往意味着一次不必要的网络切换。比如主节点只是短暂重启或者网络抖动,恢复后立刻抢回 VIP,会造成连接再次中断。对于无状态的 Web 服务来说影响不大,但如果后面挂着 Redis、数据库代理或者长连接网关,这种抢占抖动就可能影响业务。实验阶段你看到了默认行为,生产环境就要针对这个行为做修正,这部分我在第七部分给了具体做法。
6. 实验里值得记录的三个坑和排查过程
毕竟是实验,不踩几个坑都说不过去。这一节我把整个实验里印象最深的三个问题记录下来,每个都给出完整的排查链路,而不是直接告诉你答案。
6.1 两个MASTER同时出现:先看组播通不通
第一次做双节点实验时,我遇到一个诡异现象:两台机器状态都显示 MASTER,VIP 都出现在各自网卡上。外部访问 VIP 时,由于两台机器都声称拥有同一 IP,网络表现完全随机,时而通、时而不通。
排查思路首先锁定 VRRP 通信。Keepalived 依赖组播报文让 Backup 感知 Master,如果 Backup 收不到任何 Master 的通告,它就会认为 Master 失联,自己抢占 MASTER,这就是典型的脑裂。我先在备用节点上抓包,看能否收到主节点的 VRRP 报文:
tcpdump -i eth0 vrrp结果发现备用节点完全收不到任何 VRRP 报文。进一步排查,发现是系统防火墙把 VRRP 组播给拦了。实验环境我直接关掉 firewalld 解决了,但生产环境不能这么粗暴,正确做法是放行 VRRP 协议:
firewall-cmd --permanent --add-protocol=vrrp firewall-cmd --reload如果你所在网络环境不支持组播,比如很多虚拟私有云环境,那就需要改成单播模式,在vrrp_instance里指定对端地址:
unicast_src_ip 192.168.56.101 unicast_peer { 192.168.56.102 }这个配置让 Keepalived 用单播方式交换心跳,不再依赖组播。我后来在需要跨三层网络搭建 Keepalived 时也用到过这个方法,实用性很强。
6.2 haproxy进程挂了但VIP纹丝不动:问题出在探活链路上
这是我开头说过的那个问题:配置完 Keepalived 但没配track_script,Haproxy 进程挂掉后 VIP 不转移。当时我以为 Keepalived 作为"高可用组件",理所当然能保护所有本地服务,事实证明并不是。
排查时我先手动执行探活脚本,确认脚本本身能正确返回非 0 退出码。然后查看 Keepalived 日志,发现日志里根本没有脚本执行记录。再排查才发现,脚本文件没有加执行权限,track_script引用的脚本无法运行,Keepalived 只能在日志里报错但不会同步到我的注意力范围内。
这个坑提醒我:对于 Keepalived 的探活链路,每一环都要单独验证。脚本能不能执行、退出码是不是预期值、vrrp_script是否被track_script引用、weight值是否让主备产生优先级翻转,这些环节缺一不可。排查顺序也建议从脚本本身往上层走,不要在没验证脚本的情况下就去怀疑 Keepalived 配置。
6.3 restart keepalived造成VIP瞬断
第三个坑来自一次常规操作:我在主节点上执行systemctl restart keepalived想应用新配置,结果发现 VIP 出现了明显的瞬断,外部 curl 访问在这几秒内失败。
原因是 Keepalived 重启会先把网卡上的 VIP 摘掉,再重新挂上。这个摘掉和挂上之间有一个很小的窗口,VIP 不在任何节点上,服务自然中断。实验里我用了三台客户端机器并发测试,丢包时间在 1 到 3 秒左右,与 Keepalived 重启耗时基本一致。
生产环境如果要调整 Keepalived 配置,我的建议是不要直接在主节点上重启,而是先改备节点,然后通过降低主节点优先级或者直接切换 VIP 的方式让流量先落到备节点,再重启主节点。如果坚持原地重启,那就要接受 VIP 瞬断的代价。这个操作层面的细节,通常只有真实踩过坑才会放在心上。
7. 从实验台到生产环境:我做过的几处配置修正
实验验证的是机制,生产关注的是稳定。把这套架构从实验台搬到生产环境时,我做了三处比较重要的配置修正,这里一并分享。
7.1 nopreempt 替代默认抢占
默认抢占模式下,主节点从短暂故障中恢复后会立刻抢回 VIP。这在很多业务场景里并不是最优解,因为每次抢占都是一次无谓的网络切换。生产环境我建议改成非抢占模式。
具体做法是两台节点的state都配置为 BACKUP,并在vrrp_instance中加入nopreempt:
vrrp_instance VI_1 { state BACKUP nopreempt priority 100 ... }非抢占模式下,高优先级节点不会因为自己恢复就立刻抢占当前 MASTER,它会一直保持 BACKUP 状态,直到当前 MASTER 发生故障,才会重新参与选举。这样就把"切换频率"降到了最低,对长连接类服务非常友好。
7.2 双VIP互为主备,让两台机器都有活干
单主备模式下,备机平时完全空闲,有点浪费。生产环境我倾向于做双 VIP 互为主备:定义两个vrrp_instance,第一个 VIP 的主节点是 lb01,第二个 VIP 的主节点是 lb02,彼此互为备份。
vrrp_instance VI_1 { state MASTER priority 100 virtual_router_id 51 virtual_ipaddress { 192.168.56.100/24 dev eth0 label eth0:1 } } vrrp_instance VI_2 { state BACKUP priority 90 virtual_router_id 52 virtual_ipaddress { 192.168.56.101/24 dev eth0 label eth0:1 } }lb02 上的配置正好反过来:VI_1 是 BACKUP,VI_2 是 MASTER。这样两个 VIP 同时对外提供服务,正常情况下两台 LB 都在承接流量;任何一台故障,另一台会接管它的 VIP。这个模式充分利用了硬件资源,也让故障切换时业务影响面更小,是我在生产环境最推荐的一种落地方式。
7.3 最后一条建议:先单机跑,再滚动引入冗余
最后聊一个和配置无关、但同样重要的建议。不要一开始就把两台节点同时上线到生产流量里。先把一台 Haproxy 接入真实流量跑几天,看日志、看统计页面的后端状态、看 Keepalived 的心跳稳定性,确认没有任何异常后,再把第二台节点以 BACKUP 身份加进去。
在这个滚动过程中,你会发现很多实验环境模拟不出来的问题:比如后端健康检查路径在生产环境响应慢、防火墙策略对 VRRP 组播有隐性拦截、NAT 环境下客户端真实 IP 取不到等等。Keepalived+Haproxy 这套架构本身很成熟,但真正让它在生产环境稳定运行的,往往不是配置文件有多完美,而是你愿意花多少时间去观察它在真实流量下的行为。实验台给你的是一套可复制的机制,生产环境给你的才是最终答案。