news 2026/9/23 3:41:01

AI接口高并发限流实战:从秒杀思维到LLM调用汇聚点闸门

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AI接口高并发限流实战:从秒杀思维到LLM调用汇聚点闸门

1. 从一个真实的线上事故说起

去年冬天,我负责的一个 AI 应用平台上线了智能问答功能,底层接的是某主流大模型 API。上线第三天,运营做了一波推广,流量瞬间涨了十几倍。按理说我们做了限流,Sentinel 规则配得明明白白,QPS 阈值卡在 200,理论上不该出事。结果呢?网关层确实稳如老狗,一个请求都没超,但后端服务集体雪崩,线程池打满,接口响应时间从 800ms 飙到 30 秒,最后整个问答功能不可用。

排查了一整夜,根因让我哭笑不得:我们把并发闸门挂错了地方

网关层的 QPS 限流只挡住了入口流量,但每个进来的请求在后端会触发多次 LLM 调用——有的做意图识别,有的做知识检索后的重排,有的做最终答案生成。一个用户请求平均触发 3 到 5 次 LLM 调用,200 QPS 的入口流量,实际打到 LLM 接口的并发是 600 到 1000。而 LLM 接口的并发承载能力,远没有我们想象的那么强。

这件事让我彻底想明白一个道理:AI 接口的高并发,和秒杀场景的高并发,根本是两码事。秒杀是"一瞬间大量请求抢同一资源",AI 接口是"单个请求在链路中被放大成多次调用"。限流策略如果照搬秒杀那套,必然翻车。

这篇文章,我就把这次事故的完整复盘、后来的改造方案、以及踩过的坑,原原本本讲清楚。如果你正在做 LLM 应用开发,或者负责 AI 平台的稳定性,这篇内容应该能帮你少走至少半年的弯路。

2. AI 接口并发和秒杀并发,到底差在哪

2.1 秒杀并发的本质:入口洪峰,资源争抢

秒杀场景的并发模型很单纯。十万个用户同时点"立即购买",请求全部打到入口,后端要做的核心事情只有一件:用最快的速度判断谁有资格,然后把绝大多数请求挡回去。库存就那么多,抢完即止。

这种场景下,限流的核心逻辑是"入口拦截"。你在网关层挂一个 Sentinel 流控规则,QPS 超过阈值直接快速失败,用户看到"活动太火爆",完事。后端服务的压力是可控的,因为被放行的请求数量是恒定的,每个请求的处理逻辑也是轻量的——查库存、扣减、下单,几百毫秒搞定。

秒杀系统的设计哲学是:把压力挡在门外,门内保持轻量

2.2 AI 接口的本质:单请求放大,链路耗时

AI 接口完全不是这个逻辑。一个用户问"帮我总结一下这份合同的风险点",后端链路可能是这样的:

  1. 先调一次 LLM 做意图识别,判断这是合同审查类请求
  2. 调向量数据库检索相关法条和模板,拿到 20 条候选
  3. 调一次 LLM 做重排,从 20 条里选出最相关的 5 条
  4. 把合同全文和 5 条参考拼成 prompt,调一次 LLM 生成最终答案
  5. 可能还要调一次 LLM 做答案合规性检查

一个用户请求,触发了 4 次 LLM 调用。如果入口 QPS 是 100,实际打到 LLM 接口的并发就是 400。而且每次 LLM 调用的耗时是秒级的,不是毫秒级。这意味着线程会被长时间占用,连接池、线程池的消耗速度远超秒杀场景。

更麻烦的是,LLM 接口本身有严格的并发限制。大多数云厂商的 API 默认并发配额是几十到几百,超过就返回 429。你入口限流做得再好,汇聚点没控住,照样把下游打挂。

2.3 一张表看清两种并发的差异

