简介:本文复盘某AI对话平台持续十余小时的聊天服务故障:受影响的并非模型本身,而是网关、鉴权、会话等接入层组件。文章拆解连锁失效的四步过程,辨析模型过载与接入层故障的差异特征,并给出容量规划、无状态改造、限流熔断降级、多活容灾等可落地的加固方案,帮助技术团队把事故转化为下一代模型发布前的架构升级契机。
事情的经过并不复杂。某AI对话平台在一天晚间出现服务异常,从官方状态页的时间线看,大致有四个关键节点:
整个故障窗口超过十个小时。这里有两个非常值得玩味的信号。
信号一:受影响组件不是笼统的“全站”,而是被精确标记的Web Chat Service(网页/APP聊天服务)。 这说明问题大概率不在模型推理层——如果推理集群出问题,API、模型服务通常会被一并标记。而这次被点名的,恰恰是承接用户访问的前端接入层、会话层和调度层。
信号二:这不是计划内维护,而是一次“恢复后复发”的连续性故障。 修好一次、再坏一次,往往意味着根因没有被真正消除:要么是底层依赖持续处于亚健康状态,要么是服务刚恢复时积压流量瞬时涌入,把刚缓过来的服务再次打挂。
需要补充的背景是:自这家平台爆红以来,网页、API、登录注册等入口已多次出现中断或性能异常。在模型能力持续领跑的同时,服务稳定性正在成为它最容易被放大的短板。
很多用户(甚至不少从业者)会把AI平台简单理解为“模型加一个对话框”。但从工程视角看,用户从点开网页到看到回答,中间要穿过一条完整的链路:
所谓Web Chat Service,指的正是中间这段“从点开到聊天”的全部工程环节,范围通常覆盖:入口网关、鉴权、会话保持、上下文读写、长连接管理、区域调度和限流策略。任何一环失守,用户都碰不到模型。
一个更形象的比喻:如果把模型比作厨子,那么Web Chat Service就是传菜员。这次事故里,厨房一切照常运作——API服务没有受到系统性影响,推理集群也在正常出菜——但传菜环节瘫痪了,堂食客人依然一桌菜都上不了。用户端的直观表现就是“已读不回”:页面能打开、请求发出去了,内容就是刷不出来。
对稳定性工程来说,快速定位“故障在哪一层”是第一优先级,因为模型资源紧张和接入层故障的现象、处置完全不同:
| 对比维度 | 模型推理资源紧张 | 接入层(Web Chat Service)故障 |
|---|---|---|
| 典型表现 | 响应变慢、排队时间拉长、答案生成中断、高峰期统一“繁忙”提示 | 登录失败、页面一直转圈、会话无法建立、刷新后掉线、恢复后再次中断 |
| 用户感知 | 进得了页面,等得久、答不全 | 进不来,或频繁掉线 |
| 故障位置 | 推理算力与并发额度不足 | 网关、鉴权、会话、缓存等组件过载或异常 |
| 处置思路 | 扩推理资源、排队削峰、异步生成 | 架构加固、容量冗余、故障切换与演练 |
对照这次事故的公开信息,用户看到的是“转圈、掉线、刷新失效”这一类入口故障特征,而非统一的“繁忙”提示,因此受影响重点更接近入口服务与会话服务。当然,官方并未披露更底层的根因,外部无法断言具体是CDN、WAF、缓存中间件、数据库还是网关出现问题。但对读者来说更重要的是:接入层故障的识别方法与加固思路是通用的,不依赖某一次事故的内部细节。
这类事故的发生与恶化过程高度相似,可以拆成四步。
第一步:洪峰先冲击前置服务。 在某个时间窗口里,新会话创建、老会话恢复、页面刷新和登录校验一起增多。注意:最先被顶到高位的不是模型,而是负责分流和验明身份的前置服务——网关与鉴权天然站在流量最前面。
第二步:会话层读写放大。 请求穿过鉴权后进入会话层,需要读取用户资料、会话历史、上下文索引和限流状态。此时共享缓存与数据库的读写压力迅速升高,一次页面刷新的背后可能是成倍的会话读写。
第三步:连接池占满,慢请求变成排队请求。 少量慢请求占住连接不放,连接池被迅速占满,后续的快请求也拿不到资源,时延曲线整体抬升,系统从“局部慢”恶化成“整体堵”。
第四步:重试风暴与二次打挂。 客户端感知到超时后,用户会刷新、重连、重试,流量被成倍放大并压向已经过载的服务。更麻烦的是,服务刚一恢复,积压请求与重试流量瞬时涌入,把刚缓过来的服务再次打挂——这恰好解释了“修复、复发、再修复”的循环,也解释了为什么一次接入层故障能持续十个小时。
其中第四步最值得治理,示意代码如下:
# 伪代码:带指数退避与随机抖动的重试,避免重试风暴def call_with_retry(request, max_retries=3):for attempt in range(max_retries):try:return gateway.invoke(request)except (Timeout, ServiceBusy):if attempt == max_retries - 1:raisebase_delay = min(2 ** attempt * 300, 5000) # 指数退避,上限5秒sleep(base_delay + random_jitter(0, 300)) # 抖动:打散重试时间
要点有两个:一是指数退避拉大重试间隔,给下游喘息时间;二是加入随机抖动,避免所有客户端在同一时刻集体重试,把“洪峰”变成“整齐的二次洪峰”。
回到一个反直觉的观点:在下一代旗舰模型发布、流量冲击波到来之前暴露短板,反而是好事——前提是团队真正做整改。以下清单可以直接对照执行。
1. 容量规划与弹性伸缩。 以“历史峰值×冗余系数”做容量预算,接入层与会话层必须独立于推理层扩缩容;宁可冗余,不可贴地飞行。新模型发布、热点引流前,提前压测并预热扩容。
2. 接入层无状态化。 把会话状态外置到分布式缓存与持久化存储,让网关和接入节点随时可替换、可水平扩展。无状态是弹性与容灾的前提——节点有状态,故障切换就只能靠“慢慢修”。
3. 依赖隔离。 鉴权、会话、上下文、限流各自独立部署,拥有独立的连接池与熔断阈值,防止一个慢依赖拖垮整条链路。
4. 限流、熔断、降级三件套。 入口限流是保护后端的第一道闸;熔断器用于在依赖异常时快速失败、释放资源;降级则是“弃车保帅”——历史会话列表、个性化推荐等非核心能力可以降级甚至暂时关闭,核心对话链路必须保活。示意配置:
# 示意配置:入口限流 + 会话依赖熔断 + 非核心功能降级gateway:rate_limit:per_user_qps: 5 # 单用户限流,防止单点刷量global_qps: 50000 # 全局限流,保护后端容量retry_policy:max_retries: 3backoff: exponential # 指数退避jitter: true # 随机抖动circuit_breaker:session_store:error_rate_threshold: 0.5 # 错误率超50%即熔断recovery_probe_interval: 30s # 半开探测,逐步放量恢复degradation:history_list: static_cache # 会话历史降级为静态缓存recommendation: disabled # 推荐类功能直接关闭
5. 重试治理。 服务端统一下发重试预算,限制客户端重试次数与并发,配合退避与抖动,把重试风暴扼杀在客户端一侧。
6. 多可用区/多地域容灾。 接入层至少双活部署,健康检查自动摘除故障节点,故障切换以秒计而不是以小时计。这次事故中“恢复—复发”的循环,本质上就是缺少一个能整体接管的备用平面。
7. 观测与告警体系。 围绕时延、流量、错误率、饱和度四大黄金指标建设监控,明确SLO与错误预算,让稳定性投入有数据可依,而不是每次都靠用户投诉倒逼。
8. 组织与预案。 完善值班响应流程、状态页透明通报机制,故障复盘对事不对人;再定期用混沌工程演练“网关过载、缓存故障、依赖变慢”等场景,让预案停留在肌肉记忆里,而不是文档里。
在落地层面,借助成熟的云基础设施会比从零自建更稳妥:用容器平台实现接入层弹性伸缩,用消息队列做削峰填谷,用对象存储沉淀会话与日志数据,用云上的日志服务与监控告警快速搭建观测体系(以百度智能云为代表的厂商均提供这些通用产品类目)。团队的重心应放在业务架构设计与演练上,而不是重复造基础轮子。
对任何一款用户量指数级增长的AI产品来说,模型能力决定天花板,接入层稳定性决定地板——用户不会因为模型评测分数高,而原谅十个小时打不开的对话框。
十小时的故障并不可怕,可怕的是同类故障反复出现,而架构层面始终没有升级。正确的姿势是:把每一次崩溃都当成下一代旗舰模型发布前的一次免费压力测试,按清单逐项整改——或者多备容量,或者多配运维,或者重构会话层,总之让接入层比想象中更牢固。当下一次流量冲击波真的到来时,决定平台口碑的,很可能不是模型跑分,而是那十个小时有没有变成十秒钟。