HAProxy + Keepalived 高可用负载均衡集群实战:VIP 漂移与脑裂防范 1. 为什么单台负载均衡器迟早会出事很多团队第一次搭负载均衡思路都很直接找一台机器装上 HAProxy后端挂几台 Web 服务器流量一分收工。这套方案在测试环境跑得挺欢一上生产就开始暴露问题——HAProxy 这台机器本身成了整个架构里最脆弱的一环。它一挂后面所有后端服务再健康也没用用户侧看到的就是整站不可用。这就是典型的单点故障。负载均衡器的职责是把流量分发出去但它自己并没有被负载均衡。所以真正能上生产的高可用负载均衡集群核心要解决的是两件事第一流量分发要高效稳定这是 HAProxy 的活第二分发者本身要能故障自动切换这是 Keepalived 的活。两者组合起来才是一个完整的、能扛住单机宕机的高可用方案。这篇文章面向的是已经会装 Linux、懂基本网络概念、但还没亲手搭过高可用集群的运维和开发同学。我会从架构选型讲到具体配置把 VIP 漂移、健康检查、脑裂防范这些容易踩坑的地方全部拆开讲清楚。整套方案基于主备模式Active-Backup这是中小规模业务里最稳、最容易维护的一种高可用形态不追求花哨追求的是出事的时候真的能切过去。先明确一下这套集群最终要达成的效果对外暴露一个虚拟 IPVIP客户端只认这个 VIP两台负载均衡节点一主一备主机正常时备机待命主机上的 HAProxy 或整台机器出问题VIP 在秒级内漂移到备机备机接管流量客户端几乎无感知。后端真实服务器则通过 HAProxy 做四层或七层转发并配合健康检查自动摘除故障节点。2. 整体架构设计与选型思路拆解2.1 为什么是 HAProxy 加 Keepalived 这个组合负载均衡软件的选择其实不少常见的有 LVS、Nginx、HAProxy。LVS 工作在四层性能极强但配置相对晦涩七层能力弱Nginx 做反向代理很顺手但作为专职负载均衡器它的健康检查机制相对简单商业版才有比较完善的后端探测HAProxy 则是专门为负载均衡和高可用设计的四层七层都支持健康检查策略丰富会话保持、连接队列、统计页面这些生产必备功能都是原生自带。Keepalived 的定位更聚焦它最初是为 LVS 做高可用而生的核心能力就是VRRP 协议实现 IP 漂移外加对本地服务的健康检查。用它来管 VIP 的漂移比自己写脚本监听、手动切 IP 可靠得多。VRRP 是虚拟路由冗余协议多台机器组成一个组通过组播互相通告自己的状态优先级高的成为 Master 持有 VIPMaster 失联后 Backup 依据优先级重新选举并接管 VIP。所以这个组合的分工非常清晰HAProxy 负责把流量分好Keepalived 负责让分发者不死。两者各司其职耦合度低出问题时排查方向也明确。2.2 主备模式与主主模式的取舍高可用拓扑上主备Active-Backup和主主Active-Active是两条路。主主模式两台机器同时工作资源利用率高但配置复杂度陡增还要处理会话同步、后端连接状态一致等问题一旦设计不好切换时反而更容易出乱子。我个人的建议是除非你的流量确实大到单台 HAProxy 扛不住否则老老实实上主备。原因很实在——主备模式下备机平时不接流量配置可以做得和主机几乎一致切换逻辑简单出故障时行为可预测。HAProxy 单机的转发能力其实相当可观普通业务量级下一台机器完全撑得住真正的瓶颈往往在后端应用而不是负载均衡层。等业务真的发展到需要主主再演进也不迟架构是长出来的不是一步到位设计出来的。2.3 网络层面的关键前提这套方案有一个硬性前提两台负载均衡节点必须处于同一个二层网络也就是同一个广播域内。因为 VRRP 依赖组播通信VIP 的漂移本质上是备机通过免费 ARP 宣告这个 IP 现在归我了这要求网络设备能收到并更新 ARP 表。跨网段、跨机房做 VRRP 是行不通的那种场景得换别的方案。另外要提前规划好三个地址主机真实 IP、备机真实 IP、以及对外服务的 VIP。VIP 必须是同网段内未被占用的地址规划前一定要 ping 一下确认没人用否则后面会出现 IP 冲突这种极其难查的问题。角色真实 IP 示例说明HAProxy 主节点192.168.10.11持有 VIP对外服务HAProxy 备节点192.168.10.12待命主机故障时接管虚拟 IPVIP192.168.10.100客户端唯一访问入口后端服务器组192.168.10.21-23真实提供业务的应用节点3. 核心组件原理与关键配置细节3.1 VRRP 与 VIP 漂移到底是怎么发生的理解 Keepalived 的关键是理解 VRRP 的工作机制。同一个 VRRP 组里的节点会有一个虚拟路由器 IDvirtual_router_id这个 ID 必须在同网段内唯一不同组之间不能撞。每个节点配置一个优先级priority数值越大越优先范围是 1 到 254。优先级最高的节点成为 Master持有 VIP。Master 会周期性地向组播地址发送 VRRP 通告报文告诉其他节点我还活着。Backup 节点如果在一段时间内收不到通告就认为 Master 挂了于是发起选举优先级最高的 Backup 升级为 Master 并接管 VIP。这个一段时间由 advert_int通告间隔和超时机制共同决定间隔越短切换越快但网络抖动时误判的概率也越高。VIP 漂移的瞬间新 Master 会发送免费 ARPGratuitous ARP主动告诉同网段的交换机和其他设备这个 IP 的 MAC 地址变了请更新你的 ARP 缓存。这样后续发往 VIP 的流量才会被正确送到新 Master 上。如果免费 ARP 没发出去或者被网络设备拦截就会出现VIP 漂移了但流量还是发到旧机器的诡异现象这是排查切换问题时第一个要确认的点。3.2 HAProxy 的健康检查与会话保持HAProxy 的后端健康检查是它区别于普通反向代理的核心能力。它支持多种检查方式TCP 层可以只探测端口是否可连HTTP 层可以请求指定 URL 并校验返回状态码甚至可以用 expect 关键字校验返回内容里是否包含特定字符串。检查间隔inter和连续失败次数fall、连续成功次数rise共同决定一个后端节点何时被摘除、何时被恢复。举个实际场景后端应用启动需要时间如果健康检查太激进应用还没初始化完就被判定为故障摘除等它真正就绪时又要等好几轮检查才恢复中间这段时间流量全压在其他节点上。所以 fall 和 rise 的取值要结合应用启动速度来定不能照抄网上的默认值。会话保持方面如果后端应用是有状态的比如把 session 存在本地内存就必须开启会话保持否则同一个用户的请求被分到不同后端登录状态就丢了。HAProxy 支持基于源 IP 的哈希、基于 Cookie 的插入等多种方式。我的经验是能用 Cookie 就用 Cookie源 IP 哈希在用户走代理或移动网络时会失效因为同一用户出口 IP 可能变化。3.3 Keepalived 对本地服务的健康检查Keepalived 除了管 VIP还能监控本机的 HAProxy 进程。配置里可以写一个 vrrp_script定期执行一段脚本检查 HAProxy 是否存活比如检查进程是否存在、或者直接请求 HAProxy 的统计端口。一旦脚本返回失败达到指定次数Keepalived 就会主动降低本机优先级触发 VIP 漂移。这个机制非常重要因为很多时候机器本身没宕机但 HAProxy 进程崩了或者卡死了。如果没有这层检查VIP 还留在主机上但主机已经不能转发流量用户照样访问不了。加上 vrrp_script 之后HAProxy 一挂VIP 自动让给备机这才是真正意义上的服务级高可用而不只是机器级高可用。注意vrrp_script 里检查 HAProxy 的方式要选对。用kill -0检查进程存在只能发现进程崩溃发现不了进程假死。更稳妥的做法是请求 HAProxy 的统计页面或一个固定的健康探测 URL能拿到正常响应才算健康。4. 完整实操过程与核心环节实现4.1 环境准备与基础配置先在两台节点上统一基础环境。关闭防火墙对 VRRP 组播的拦截是关键一步VRRP 用的是 112 号协议很多默认防火墙策略会把它挡掉导致备机根本收不到主机的通告从而误判主机已死出现双 Master 抢 VIP 的脑裂。生产环境里更规范的做法是放行 VRRP 协议和组播地址而不是简单粗暴地全关防火墙。# 两台节点都执行放行 VRRP 协议协议号 112 firewall-cmd --direct --permanent --add-rule ipv4 filter INPUT 0 \ --protocol vrrp -j ACCEPT firewall-cmd --reload # 确认内核允许绑定非本机 IPVIP 漂移需要 sysctl -w net.ipv4.ip_nonlocal_bind1 echo net.ipv4.ip_nonlocal_bind 1 /etc/sysctl.confnet.ipv4.ip_nonlocal_bind这个参数特别容易被忽略。它的作用是允许进程绑定一个当前不属于本机的 IP 地址。备机在待命状态下VIP 并不在它身上但 HAProxy 的配置里监听的是 VIP如果不开启这个参数备机上的 HAProxy 会因为无法绑定不存在的地址而启动失败等真正需要切换时才发现备机根本没准备好那就尴尬了。4.2 HAProxy 配置详解HAProxy 的配置文件分四大块global、defaults、frontend、backend。下面这份配置是主备通用的两台机器配置完全一致这样切换时行为才可预测。# /etc/haproxy/haproxy.cfg global log 127.0.0.1 local2 maxconn 40000 daemon stats socket /var/run/haproxy.sock mode 600 level admin defaults mode http log global option httplog option dontlognull option http-server-close retries 3 timeout connect 5s timeout client 30s timeout server 30s frontend web_front bind 192.168.10.100:80 default_backend web_servers backend web_servers balance roundrobin option httpchk GET /health http-check expect status 200 server web1 192.168.10.21:80 check inter 2s fall 3 rise 2 server web2 192.168.10.22:80 check inter 2s fall 3 rise 2 server web3 192.168.10.23:80 check inter 2s fall 3 rise 2 listen stats bind 0.0.0.0:9000 stats enable stats uri /haproxy-status stats auth admin:StrongPass123几个参数值得展开说。maxconn 40000是单进程最大连接数要结合系统 ulimit 一起调光改这里不改系统限制是没用的。option httpchk GET /health配合http-check expect status 200表示只有后端返回 200 才算健康这比单纯探测端口可靠得多——端口开着但应用返回 500 的情况太常见了。inter 2s fall 3 rise 2意味着每 2 秒检查一次连续 3 次失败摘除连续 2 次成功恢复这个节奏在大多数业务里比较平衡。stats socket那一行是给 Keepalived 的健康检查脚本用的通过这个 socket 可以查询 HAProxy 的运行状态比 HTTP 请求统计页面更轻量。4.3 Keepalived 配置与 VIP 漂移实现Keepalived 的配置分三部分global_defs、vrrp_script、vrrp_instance。主备节点的差异只在 priority 和 state 上。主节点配置# /etc/keepalived/keepalived.conf 主节点 global_defs { router_id haproxy_master enable_script_security script_user root } vrrp_script chk_haproxy { script /etc/keepalived/check_haproxy.sh interval 2 weight -30 fall 2 rise 2 } vrrp_instance VI_WEB { state MASTER interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass ClusterPass2024 } virtual_ipaddress { 192.168.10.100/24 dev eth0 } track_script { chk_haproxy } }备节点配置几乎一样只改两处state BACKUP、priority 90。优先级差 10主机正常时备机永远抢不过它主机故障降权后weight -30 让优先级从 100 降到 70备机的 90 就能胜出接管 VIP。健康检查脚本check_haproxy.sh这样写#!/bin/bash # 通过 stats socket 查询 HAProxy 状态比请求 HTTP 更轻量 if ! echo show stat | socat stdio /var/run/haproxy.sock /dev/null 21; then exit 1 fi exit 0这里用 socat 连 HAProxy 的 stats socket能正常通信说明 HAProxy 进程活着且响应正常。脚本必须有可执行权限且script_user指定的用户要有权限访问那个 socket 文件。4.4 验证切换是否真的生效配置写完最关键的环节是验证。很多人配完就上线从没测过切换等真出事时才发现切不过去那就晚了。验证分几步走。先确认初始状态在主节点上执行ip addr show eth0应该能看到 VIP 192.168.10.100 挂在上面备节点上没有。然后从一台客户端持续 ping VIP同时手动停掉主节点的 HAProxy 或直接关机观察 ping 是否中断、中断多久恢复。正常情况下应该只丢一两个包VIP 在 1 到 2 秒内漂移到备机。# 客户端持续观察 VIP 连通性 ping -i 0.2 192.168.10.100 # 主节点上模拟 HAProxy 故障 systemctl stop haproxy # 备节点上确认 VIP 是否漂移过来 ip addr show eth0 | grep 192.168.10.100如果 VIP 没漂移按这个顺序排查先看备机有没有收到主机的 VRRP 通告抓包看 112 协议再看防火墙是否放行然后确认 virtual_router_id 和 auth_pass 主备是否一致最后检查健康检查脚本是不是一直返回失败导致主机优先级被降到了备机以下。5. 常见问题与排查技巧实录5.1 脑裂最危险也最常见的坑脑裂指的是主备两台机器同时认为自己是 Master同时持有 VIP。这时候同网段里会出现两个机器抢答 ARP流量时通时断现象非常诡异。脑裂的根因通常是 VRRP 通告收不到——防火墙拦截、组播被禁、网线单通、virtual_router_id 冲突都可能导致。排查脑裂第一步是在两台机器上同时ip addr看 VIP 是不是同时存在。确认后抓包看 VRRP 报文是否正常收发。防范上除了放行 VRRP还可以配置nopreempt非抢占模式避免主机恢复后立刻抢回 VIP 造成二次抖动以及用 unicast_peer 指定单播对端绕开组播在某些网络设备上被限制的问题。现象可能原因排查方向双 Master 抢 VIPVRRP 通告被拦抓包看 112 协议、查防火墙VIP 漂移后流量不通免费 ARP 未生效检查交换机 ARP 表、抓包看 GARP备机 HAProxy 起不来未开 nonlocal_bind检查 sysctl 参数切换后频繁来回漂健康检查过于敏感调大 fall、加 nopreempt后端节点被误摘健康检查 URL 不对确认 /health 返回 2005.2 切换后连接中断时间过长有人反馈切换时用户掉线好几秒体验很差。这里要区分两个层面VIP 漂移本身是秒级的但已经建立的 TCP 连接在切换后必然中断因为连接状态在旧 Master 上。要减少影响可以在 HAProxy 上配置较短的timeout client和timeout server让僵死连接尽快释放应用层则要做好重试和幂等设计让客户端在连接断开后能自动重连。另一个容易被忽视的点是advert_int。默认 1 秒意味着最坏情况下要等 3 秒左右3 倍通告间隔才判定主机失联。想更快可以调小但太小会在网络轻微抖动时误判。我的经验值是 1 秒比较稳妥追求极致可以到 0.5 秒再小就不建议了。5.3 后端健康检查的实战心得健康检查的 URL 一定要专门设计不要图省事直接检查首页。首页可能依赖数据库、缓存等一堆下游任何一个抖动都会让首页返回 500导致健康的后端被误摘。正确的做法是提供一个轻量的/health接口只检查应用进程本身是否正常不牵扯下游依赖。这样健康检查反映的是这个节点能不能接流量而不是整个链路是否完美。还有一点rise值不要设得太小。后端刚恢复时可能还在预热立刻放流量进去容易把它再次压垮。设成 2 到 3给它一点缓冲时间整体更稳。6. 生产环境加固与后续演进6.1 日志与监控不能省HAProxy 的日志默认走 syslog要确保 rsyslog 配置了接收 local2 设施的日志否则你在journalctl里什么都看不到。日志里能看到每个请求转发到了哪个后端、响应时间多少、有没有后端被摘除这些是排查问题的第一手资料。统计页面stats也要开配上认证日常巡检时一眼就能看出后端健康状态和流量分布。监控层面建议把 HAProxy 的 stats socket 数据采集出来重点盯几个指标当前活跃连接数、后端节点的健康状态、请求错误率、队列积压。Keepalived 这边则要监控 VIP 当前在哪个节点上一旦发生漂移立刻告警——漂移本身不是坏事但频繁漂移说明有隐患。6.2 配置管理与变更流程主备两台机器的配置必须保持一致否则切换后行为不一致问题极难排查。建议把 HAProxy 和 Keepalived 的配置文件纳入版本管理变更时先改备机、验证、再改主机或者用配置管理工具统一推送。改完配置一定要haproxy -c -f做语法检查Keepalived 也要确认配置能被正确解析别等重启时才发现写错了。提示HAProxy 支持热加载systemctl reload haproxy会启动新进程接管监听 socket旧进程处理完存量连接后退出不会中断服务。但 Keepalived 的配置变更通常需要 restart重启瞬间 VIP 可能短暂漂移尽量在低峰期操作。6.3 从主备到更复杂形态的演进当业务量增长到单台 HAProxy 吃力时可以考虑几个方向。一是把 HAProxy 升级为多实例加多 VIP用 DNS 轮询或上层再做一层分发二是引入 ECMP 让多台负载均衡器同时工作这需要网络设备配合三是把部分七层逻辑下沉到服务网格让负载均衡层更纯粹。但这些都是后话主备这套方案在相当长的时间内都能扛住大多数业务不要为了架构而架构。我个人在实际操作中的体会是高可用集群的价值不在于平时跑得多顺而在于出事那一刻能不能真的顶上去。所以配置完一定要反复演练切换把各种故障场景都模拟一遍——停进程、关机、断网、拔线每种情况都测过心里才有底。最后再分享一个小技巧给 VIP 配一个独立的、容易记忆的地址并在文档里写清楚当前 Master 是哪台、怎么手动切换、切换后怎么验证这些看似琐碎的记录在凌晨三点被告警叫醒的时候能救命。