服务熔断这个坑,我们填了三次

上周给一家客户的内部问答系统做交付,最狼狈的不是模型答错,而是熔断器把整个服务切崩了。三次。三次都是同一个配置,三次都怪我没想到。

专属插画
服务熔断这个坑,我们填了三次

服务熔断这个坑,我们填了三次

上周给一家客户的内部问答系统做交付,最狼狈的不是模型答错,而是熔断器把整个服务切崩了。三次。三次都是同一个配置,三次都怪我没想到。

事情是这样的:客户的问答走我们的一层代理,代理后面接大模型 API,超时设 30 秒,错误率超过 30% 就熔断,熔断后直接返回兜底文案。听起来挺稳,对吧?

第一次翻车:模型有一次生成慢,35 秒才出结果,代理记成超时。连续几个慢请求把错误率推过阈值,熔断触发,后面所有问题都返回"服务暂时不可用"。其实模型只是慢,不是挂了。

第二次翻车是修完超时之后。我们把超时放宽到 90 秒,结果熔断半开时只放行一个试探请求,这个请求又碰上慢生成,再次失败,又回到熔断。半开状态变成了一个放大器:它不生产错误,但会把一个偶发慢请求放大成全局故障。

第三次最隐蔽。我们改了策略:半开时放行三个试探请求。上线当天流量正好低,三个请求全成功,熔断"恢复"了。可真实问题是间歇性的——恢复后流量上来,问题复现,又熔断。客户那边看到的是服务正常了又抽风,比一直报障更让他们没安全感。

最后真正修好,靠的不是把熔断参数调得更精巧,而是拆掉了一层伪需求:客服场景根本不需要硬熔断。我们改成三件事:

一是把超时和熔断解耦。慢请求不再计入错误率,单独进一个限流队列,超过队列长度才排队拒绝,返回"稍后重试"而不是"服务不可用"。客户能分辨"排队"和"故障",这两个词对信任的影响完全不同。

二是熔断只保护真正的依赖故障:连接拒绝、5xx、网关错误。生成慢不算。这个改完之后,熔断从一周触发八次变成两个月没触发过。

三是加了熔断状态可见性。后台能看到当前是关闭、打开还是半开,半开时放行几个、成功几个。有了这个,第三次那种"看着好了其实没好"的故障,我们当天就定位了,不用等客户投诉。

这里多说一个容易被忽略的点:兜底文案本身也是设计的一部分。我们原来的兜底是"服务暂时不可用,请稍后再试",改完之后分成了两种:排队场景返回"当前咨询较多,约 1 分钟后回复你",真正故障才返回"服务异常,我们已收到告警"。上线后客户投诉里"你们是不是挂了"这种问句明显变少了。文字不是装饰,它是故障时刻的最后一道防线:用户失去回答的时候,接住他们的是这段话,不是模型。

复盘下来,我的体会是:熔断是个好的保护机制,但它保护的是依赖,不是业务。把"业务上的一次延迟"交给熔断去裁决,它就会在你最没防备的时候把整个入口关死。交付现场判断一个保护机制设计得好不好,就看一条:故障时用户看到的是"我在排队"还是"你们挂了"。前者留得住人,后者留不住。

留言区

欢迎分享你的想法!

发表留言

0/500

加载留言中…