限流规则和并发控制的区别

接入与开发

讲清限流规则和并发控制在目的、触发点和实现上的差别,给接口开发者一套判断与排错顺序。

调接口时经常遇到两种「被挡住」:一种是你压根没超并发数却收到 429,另一种是并发拉太高把本地连接池和队列撑爆。很多人把这两件事混着看,改参数改了半天没改到点上。这篇只做一件事:把限流规则和并发控制拆成两条线,告诉你各自管什么、怎么判断当前卡在哪一层、以及先动哪个旋钮。

调接口的时候,卡壳的情况其实分两种:一种是你压根没开几个线程,却被服务端直接打回一句「请求太多」;另一种是线程拉得很猛,服务端没说啥,结果本地连接池先炸了。很多人把这两件事当成一回事,参数来回改,改完发现没用,因为压根没改到点上。

这篇只做一件事:把限流和并发控制拆成两条线。各自管什么、怎么判断当前卡在哪一层、先动哪个旋钮,讲清楚就够了。

先分清:一个管「你被允许多快」,一个管「你同时压多少」

限流是服务端或者网关下发的准入规则,决定的是单位时间内你能发多少次请求,超了就直接拒。这个额度窗口是对方定的,你改不了,只能顺着它调自己的节奏。并发控制则完全是你这一侧的事:同时有多少个请求在外面飞,是你本地代码里一个可以随手改的旋钮。

两者容易互相伪装。并发拉高会让单位时间的请求数变多,于是撞上服务端的限流;反过来限流拒掉一部分请求,你的实际并发数会看起来虚高或者虚低,监控图上的数字就不准了。判断顺序上,先看响应里服务端给的限流信号(状态码、重试等待提示、剩余额度头),再看自己这边的并发计数和排队长度。

限流
服务端或网关下发的准入规则,超出单位时间额度就拒绝,客户端无法修改
并发控制
客户端自己决定同时飞出去多少请求,是本地可调参数
伪装效应
并发高会推高单位时间请求数从而触发限流;限流又会让你看到的实际并发失真

怎么判断你这次卡在哪一层

观察项像限流的样子像自己并发问题的样子
返回速度请求一发出就快速失败发出去了,慢慢耗到超时
失败分布某一小段时间窗口内成批出现持续性的长尾延迟、连接超时
重试效果重试也不好,等待后才有改善重试偶尔能成,但整体越来越慢
本地指标连接池水位正常连接池占满、队列长度一直涨
  • 看请求的时间线:被限流的请求耗时通常极短;被自己并发拖住的请求是缓缓耗到超时。
  • 看失败是否成批:限流失败往往集中在某个时间窗内扎堆出现;并发问题表现为长期的长尾。
  • 看本地资源:连接池占用、排队深度、活跃连接数,这几个指标涨了就是自己这边的事。
  • 先把中间层的自动重试关掉再测,否则网关、中转层各自重试叠加,两层混在一起根本分不清是哪一层的锅。

动手调的顺序:先治限流,再调并发

  1. 对着服务端的等待提示做退避别用固定间隔硬重试,按对方给的等待时间退避,并加随机抖动,避免多个实例同一秒一起冲上去。验证方式:观察被拒次数是否明显下降。
  2. 把并发拆开设请求发起并发和连接池上限分开配,池子比并发数略大即可,否则请求会在本地排队等着拿连接。验证方式:连接池等待时间应该接近零。
  3. 排队和分批,而不是直接丢超出额度的部分先入队,配一个明确的失败重投上限,避免无限重试把额度烧光。验证方式:被丢弃的请求数应可控。
  4. 加观测再看调参有没有用每分钟记录成功数、被拒数、平均耗时和排队深度。只有这几个数字同时看,才知道调整是往好的方向走还是把问题挪了个位置。

有一点要提醒:交互式场景不合适长排队。用户就在那儿等着看结果,排队深度一高就该快速失败并给提示,而不是让人干等。批量任务、离线补数据这类场景才适合把队列堆高一点。

把这件事固定成一条可复用的清单

  • 上线前先量基线:单独发请求测一遍响应延迟,到 /tools/speed-test 看看正常时这条链路是什么水平。

把限流相关字段和并发计数一起打日志,事后复盘时能一眼看出是外部拒绝还是内部排队。给每个上游单独设并发上限,不要所有接口共用一个全局并发数,一个慢接口会把额度全占住。

环节要落到日志里的字段用来判断什么
请求发出时间戳、目标上游、当前并发数并发是否被拉高
响应返回状态码、耗时、服务端限流头是被拒还是自己慢
本地资源连接池水位、队列深度是不是自己这侧堵了
定期核对上游额度口径、模型规格配额是否已经变了
下一步各家上游的限流口径、额度窗口和调用规格会不定期调整,配参数之前先去核对一遍当下的数字,比拍脑袋靠谱。

常见问题

我没超并发数,为什么还是被限流?

因为限流和并发数的计量口径常常不同:限流可能按单位时间请求数、按 token 量或按账号共享额度来算,你的并发数只是一个瞬时快照。多个进程共用一个 Key、或者有重试在放大请求量,都会让你「看起来没超并发」但实际已撞线。先看服务端返回的限流信号,再统计整个账号层面的请求速率。

并发数应该设多少?

没有通用答案,取决于上游额度、你的超时设置和单个请求耗时。稳妥做法是从小往大试:先设一个明显保守的值,加压观察成功率和平均耗时,逐步加上去,直到被拒率或超时开始上升就退一格。同时给连接池留点余量,池子小于并发数时请求会在本地排队,看起来像限流其实是自己堵自己。

限流和并发控制能不能只做一层?

通常两层都要,但职责不同。服务端的限流你改不了,只能通过退避、分批、排队去适应;客户端的并发控制是你唯一能主动设计的部分,它决定你会不会把上游打爆、以及失败时表现得多难看。只做退避不做并发收敛,高峰期请求会堆成雪崩;只限并发不处理限流信号,遇到额度收紧照样全量失败。

本文依据各平台公开文档与官方公告整理,只做中文归纳;具体做法、参数与限制以官方文档为准。