你要做企业级高可用(HA)时,最容易踩的坑不是“技术不会”,而是顺序错了。
很多团队一上来就画双机热备、搞多活,结果:
- 业务还是有单点(比如文件上传、本地 session、单库)
- 监控和告警没做好,宕机了还得靠用户来报案
- 备份有了但没恢复演练,真出事时才发现备份是摆设
这篇不讲玄学,也不卖“完美架构”。我按一个更现实的目标来写:
让你用可回滚的方式,一步步把可用性做上去。
我见过不少“伪需求”:
- 其实业务允许半夜维护,但被“企业级”三个字吓到了
- 其实用户量不大,单机+备份+监控就够了
- 其实最大风险不是宕机,而是误操作删库、证书过期、硬盘写满
你可以用两个问题快速判断:
- 你能接受一次故障停多久?(RTO)
- 你能接受丢多少数据?(RPO)
如果你还没把 RTO/RPO 写进文档,别急着上 HA。
顺手提醒一句:做 HA 之前,先把“时间成本”算清楚,很多项目不是被服务器打垮,是被维护成本打垮。
我建议你把 HA 拆成四个等级,按等级交付。
这一步的目标是:
- 单机也能稳定跑
- 出事能定位
- 数据能恢复
最低配置三件套:
- 安全:SSH/防火墙/Fail2Ban
- 备份:能自动备份 + 能恢复
- 监控:能知道服务挂了 + 磁盘满了 + 证书要过期
对应的“抄作业链接”:
如果你 L0 都没做完,就别急着谈 L2/L3。
你要做 HA,最先要解决的不是“加两台机器”,而是:
- 应用能不能水平扩展。
无状态化最常见的坑:
- session 存在本机内存(换一台就掉登录)
- 文件上传写本机磁盘(换一台就找不到文件)
- 定时任务跑在某一台(切换后重复执行或漏执行)
典型解法:
- session 放 Redis(或用无状态 JWT 但要控制风险)
- 文件放对象存储(S3/R2)或共享存储
- 定时任务用“唯一调度”机制(leader election / 单独的 job 节点)
到这一步,你至少要做到:
- 两台应用节点(App A / App B)
- 一个入口(LB)做健康检查和转发
最小可落地架构:
- Client → LB → App A / App B
- App → DB(先可以单库,但要有备份和恢复演练)
健康检查别做“端口通就算活”。最好是一个真正的 /healthz 接口:
- 检查进程活着
- 检查依赖(DB/Redis)是否可用(至少做浅检查)
你可以先用最朴素的配置把流量切走能力做出来。
下面是一个能跑的最小示例(你按自己端口改就行):
# /etc/haproxy/haproxy.cfg(示例)
frontend fe_http
bind :80
default_backend be_app
backend be_app
balance roundrobin
option httpchk GET /healthz
http-check expect status 200
server app_a 10.0.0.11:8080 check
server app_b 10.0.0.12:8080 check
验证思路很简单:
- 你把
app_a的服务停掉(或让/healthz返回 500) - 访问 LB,看请求是否自动落到
app_b
很多人做完 L2,以为自己 HA 了。
但 LB 本身如果是单机,那它就是新的单点。
常见做法是:
- 双 LB + VRRP(Keepalived)漂移 VIP
- 或者用云厂商的托管 LB(你少折腾,但要接受规则和费用)
这里最容易踩的坑叫 split-brain:
- 两个节点都以为自己是主
- 同一个 VIP 被“抢来抢去”
解决 split-brain 的关键不是“再加配置”,而是:
- 有明确的仲裁/优先级
- 有健康检查与隔离(fencing)策略
- 故障演练要覆盖“网络分区”这种场景(别只演练关机)
下面是一个常见写法(示例,只写核心结构)。
主节点(MASTER):
# /etc/keepalived/keepalived.conf(示例)
vrrp_script chk_haproxy {
script "pidof haproxy"
interval 2
fall 3
rise 2
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 110
advert_int 1
authentication {
auth_type PASS
auth_pass CHANGE_ME
}
virtual_ipaddress {
10.0.0.100/24
}
track_script {
chk_haproxy
}
}
从节点(BACKUP)把 state 改成 BACKUP,priority 调低(例如 100),其他保持一致。
你要验证的是两件事:
haproxy真挂了,VIP 会不会漂到另一台- 网络分区/脑裂场景下,VIP 会不会“来回跳”
在 VPS 自建场景,fencing 往往没法做到 100% 完美,但至少你要做到:
- 让“入口漂移”跟健康检查绑定
- 明确故障时谁有权成为 MASTER
- 把演练写进流程(别靠记忆)
数据库往往是 HA 最难、也最容易翻车的地方。
我给一个实用原则:
- 先做可恢复(备份+演练)
- 再做主从/读写分离
- 最后才考虑多主/分布式(除非你真的需要)
- 单主(Primary)
- 一台只读副本(Replica)
- 自动备份 + 定期恢复演练
- 监控“复制延迟/磁盘/连接数/慢查询”这类基础指标
你要问自己两个问题:
- 你的写入量到底有多大?
- 你能不能接受“短时间只读/只写”作为降级策略?
很多业务完全可以:
- 故障时先切只读
- 先把服务恢复
- 再慢慢修复一致性
比你追求“永不宕机”更现实。
你别指望故障当场临时讨论。
我建议你写一个最短可用的 Runbook(5 行也行):
- 发生故障时,谁是负责人(一个名字/一个群)
- 如何判断 Primary 是否真的挂了(不要只看 ping)
- 何时触发切换(满足什么条件)
- 切换后的回滚策略(新 Primary 出问题怎么办)
- 事故后如何补齐数据/修复一致性
这份 Runbook 写出来,你的“高可用”就已经比大多数团队强了。
高可用不是写在文档里,是练出来的。
我建议你至少做这 6 个演练(按顺序):
- 杀掉应用进程:LB 能不能把流量切走
- 应用节点断网:健康检查能不能识别
- 数据库宕机:服务能不能降级(明确返回错误/只读)
- 磁盘写满:监控能不能提前告警
- 证书过期:能不能提前 7 天告警
- “误操作”:删表/删文件能不能按备份恢复
| 场景 | 触发方式 | 预期现象 | 实际现象 | RTO | 复盘/改进 |
|---|---|---|---|---|---|
| App A 挂掉 | kill / stop service | 自动切走 | |||
| LB 挂掉 | stop keepalived | VIP 漂移 | |||
| DB 挂掉 | stop db | 降级/只读 |
如果你要做网络层面的验证(丢包/抖动/绕路),可以用 mtr 一套流程跑清楚(出事时也更容易说服自己/说服同事):
我最后给一个不太“架构师”的建议:
- 先把 L0 做到“能恢复、能告警、能定位”
- 再做无状态化
- 然后两节点 + LB
- 最后才把入口/数据库做高可用
你每走一步,都要能回答一句话:
这一步做完,宕机时我能少慌多少?
能回答出来,你就在正确的路上。
