1. 这套组合拳到底在防什么:先说清每一层承担的风险
业务量一旦上来,最怕的不是代码出 bug,而是值班半夜被叫醒——先是 Tomcat 服务挂了,然后发现负载均衡节点也断了,数据库前一条慢 SQL 就把连接池打满,监控面板还是黑的。几年前我接过一个内部项目,高峰期一千多并发就能把单台 Tomcat 压死在 90%,于是决定把整套架构从单点往高可用方向改造。改造方案就是今天要说的这套:HAProxy 做入口负载均衡,Keepalived 负责 VIP 漂移,后端 MariaDB 和 Tomcat 承担业务,Prometheus 抓指标、Grafana 出面板。
1.1 组件各自解决什么问题
很多人第一次看这套架构会觉得组件太多、很重,其实拆开来看,每一层都在处理一个真实存在的故障点:
- Keepalived:解决“入口 IP 挂了怎么办”。它通过 VRRP 协议让两台负载均衡器共享一个虚拟 IP,主节点宕机后虚拟 IP 会自动漂移到备用节点,客户端请求的地址不用改。
- HAProxy:解决“请求往哪台应用服务器转发”。它负责把到达入口的流量按一定调度策略分发到多台 Tomcat,同时做健康检查,发现某台 Tomcat 异常就自动摘除,恢复后再加回集群。
- MariaDB:提供统一的数据存储。多台 Tomcat 连接同一个数据库服务,避免应用层各自持有一份本地数据导致不一致。
- Prometheus + Grafana:解决“系统到底是不是真的高可用”。高可用不是配置完就算数,而是要让核心指标持续可见,进程挂了、节点失联、连接数异常都要能第一时间发现。
组件之间的流量路径大概是:用户访问 VIP 地址,请求先经 HAProxy 主节点,再转发到后端某台 Tomcat,Tomcat 执行业务逻辑后访问 MariaDB。Prometheus 从所有节点采集操作系统、中间件和数据库指标,Grafana 把这些指标以面板形式展示出来。
1.2 这套方案更适合应对哪些故障
我在实际规划时会先列一个故障矩阵,明确这套架构能覆盖哪些问题、不能覆盖哪些问题:
| 故障类型 | 这套架构的应对方式 | 恢复预期 |
|---|---|---|
| HAProxy 主节点宕机 | Keepalived 检测到进程或节点异常,VIP 漂移到备节点 | 2-5 秒 |
| 某台 Tomcat 崩溃或假死 | HAProxy 健康检查失败后自动摘除该节点 | 6-10 秒内摘除 |
| 后端 Tomcat 全部正常但数据库异常 | MariaDB 所在的单点问题仍存在,需要额外数据库高可用方案 | 不在本方案内 |
| 应用数据容量增长、慢查询增多 | 需配合 MySQL 慢查询监控、连接池调优解决 | 监控发现后再动作 |
| Prometheus 所在节点宕机 | 采集中断,不影响业务流量,但建议监控节点也做冗余 | 不影响业务 |
从这张表能看出来,HAProxy 和 Keepalived 承担的是接入层故障转移,Tomcat 集群解决应用层冗余,监控体系让故障能被动发现。整套方案适合中小规模 Web 应用、内部管理系统和有一定 SLA 要求的公共业务平台;如果数据库也是核心瓶颈,那还需要再叠加数据库主从或集群方案。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 动手前先理顺概念:Keepalived 和 HAProxy 的高可用根本不在一个层面
网上有一个高频问题:HAProxy 和 Keepalived 有什么区别?甚至有人误以为两者都是负载均衡器,随便选一个就行。我在给团队讲架构时经常会打个比方:Keepalived 管的是“这个大门永远能用同一个门牌号找到”,HAProxy 管的是“进门之后把客户分给哪个柜台”。职责不一样,但缺一不可。
2.1 VRRP 做的是故障转移,不是流量分担
Keepalived 的底层是 VRRP(虚拟路由冗余协议)。两台服务器会组成一个虚拟路由器组,对外暴露同一个虚拟 IP。正常情况下虚拟 IP 绑定在主节点上,主节点每隔 1 秒(可配置)向备节点发送 VRRP 心跳报文;备节点一旦连续几个周期没有收到心跳,就认为主节点有问题,立即在自己的网卡上绑定这个虚拟 IP,继续对外提供服务。
这个动作就是常见的“VIP 漂移”。用户请求的 IP 始终是那个虚拟 IP,无论背后是主还是备,对客户端都完全透明。
2.2 HAProxy 是应用流量的分发器
HAProxy 运行在四层或七层,支持 TCP 和 HTTP 转发。同样是两台 HAProxy 节点,当 Keepalived 把 VIP 漂移到备节点后,备节点上的 HAProxy 必须已经提前启动、配置正确,并且能够正常连接后端 Tomcat。否则 VIP 虽然漂移过去了,请求还是进不来。
我给多个项目做过排查,最常见的翻车场景是:Keepalived 切换成功了,但备节点的 HAProxy 服务没有随系统开机自启,或者配置里还指向了旧的后端 IP。VIP 漂移后用户大量报错,这时候去看 VRRP 日志却一切正常。高可用的核心不是 IP 能漂,而是漂过去之后整条链路都是通的。
2.3 为什么两个负载均衡节点之间不需要做数据同步
HAProxy 本身是纯转发层,没有业务状态,配置只有一份文件,所以两台 LB 节点各放一份相同配置即可。Keepalived 的配置也是各写一份,只需要保证虚拟路由 ID、鉴权密码、VIP 等关键字段一致。
这里有一个经常会踩的坑:修改 HAProxy 配置后只在一台节点上执行了 systemctl reload haproxy,备节点还是旧配置。下次故障切换时备节点带着旧配置上线,可能把新加的后端全落在错误网络里。所以我一律要求改配置必须两台同步、两台 reload,并且用 haproxy -c -f /etc/haproxy/haproxy.cfg 先做配置校验。
3. MariaDB 与 Tomcat 部署前必须处理好的三件事
很多人一上来就配 Keepalived 和 HAProxy,却忽略后端节点的初始化。等集群搭好之后才发现,Tomcat 访问数据库失败、MariaDB 只监听了 127.0.0.1、应用没有任何可探测的健康检查路径。这些基础问题不处理,上层高可用做得再漂亮也是空中楼阁。
3.1 让 MariaDB 先走出 127.0.0.1 的默认坑
MariaDB 安装完成之后,默认监听地址通常是 127.0.0.1,只允许本机访问。如果你在多台 Tomcat 上部署同一个应用,这些 Tomcat 要访问数据库,就必须把监听地址改到对外网卡。很多人搜过“ubuntu 让 mariadb 不绑定 127.0.0.1”,问题基本都出在配置文件里的 bind-address。
在 MariaDB 配置文件 /etc/mysql/mariadb.conf.d/50-server.cnf 的 [mysqld] 段里,默认会有一行:
code复制bind-address = 127.0.0.1
将其改为:
code复制bind-address = 0.0.0.0
这里 0.0.0.0 表示监听本机所有 IP 地址。如果服务器上存在多网卡、出于安全考虑只想对外提供数据库服务,也可以写成具体的业务网卡 IP,比如 bind-address = 10.0.1.130。改完之后重启 MariaDB:
code复制systemctl restart mariadb
然后使用 ss -lntp | grep 3306 确认监听表现在是 0.0.0.0:3306 或指定 IP,而不是 127.0.0.1:3306。
注意:改完监听地址后防火墙也要同步放开 3306 端口。如果系统里开了 ufw,需要执行 `ufw allow from 10.0.1.0