维度秒杀高并发AI 接口高并发
压力来源入口瞬时洪峰单请求链路放大
请求耗时毫秒级秒级到十秒级
资源占用短时 CPU/DB 争抢长时线程/连接占用
下游依赖库存服务、订单服务LLM API、向量库、重排服务
限流位置网关入口调用汇聚点
失败模式超卖、少卖429 限流、超时雪崩
核心矛盾抢同一资源调用次数放大

这张表是我在事故复盘会上画的,当时团队里做电商出身的老哥看完沉默了很久,说了一句:"我们一直用秒杀的脑子在做 AI 的限流,难怪出事。"

2.4 为什么"汇聚点"才是正确的闸门位置

所谓汇聚点,就是所有 LLM 调用最终都会经过的那个地方。不管你是意图识别、重排、生成还是合规检查,只要调 LLM,就必须走这个口子。

把并发闸门挂在这里,好处有三个:

第一,精准控制实际并发。你限制的是真正打到 LLM 接口的并发数,而不是入口的请求数。入口可以放 1000 QPS 进来,但汇聚点只允许 50 个并发同时在跑,剩下的排队或降级。

第二,保护下游不被击穿。LLM API 的并发配额是硬约束,汇聚点限流能确保你永远不会超过这个配额,避免 429 错误引发的连锁反应。

第三,便于统一治理。所有 LLM 调用的超时、重试、降级、熔断策略都在汇聚点统一配置,不用在每个业务模块里重复写。

提示:汇聚点不一定是一个物理服务,也可以是一个统一的 SDK 封装层。关键是要保证所有 LLM 调用都经过它,不能有绕过的情况。

3. 并发闸门的技术选型与核心原理

3.1 为什么选 Sentinel 而不是其他方案

限流工具市面上不少,Guava RateLimiter、Resilience4j、Sentinel 都能做。我最终选 Sentinel,原因很实际:

第一,支持热点参数限流。AI 场景里,不同用户的请求优先级不一样,VIP 用户和普通用户的 LLM 调用配额应该区分开。Sentinel 的热点参数限流可以直接按用户 ID 做差异化控制,这是 Guava 做不到的。

第二,流控模式丰富。直接拒绝、Warm Up、匀速排队三种模式,AI 场景下匀速排队特别有用——LLM 调用本来就慢,与其快速失败让用户重试,不如排队等一会儿,用户体验反而更好。

第三,熔断降级一体化。LLM 接口不稳定是常态,Sentinel 的熔断器可以在下游错误率升高时自动切断,避免雪崩。这个能力在秒杀场景里用得少,但在 AI 场景里是刚需。

第四,规则动态推送。通过 Nacos 或 Apollo 配置中心,可以实时调整限流规则,不用重启服务。LLM 接口的配额经常变,动态调整能力很重要。

3.2 并发线程数限流 vs QPS 限流

这是选型时最容易搞混的地方。Sentinel 支持两种流控指标:QPS 和并发线程数。

秒杀场景用 QPS 就够了,因为请求处理快,QPS 和并发数基本成正比。但 AI 场景必须用并发线程数限流,原因很简单:LLM 调用耗时波动极大,同样的 QPS,耗时 1 秒时并发是 10,耗时 10 秒时并发就是 100。用 QPS 限流,你根本不知道实际并发是多少。

并发线程数限流的逻辑是:当前正在处理中的请求数超过阈值,新请求就排队或拒绝。这个指标直接反映了对下游的实际压力,是 AI 场景下唯一靠谱的限流维度。

我实测下来的经验值:如果 LLM API 的并发配额是 100,汇聚点的并发线程数阈值设成 80 比较稳妥,留 20% 的缓冲应对突发。

3.3 匀速排队模式在 AI 场景的妙用

Sentinel 的匀速排队(Rate Limiter)模式,是 AI 场景下我最推荐的流控方式。

它的原理是:请求不直接拒绝,而是以均匀的速度放行。比如你设 QPS 为 10,那么每 100ms 放行一个请求,超出的请求排队等待,等待超过超时时间才拒绝。

