AI网关流式输出客户端限速与流控隔离落地

日期:2026-08-15

一、项目背景

我们网关的流式接口上线后,被几个客户端疯狂拉满带宽。这些客户端接了流式对话,但消费得慢,拿到一段数据不赶紧处理,连接就一直占着,把网关出口带宽打满。结果其他普通用户的流式响应卡成幻灯片,首字出来了后面半天不动。我们一开始以为是模型慢,查了半天才发现是出口被几个慢消费者堵死,模型那边早就吐完了,数据堵在网关到客户端的链路上。随着流式接口用量涨上来,这个问题从偶发变成了常态故障,不治理,流式体验就会整体崩掉,连正常用户都跟着遭殃。

二、落地场景

流控是建在 AI 网关的接入层和可观测之上的。我们按客户端加应用维度做了限速,每个客户端有独立的带宽配额,超过就限速而非断连,保证慢的不拖死快的。同时把流式出口按优先级分组,普通用户和重度客户端不在同一个带宽池,互不影响。慢消费者连接长时间不消费达到阈值,网关主动断连回收,避免半开连接堆积。整个限流对正常用户基本无感,只对真正滥用的客户端生效,普通用户侧的流式体验反而比治理前更稳。

三、关键技术挑战与解决思路

第一个难点是慢消费者拖垮整体。我们一开始想直接断连,结果误杀了一些网络抖动的正常用户,后来改成先限速再观察,持续不消费才断,误杀率下来了。第二个难点是带宽隔离与超卖,各组不能简单按比例切,重度组峰值会挤占,我们给普通用户组设了保底带宽,宁可重度组受限也不动保底。第三个难点是断连与重连状态,流式中断后客户端要能从断点续,我们让网关在断连前回传已发偏移,客户端拿偏移重连续传,不能让用户从头再来。第四个难点是限速值的设定,固定阈值要么太松没用要么太紧误伤,我们改成按客户端历史消费速率动态调。我后来觉得,限速值别定死,动态调比固定阈值聪明,固定值那次误杀正常用户就是教训。

还有一块是限速值的运营,动态调参需要历史数据积累,我们上线头两周先用保守固定值兜底,等消费速率画像出来再切动态,避免一开始就把正常用户限伤。这个过渡期我们盯了很久监控,才敢放开自动调,毕竟误伤比慢一点更糟,宁可保守。

另外,限速的计量也要准,客户端实际消费速率要靠网关侧真实统计,不能信客户端自报,我们统一在网关出向统计字节数,避免客户端虚报绕过限速。早期信了客户端心跳,被钻了空子,后来改成网关侧硬统计,限速才真正生效,这条也算交了学费。流控的每一环都要假设对端不可信,否则规则再漂亮也会被绕过,这是安全上的老道理。

四、效果数据

治理后,网关出口带宽峰值下降约四成,普通用户流式卡顿率从约一成二降到约百分之一。慢消费者断连数日均约三百,其中误杀(正常网络抖动)占比从早期的约两成降到约百分之三。连接复用率提升到约八成五,半开连接占比从约一成降到约百分之一。一个季度因流控问题引发的客户投诉下降约七成,运维半夜被带宽告警叫醒的次数从每周几次降到几乎为零。普通用户组保底带宽几乎没被触发过,说明资源主要被重度客户端占着,隔离方向是对的。

带宽隔离上线后,大促期间普通用户侧的流式首字延迟几乎没波动,重度组的突发被牢牢关在保底带宽之外,这次大促运维第一次没被带宽告警叫醒。

五、可复用经验总结

流式接口不治慢消费者,迟早把网关出口堵死,这是和同步接口完全不同的坑,同步接口慢了顶多占个线程,流式慢了占的是带宽,影响面大得多。限速优于硬断连,先限再断能把误杀压到最低,我们吃过误杀正常用户的亏才改过来,现在断连前一定先看是不是真不消费。普通用户组的保底带宽一定要留,超卖省的那点资源,换来一次卡顿投诉就全赔进去,这笔账不划算。说到底,流控的本质是保护大多数人的体验,不是惩罚少数人,这个优先级别搞反了,系统就会越治越糟,正常用户反而最先受伤。

我们吃过误杀正常用户的亏,所以现在断连前一定先看是不是真不消费,限速优先于断连。保底带宽那次要不是留着,一次大促的突发就把普通用户拖进去了。流控的尺度,是护大多数人还是罚少数人,这个选择我们想得很清楚,也栽过跟头,不会再摇摆。

流控上线后我们才明白,体验是设计出来的不是限出来的,把大多数人护住,系统才算真的稳,这一点我们是用误杀的代价换来的。

案例片段(已脱敏): 客户端限速与流控分组配置:yaml stream_ratelimit:  per_client_bandwidth: dynamic     # 按历史消费速率动态  groups:    normal: { guarantee_bw: 20MBps }  # 普通用户保底    heavy:  { max_bw: 50MBps }  slow_consumer:    idle_threshold_s: 30    action: throttle_then_drop    resume_offset: true              # 断连前回传偏移流控事件日志节选:[2026-08-06 21:14] client=C_7782 group=heavy  消费速率 0.2MBps < 阈值, 限速生效  空闲 30s -> 断连, 回传 offset=18432  普通组带宽占用回落至保底内