去年双11的凌晨两点,我接到了老周的电话。
他负责的那家做户外装备的电商平台,本来预估当天峰值是平时的8倍,结果提前半小时就冲破了预估线,整个商品详情页直接挂死,技术部十几个人对着监控面板满头汗,连回滚都忘了点。
问题出在哪?
其实翻监控日志的时候一眼就能看到:三台商品服务节点挂了两台,剩下的那台被请求堵得CPU直接冲到100%,而导致节点接连挂掉的原因,是下游的库存服务因为数据库锁表超时,所有卡在等待库存响应的请求,慢慢把服务的线程池占满了。更可笑的是,占线程最多的根本不是用户关心的价格、库存查询,而是页面下方加载的“猜你喜欢”推荐接口——大促当天谁会在抢冲锋衣的时候刷推荐啊?
别把高可用当成堆服务器的游戏
说真的,我见过太多团队,一提到高可用,第一反应就是扩容、加机器,算下来云服务器成本涨了三倍,结果故障来的时候还是一样崩。
大家对高可用的误解太深了。你买再多的服务器,要是所有节点都绑在同一条没有容错的依赖链上,只要一个下游组件出问题,所有节点都会跟着一起死,跟你有几台机器根本没关系。老周他们当时就是典型的反面教材:为了扛大促,提前一周买了两倍的服务器配额,结果连最基础的服务熔断规则都没配,线程池被非核心请求占满的时候,连最核心的下单请求都挤不进来。

真正的高可用第一步,从来不是加机器,是核心链路的隔离。你得把用户掏钱的路径——浏览商品、查库存、下单、支付——和那些无关紧要的功能——推荐、评价加载、营销弹窗——从线程池、资源配额上彻底拆开。哪怕推荐服务整个挂了,也绝对不能影响用户点“提交订单”的按钮。
很多人觉得拆链路太麻烦,要改一堆代码。其实哪有那么复杂?最基础的操作,就是给不同优先级的接口配独立的线程池,给非核心接口设独立的超时时间,别让非核心的请求把核心资源耗光。
成本账要算到每个依赖节点上
不过话说回来,谁的预算都不是大风刮来的。
很多团队一提高可用,就拍脑袋要做三地五中心,要全链路跨可用区部署,算下来一年几百万的基础设施成本,最后用得上的场景可能一年都遇不到一次。老周他们一开始也想这么干,三个可用区各放两台核心节点,算下来一个月要多花12万,我当时直接给他们算了笔账:他们全年的大促满打满算也就四次,每次峰值持续不超过6个小时,为了这几个小时的峰值,平摊一年的成本完全没必要。
最后我们调整了方案:只给下单、支付这两个最核心的链路做跨可用区部署,哪怕某个可用区整个断网,用户的下单流程也不会受影响;剩下的商品浏览、推荐、评价这些非核心服务,就放在单可用区跑,真出问题就切静态兜底页面。算下来最后每个月只多花3万多,不到原来预算的三分之一。

这里的关键,是你得算清楚每个节点的容错成本。不是所有的组件都值得你付出跨区部署的代价——比如你那个内部用的报表系统,就算挂两个小时,对用户的交易也没有任何影响,根本没必要给它配高可用的冗余资源。反过来,要是你的支付接口挂了一秒钟,可能就会丢几万块的订单,那这个节点哪怕花再多钱做冗余,都是值得的。
老周后来跟我说,之前他们做的降级开关,就是个写在文档里的摆设,从来没真的触发过。那次我们把开关改成了自动触发:只要服务CPU超过70%,就自动把非核心的推荐、评价接口切到静态兜底数据,根本不需要人盯着点按钮。双11当天CPU真的冲到72%的时候,开关自动切了,整个核心链路一点没晃,老周后来请我喝了三瓶冰啤酒,说终于不用在凌晨接告警电话了。
别等故障来了才想起演练
这是我见过最普遍的误区。
很多团队的高可用预案写得花里胡哨,什么故障分级、响应流程、责任人安排,整整齐齐放了几十页在共享文档里,结果从来没真的跑过一次。真等故障来的时候,要么发现降级开关的权限根本没开,值班的人改不了配置;要么发现告警消息被群消息刷上去了,根本没人看到;更夸张的是,有团队演练的时候才发现,他们的回滚包是三个月前的旧版本,回滚完直接把核心功能弄没了。
演练不是走形式。
你得真的把某个节点打挂,看看整个系统能不能按预案走,看看告警能不能真的发到值班人的手机上,看看值班人看到告警之后,知不知道第一步该点哪个按钮。我接触过的做得好的团队,每个月都会随机抽一个业务组件,在生产环境故意把它打挂,从故障发生到完全恢复,全程掐表算时间。哪个环节慢就补哪个:比如从故障发生到监控发现花了30秒,就把告警阈值再往前调;比如从发现问题到定位根因花了10分钟,就把链路追踪的日志颗粒度再做细点。
老周他们后来把监控的告警阈值从原来的CPU90%降到了70%。为啥?因为从70%到90%的过程,就是你做预案的黄金时间,等冲到90%再动手,服务已经被打满了,再怎么操作都晚了。
其实高可用从来不是什么需要写几十页PPT的高大上架构设计。
它就是你在日常迭代里,多考虑一步“这个组件挂了怎么办”;多算一笔不花冤枉钱的成本账;多跑几次不走过场的故障演练。没有那么多玄乎的概念,说白了就是别让用户在最关键的操作环节,碰到打不开的页面、转不停的加载圈。