为什么适合 AI 场景?因为 LLM 调用本来就是秒级的,用户对延迟的容忍度相对高。与其快速失败让用户手动重试,不如让请求在队列里等几秒,成功率反而更高。

配置上有个关键参数:超时时间。设太短,排队没意义;设太长,用户等不及。我的经验是设成 LLM 平均耗时的 2 到 3 倍。比如 LLM 平均 3 秒返回,超时设 8 秒左右比较合适。

3.4 熔断降级策略的配置要点

LLM 接口的稳定性是玄学,有时候好好的,突然就开始超时。熔断器的作用是在下游出问题时快速切断,避免线程被大量占用。

Sentinel 的熔断策略有三种:慢调用比例、异常比例、异常数。AI 场景我推荐用慢调用比例

配置逻辑是:统计窗口内,如果慢调用(超过设定 RT 阈值的调用)比例超过阈值,就触发熔断。比如设 RT 阈值为 5 秒,慢调用比例阈值为 0.5,统计窗口 10 秒。意思是 10 秒内有超过一半的调用耗时超过 5 秒,就熔断。

熔断后的降级策略,我一般做两级:第一级返回缓存的历史答案(如果有),第二级返回友好的提示语,引导用户稍后重试。绝对不能让用户看到 500 错误。

4. 汇聚点闸门的完整落地实现

4.1 整体架构设计

改造后的架构分三层:

接入层:Spring Cloud Gateway 做入口路由和基础限流,这里保留 QPS 限流,但阈值设得比较宽松,主要防 DDoS 级别的攻击。

业务层:各个业务服务正常处理逻辑,但所有 LLM 调用必须通过统一的 LLM Client SDK。

汇聚层:LLM Client SDK 内部集成 Sentinel,在真正发起 HTTP 请求前做并发线程数限流和熔断判断。

关键设计原则:SDK 是唯一出口。业务代码不允许直接调 LLM API,必须走 SDK。这一点靠代码规范和 CI 检查双重保障——CI 里加了静态扫描,发现直接调用 LLM API 的代码直接构建失败。

4.2 LLM Client SDK 的核心代码

SDK 的核心逻辑不复杂,我贴一下关键部分:

public class LlmClient { private final SentinelResourceWrapper resourceWrapper; private final OkHttpClient httpClient; public LlmResponse call(LlmRequest request) { // 定义 Sentinel 资源,资源名统一为 llm_call Entry entry = null; try { entry = SphU.entry("llm_call", EntryType.OUT); // 真正发起 HTTP 请求 return doHttpCall(request); } catch (BlockException e) { // 被限流或熔断,走降级逻辑 return fallback(request, e); } catch (Exception e) { // 业务异常,记录并抛出 Tracer.traceEntry(e, entry); throw e; } finally { if (entry != null) { entry.exit(); } } } private LlmResponse fallback(LlmRequest request, BlockException e) { // 降级逻辑:先查缓存,没有再返回提示 LlmResponse cached = cache.get(request.getCacheKey()); if (cached != null) { return cached; } return LlmResponse.busy("当前请求较多,请稍后重试"); } }

这段代码的关键点:SphU.entry("llm_call")是 Sentinel 的入口,所有 LLM 调用共用同一个资源名,这样限流规则才能统一生效。entry.exit()必须在 finally 里调用,否则并发计数不会释放,会导致限流误判。

4.3 Sentinel 规则配置详解

规则配置我放在 Nacos 里,格式是 JSON。核心规则如下:

[ { "resource": "llm_call", "grade": 1, "count": 80, "strategy": 0, "controlBehavior": 2, "maxQueueingTimeMs": 8000, "clusterMode": false }, { "resource": "llm_call", "grade": 0, "count": 10, "strategy": 0, "controlBehavior": 0, "clusterMode": false } ]

第一条规则是并发线程数限流:grade: 1表示线程数模式,count: 80是阈值,controlBehavior: 2是匀速排队,maxQueueingTimeMs: 8000是最大排队时间 8 秒。

第二条规则是 QPS 限流:grade: 0表示 QPS 模式,count: 10是阈值,controlBehavior: 0是快速失败。这条是兜底,防止排队请求无限堆积。

两条规则同时生效,Sentinel 会取最严格的那个。实际运行中,并发线程数限流是主力,QPS 限流是保险丝。

4.4 参数计算:阈值到底怎么定

阈值不是拍脑袋定的,我有一套计算方法:

第一步,确定 LLM API 的并发配额。这个问云厂商或者看文档,假设是 100。

第二步,留安全缓冲。一般留 20%,所以汇聚点阈值设 80。

第三步,验证单实例承载能力。压测一下,看单个应用实例在 80 并发下,CPU、内存、线程池是否健康。如果单实例扛不住,就水平扩容。

第四步,计算总实例数。如果单实例能扛 20 并发,那 4 个实例刚好 80。但要注意,Sentinel 默认是单机限流,多实例场景下总并发是各实例之和。如果需要集群限流,要部署 Sentinel 的 Token Server。

我踩过的坑:一开始没注意单机限流的问题,4 个实例每个都配 80,实际总并发 320,直接把 LLM API 打爆。后来改成单实例 20,总并发控制在 80,才稳定下来。

4.5 超时与重试的配合策略

限流只是第一道防线,超时和重试策略同样关键。

超时设置:LLM 调用超时我设的是 30 秒。这个值看起来很长,但 LLM 生成长文本确实可能耗时这么久。设太短会导致大量正常请求被误杀。

重试策略:只对特定异常重试,比如连接超时、429 限流。重试次数最多 2 次,且必须加退避——第一次重试等 1 秒,第二次等 3 秒。绝对不能用固定间隔重试,否则会加剧下游压力。

重试与限流的关系:重试的请求也会经过 Sentinel,会占用并发配额。所以重试次数不能多,否则会挤占正常请求的配额。我的经验是重试请求的配额占比不超过 10%。

5. 常见问题与排查技巧实录

5.1 限流不生效的排查思路

限流配了但没生效,是最常见的问题。排查顺序如下:

第一,检查资源名是否一致。Sentinel 是按资源名匹配规则的,SDK 里写的是llm_call,规则里也必须写llm_call,大小写、下划线都不能错。我见过有人 SDK 写llmCall,规则写llm_call,排查了半天。

第二,检查规则是否推送成功。Sentinel Dashboard 上能看到当前生效的规则,如果规则列表是空的,说明推送链路有问题。检查 Nacos 配置、检查 Sentinel 客户端版本、检查网络连通性。

第三,检查是否走了 SDK。如果业务代码绕过 SDK 直接调 LLM API,限流当然不生效。用 Arthas 或者日志确认一下调用链路。

第四,检查并发计数是否泄漏。如果entry.exit()没在 finally 里调用,并发计数会一直涨,最后所有请求都被限流。这种情况的表现是"限流过于严格",而不是"不生效"。

5.2 匀速排队导致请求堆积的处理

匀速排队模式用不好,会导致请求在队列里堆积,最后大量超时。

我遇到过一次:maxQueueingTimeMs 设了 30 秒,结果高峰期队列里堆了几千个请求,用户等 30 秒后还是失败,体验极差。

解决办法有两个:一是缩短排队时间,我后来改成 8 秒,超过就快速失败,让用户尽早知道结果;二是加队列长度限制,Sentinel 本身不支持队列长度限制,但可以在 SDK 层加一个计数器,队列超过一定长度就直接拒绝。

5.3 LLM 返回 429 的应急处理

即使做了限流,偶尔还是会收到 429。这时候不能慌,按以下步骤处理:

立即动作:在 SDK 层捕获 429 异常,触发熔断,暂停所有 LLM 调用 10 秒。这 10 秒内所有请求走降级逻辑。

短期动作:检查是不是有突发流量,如果是,临时调低限流阈值。同时联系云厂商确认配额是否有变化。

长期动作:如果 429 频繁出现,说明配额不够,要么申请提额,要么做多厂商备份,一个挂了切另一个。

5.4 常见问题速查表

问题现象可能原因排查方法解决方案
限流不生效资源名不匹配对比 SDK 和规则配置统一资源名
限流过于严格并发计数泄漏检查 entry.exit() 调用确保 finally 中调用
请求大量超时排队时间过长查看队列长度和等待时间缩短 maxQueueingTimeMs
频繁 429总并发超配额检查各实例阈值之和调低单机阈值或集群限流
熔断后不恢复熔断窗口设置过长查看熔断器状态缩短熔断时长
降级逻辑不生效异常类型不匹配检查 catch 的异常类型扩大异常捕获范围

5.5 几个血泪教训

教训一:不要相信"理论上"的并发。我们上线前算过,单请求平均 3 次 LLM 调用,入口 200 QPS,总并发 600,LLM 配额 1000,理论上够。实际上线后,某些复杂请求触发 8 次调用,峰值并发直接破千。永远按最坏情况估算

教训二:限流阈值要留足缓冲。我一开始把阈值设成配额的 95%,觉得充分利用资源。结果 LLM API 的响应时间波动时,实际并发会短暂超过阈值,触发 429。后来改成 80%,再没出过问题。

教训三:降级逻辑必须提前准备好。事故当晚,限流触发后,降级逻辑返回的是空答案,用户看到一片空白,投诉如潮。后来改成返回缓存答案或友好提示,投诉量降了 90%。降级不是技术问题,是产品问题

教训四:监控比限流更重要。限流是事后补救,监控是事前预警。我们在汇聚点加了详细的监控:当前并发数、排队长度、429 次数、熔断状态。这些指标一有异常就告警,能在用户感知前发现问题。

6. 监控告警与容量规划

6.1 必须监控的核心指标

汇聚点的监控指标,我列了一个清单,缺一不可:

  • 当前并发线程数:实时反映对 LLM API 的压力,是最核心的指标
  • 排队请求数:匀速排队模式下,队列长度超过阈值要告警
  • 限流触发次数:按分钟统计,突增说明流量异常或阈值过低
  • 429 错误次数:直接反映 LLM API 的限流情况
  • 熔断器状态:打开状态持续超过 1 分钟要告警
  • LLM 调用 P99 耗时:耗时突增往往是下游出问题的前兆
  • 降级请求占比:降级比例超过 5% 要关注,超过 20% 要告警

这些指标通过 Micrometer 上报到 Prometheus,Grafana 做看板,Alertmanager 做告警。告警阈值根据历史数据动态调整,避免误报。

6.2 容量规划的实用方法

容量规划的核心问题是:当前配置能扛多少流量,什么时候需要扩容

我的方法是做压测,但不是简单的 QPS 压测,而是模拟真实调用链路的压测。用生产环境的请求日志做回放,每个请求触发真实的 LLM 调用次数,观察汇聚点的并发数和响应时间。

压测结果用来画一张图:横轴是入口 QPS,纵轴是汇聚点并发数。找到并发数接近阈值时的入口 QPS,这就是当前配置的容量上限。留 30% 余量,就是安全容量。

扩容的触发条件:连续 3 天,每天的高峰期并发数超过安全容量的 80%,就该扩容了。扩容方式优先水平扩容应用实例,同时按比例调整单机限流阈值。

6.3 多厂商备份的切换策略

单一 LLM 厂商的风险很高,配额限制、服务故障、价格调整都可能影响业务。多厂商备份是必然选择。

切换策略我设计了三层:

第一层,主备切换。主厂商正常时全量走主,主厂商熔断时自动切到备厂商。切换在 SDK 层完成,业务无感知。

第二层,流量灰度。新厂商接入时,先切 5% 流量过去,观察一周,没问题再逐步放大。

第三层,成本优化。不同厂商价格不同,可以在低峰期把流量切到便宜的厂商,高峰期切回稳定的厂商。这个策略需要业务方确认,因为不同厂商的回答质量可能有差异。

切换的关键是统一抽象。SDK 层定义统一的请求和响应格式,各厂商的差异在适配器里消化。这样切换时业务代码完全不用改。

7. 一些个人体会

这套方案跑了大半年,中间又迭代了几次,目前支撑着日均千万级的 LLM 调用,没再出过雪崩事故。回过头看,最关键的认知转变就是标题里那句话:AI 接口高并发不等于秒杀高并发

秒杀思维是"堵入口",AI 思维是"控汇聚"。入口堵得再死,链路内部的放大效应不解决,下游照样被打穿。把闸门挂在 LLM 调用汇聚点,才是治本之策。

另外一点体会是,限流不是越严越好。我见过有的团队把阈值设得极低,结果大量正常请求被拒,用户体验极差。限流的目标是"保护下游的同时最大化吞吐",不是"把请求挡在门外"。阈值要基于压测数据来定,不能拍脑袋。

最后分享一个小技巧:在 SDK 里加一个"影子模式",新规则上线时先只记录不拦截,观察一周的实际影响,确认没问题再真正生效。这个做法帮我们避免了好几次误配置导致的事故。

这套方案不是银弹,不同业务场景可能需要调整。但核心思路——找到调用汇聚点,在那里挂闸门——应该是通用的。如果你正在做类似的事情,希望这篇内容能帮你少踩几个坑。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/23 3:40:48

5个步骤搞懂字幕模板源码解析,告别教程依赖症

5个步骤搞懂字幕模板源码解析,告别教程依赖症 看了一堆视频,跟着敲完代码,一动手写项目就卡壳?这不是你的问题,是大多数教程的毛病。他们只教“怎么做”,不教“为什么这么做”,导致你脑子里全是碎片,没有底层逻辑。今天咱们不谈虚的,直接拆解【字幕模板】的【源码解析】,把那些藏在框架背后的底层原理给你扒得干…

作者头像 李华
网站建设 2026/9/23 3:40:09

爱帮网3个核心API改造方案附完整示例

爱帮网3个核心API改造方案附完整示例 版本升级后 API 全变了,看着文档头大,代码报错满天飞?别慌,这是很多老项目升级时的通病。今天直接上干货,用 完整示例 拆解爱帮网高频接口的性能瓶颈,手把手教你把响应时间砍掉 80%。 性能瓶颈定位:别猜,用数据说话…

作者头像 李华
网站建设 2026/9/23 3:39:59

3个坑教你搞定期货现货策略代码实战

3个坑教你搞定期货现货策略代码实战 复制来的策略代码一跑就报错,变量名对不上、接口调用超时,这种抓狂感太熟了。我在带新人做 期货现货 套利 实战项目 时,发现80%的问题都出在数据清洗和状态管理上。别急着甩锅给代码作者,咱们得自己懂底层逻辑才能调通。…

作者头像 李华
网站建设 2026/9/23 3:39:50

Python连连看小游戏源代码解析:从运行到核心逻辑

简介:这是一份面向Python初学者与中级开发者的连连看小游戏完整源代码,适合想通过实战项目巩固语法、理解GUI编程与游戏逻辑的读者。压缩包共2个文件,包含1个py主程序与1个png图片素材,整体约84KB,轻量易读&#xff0c…

作者头像 李华
网站建设 2026/9/23 3:39:46

3个坑让你搞懂来电闪光灯怎么设置的开发最佳实践

3个坑让你搞懂来电闪光灯怎么设置的开发最佳实践 复制来的代码跑不通不知道怎么调?别急,这不是你的问题。很多刚入行的朋友拿到一段关于【来电闪光灯怎么设置】的示例代码,直接粘贴到项目里,结果手机黑屏或者闪光灯根本不亮,甚至直接崩溃。这时候你只会盯着屏幕发呆,不知道哪里错了。其实,核心问题往往出在权限申请…

作者头像 李华