查看: 3151| 回复: 5
跳转到指定楼层
上一主题 下一主题
收起左侧

[经验总结] 当 QPS 不再等于容量:聊聊自适应并发控制的工程实践

   
全局:

注册一亩三分地论坛,查看更多干货!

您需要 登录 才可以下载或查看附件。没有帐号?注册账号

x
刷一地论坛经常看到大家在讨论高并发流量治理时,张口闭口就是 Guava 的 RateLimiter、分布式令牌桶、漏桶。说实话,这些东西应付一下面试八股文挺好,要是真不加思索地扔进几千个 Pod 的复杂微服务底座里,大概率大促当晚你就得起来擦屁股。

今天咱们不扯理想化的公式,从流量配额的本质出发,聊聊为什么大规模工业界都在从静态 QPS 限流走向自适应并发控制。

【先说结论:令牌桶其实没错】

在正式剖析痛点前,先定个调子:令牌桶没有错。
令牌桶解决的是流量配额(Rate Limiting)和业务边界问题,在以下场景中它是绝对的主力:
  • 用户公平性控制
  • 租户隔离(Multi-tenancy)
  • API 防刷与恶意爬虫防护
  • 业务层面的流量预算控制(Budgeting)
但它并不直接回答另一个更底层、更物理的工程问题:"当前这台机器,此刻到底还能扛多少请求?"

当系统进入资源瓶颈区间时,真正决定服务是否会雪崩的,往往不是 QPS 本身,而是当前正在处理的请求数(Concurrency)、响应时间(RT)以及底层的资源利用率。

【真实工业界的 Corner Case】

教科书总假设流量是完美的随机均匀分布。但在生产环境中,静态阈值往往会被下面两个经典场景背刺。

1. 静态阈值的“刻舟求剑”与 Little's Law

我们在配置中心给某个接口配了
  1. 单机 Limit = 500 QPS
复制代码
。下午 3 点,由于各种不可控的客观物理原因,单机处理延迟开始恶化。
其实这里隐藏着一个经常被忽略的底层事实:对于一个在线服务来说,机器承受的实际压力往往更接近并发数,而不是 QPS。
根据经典的 利特尔法则(Little's Law)
  1. Concurrency = QPS * RT
复制代码

这也是为什么很多团队会发现一个极其诡异的现象:某个接口上线半年一直稳定运行,某天下游数据库突然变慢了 30%,明明外部输入的 QPS 完全没变,结果自己服务的线程池却先满了,随后 RT 飙升,最终整个服务陷入雪崩。

问题从来不是流量变大了,而是因为 RT 变长,单位请求在系统里停留得更久了。如果 QPS 保持 500 不变,但 RT 从 50ms 上涨到 100ms,那么系统中的在途请求数(持有的线程和内存资源)会直接翻倍。

从这个角度看,QPS 其实只是外部观察指标,RT 反映的是系统内部状态,而 Concurrency 才是连接二者的桥梁。 这也是为什么很多成熟系统最终控制的是并发数而不是 QPS。因为 QPS 只是输入流量,而 Concurrency 才是真正占用线程、连接、内存和 CPU 资源的对象。QPS 并不等于系统容量。

2. 新 Pod 扩容时的“冷启动脆断”

在大促或者突发流量把现有集群逼到绝路时,HPA 终于憋出招来,紧急扩容了 50 个 Pod。按照静态均摊逻辑,每个新 Pod 分到了满额的 2000 QPS 指标。

然而,一个处于完全冷状态的实例,由于本地缓存空白(Cache Miss)、连接池尚未建立、下游连接未预热、以及 JVM 的分层编译(Tiered Compilation)此时尚未完成充分优化(JIT 优化尚未收敛),其真实的实际处理能力往往远低于稳定运行状态。

当 Readiness Probe 刚探测通过后,上游负载均衡可能在很短时间内开始向该实例分配正常流量。如果直接灌进来满额的静态均摊流量,会导致这个新 Pod 瞬间 CPU 爆表、RT 飙升,进而引发健康检查超时被直接干死。扩一个死一个,形成骨牌雪崩。

【走向自适应并发控制】

这也是为什么 Netflix 的 Concurrency Limits、Envoy 的 Adaptive Concurrency Filter、以及越来越多现代 Service Mesh 和 API Gateway,虽然实现细节不同,但都在向基于实时反馈的并发控制演进
它们的核心思想和 TCP 的拥塞控制(Congestion Control)非常接近:
  • 不断探测系统当前的极限
  • 出现排队迹象和延迟变长时快速收缩并发窗口
  • 窗口恢复后缓慢扩张
很多现代系统甚至不再把 CPU 作为主要控制信号。因为 CPU 打满未必代表系统已经拥塞,而排队和 RT 恶化往往能更早地反映瓶颈。因此,更常见的做法是将 In-flight Requests(在途请求数)、Queue Length(队列长度)和 RT 变化趋势作为核心的反馈信号,而将 CPU、Memory 和 Load Average 退化为辅助的兜底保护指标。
核心思想示意(AIMD)这种动态窗口最朴素的实现,其实非常类似 TCP 里的 AIMD(Additive Increase Multiplicative Decrease) 算法。
  • 系统健康(RT 正常):并发窗口缓慢递增(
    1. MaxInflight + 1
    复制代码
  • 系统开始拥塞(RT 变长):并发窗口快速收缩(
    1. MaxInflight * 0.8
    复制代码
这种策略最大的优点是稳定:扩张很慢,避免流量突增瞬间冲垮系统;收缩快,避免雪崩进一步扩散。
为了说明核心思想,这里放一段极简的逻辑示意代码(实际生产环境一般会使用更复杂的 AIMD、Vegas 或者 Netflix Gradient2 算法,下面代码只是为了剥离细节看本质):
您好!
本帖隐藏的内容需要积分高于 188 才可浏览
您当前积分为 0。
使用VIP即刻解锁阅读权限或查看其他获取积分的方式
游客,您好!
本帖隐藏的内容需要积分高于 188 才可浏览
您当前积分为 0。
VIP即刻解锁阅读权限查看其他获取积分的方式
Unlock interview details and practice with AI
Curated Interview Questions from Top Companies


【深入浅出:Vegas 与 Gradient2 思想与工程痛点】

当然,工业界的顶尖生产底座并不会真的像上面 AIMD 的示意代码那么粗暴。
以 Netflix Limits 或 Envoy 过滤器背后的算法演进为例,其核心逻辑都是在实时观察和对比:当前短窗口的平均 RT (R_current) vs 历史长周期无排队时的基准 RT (R_min) 二者之间的差值。

为了方便说明思想,在排除了 RTT EWMA 采样、长周期均值窗口以及分歧检测(Divergence Detection)等工程细节后,我们可以将其近似理解为如下的梯度调节公式:
  1. Limit_new = Limit_current * (R_min / R_current) + QueueSize
复制代码
  • 当系统没有排队时
    1. R_current
    复制代码
    接近
    1. R_min
    复制代码
    ,梯度接近 1,并发窗口保持稳定,并配合一个微小的
    1. QueueSize
    复制代码
    (常数,比如 1~3)允许系统缓慢向外探测更高的边界。
  • 当系统开始出现排队时
    1. R_current
    复制代码
    开始变大,
    1. (R_min / R_current)
    复制代码
    变成一个小于 1 的系数(比如 0.85),并发窗口立刻平滑地向内收缩
由于直接观察 RT 的变化趋势,这种方法往往能比 CPU 利用率更早、更精准地发现系统正接近饱和状态。这与 TCP Vegas 的核心思想非常接近:利用延迟变化预测拥塞,而不是等到系统已经发生资源耗尽、线程池打满甚至雪崩之后再被动处理。
真正踩过坑才知道的工程细节:RT 选型的两难

然而,实际生产中,RT 基准值的选择本身就是一个巨大的难题。

采样 RT 时,我们到底看平均值、P50 还是 P99?
  • 使用平均值:极易受到长尾请求的严重污染,导致窗口无意义地频繁收缩。
  • 使用 P99:虽然代表了极端长尾,但可能导致窗口过度保守,系统白白空闲。
  • 使用 P50:又容易漏掉真实的拥塞苗头。
因此,在工业界的真实治理底座里,通常需要引入 EWMA(指数加权移动平均),配合长短周期基线对比来降低噪声。同时,当硬件环境、下游依赖或者网络拓扑长期发生变化时,历史基准 RT(R_min)可能逐渐失真,从而导致窗口判断出现偏差,因此很多实现都会对基准值进行动态更新或老化处理。
总结
梳理完这条演进线,我们就能清晰地看清现代分布式流量治理的全局拓扑。
  • 令牌桶解决的是流量配额问题(关心“谁能进来”,聚焦于公平性、隔离与预算控制)。
  • 自适应并发控制解决的是容量边界问题(关心“系统还能承受多少”,聚焦于单机物理边界的动态自愈)。
两者并不是替代关系,而是现代流量治理体系中相互补充的两层保护机制。

[外部流量引入]
      |
      v
+------------------------------------------+
| 外层防护:Rate Limiting (令牌桶/配额管理)   |  --> 过滤租户、防刷、控预算
+------------------------------------------+
      |
      v
+------------------------------------------+
| 内层内核:Adaptive Concurrency Control   |  --> 盯紧 In-flight、RT 反馈与 Vegas 思想
|      (Vegas / Gradient / Gradient2)      |      动态收缩/扩张并发窗口,保护单机物理边缘
+------------------------------------------+
      |
      v
[业务线程池处理]
放弃对静态阈值的盲目迷信,转而通过在途请求数(Concurrency)去和系统的硬件负载及延迟做实时对齐,对于大规模分布式系统而言,这往往是流量治理走向精细化的重要一步。

大伙儿组里在物理网关或者 Mesh 边车里,目前有真正把 Gradient2 这种自适应并发算法推向大规模生产的吗?大家在实操中遇到过哪些调参的坑(比如长短周期滑动窗口的参数设计,或者规避瞬时抖动干扰)?欢迎在回帖里聊聊你们组真实的流量治理故事。

利益相关提示:给别人加米不会扣除自己的积分/米,看完觉得有点收获的老铁,顺手赏两颗米鼓励一下硬核技术分享,拜谢!

评分

参与人数 17大米 +26 收起 理由
heyjudydb4aid + 1 很有用的信息!
Coherence + 2 楼主/层主请继续!
微信用户_yh8zv + 1 给你点个赞!
匿名用户-JANXT + 1 赞一个
instant_dev + 5 给你点个赞!

查看全部评分


上一篇:【反向重构】聊聊最近组里把微服务并回大单体时,数据迁移和安抚老客户的真实血泪史
下一篇:【系统设计】Alex Xu的System Design不过瘾?这里有全网最全的系统设计真题和解答
🔗
soyohu 2026-6-8 01:43:41 | 只看该作者
全局:
难得的好文,感谢分享!我们也是今年才开始针对每个service设置不同的istio concurrency,在此之前完全依赖frontgate rate limiter,通过在生产环境做压力测试推算出每个service最大可承载concurrency然后加一些buffer,本质上也是个静态设置,但是大大降低雪崩效应。
回复

使用道具 举报

🔗
 楼主| 秀眉丽眼的木耳 2026-6-8 03:06:25 | 只看该作者
全局:
soyohu 发表于 2026-6-7 10:43
难得的好文,感谢分享!我们也是今年才开始针对每个service设置不同的istio concurrency,在此之前完全依赖 ...

感谢分享,这其实和文章想表达的方向很接近。

很多团队一开始都是从 Rate Limiting 起步,后来发现真正决定单机是否失稳的往往还是并发度,于是开始引入固定 Concurrency Limit。你们通过生产压测去估算每个 Service 的容量边界,再留 Buffer,本质上已经是在做容量保护了。

我个人觉得静态 Concurrency Limit 最大的价值就是简单、稳定、可解释。对于 RT 比较稳定的服务,很多时候已经能解决 80% 的问题。

我比较好奇的是,你们后面有没有遇到过这种情况:同样的 Service,在正常情况下能稳定扛住某个 Concurrency,但因为下游依赖变慢、缓存命中率下降或者冷启动等原因,实际容量突然缩水?这种场景下静态阈值会不会经常需要重新调?

这也是我后来开始关注 Adaptive Concurrency 的原因,它更像是在自动追踪容量边界,而不是人工维护容量边界。
回复

使用道具 举报

🔗
soyohu 2026-6-8 06:04:23 | 只看该作者
全局:
秀眉丽眼的木耳 发表于 2026-6-7 12:06
感谢分享,这其实和文章想表达的方向很接近。

很多团队一开始都是从 Rate Limiting 起步,后来发现真 ...

这种情况肯定存在,对于business critical service每隔几周就会做一次生产环境压力测试,这个权限下放给了service team,如果有重大功能更新,他们随时可以自己测试。
再就是每年traffic peak提前2~3个月我们就会做大范围的生产环境压力测试,然后size capacity for annual traffic peak。
这里唯一的问题就是没法在生产环境做某个业务数据流的压力测试,比如在traffic入口慢慢增加流量,然后fan out。
回复

使用道具 举报

全局:
好文。 Gradient2参数不好控制吧。 实际应用中确实会避免雪崩的问题,但也会导致service过度reject requests, 然后CPU memory 利用率极低, 很难trigger HPA
回复

使用道具 举报

🔗
Jaywolf 2026-7-5 04:31:41 | 只看该作者
全局:
😢,信号处理的问题,看看流量控制的算法吧
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册账号
隐私提醒:
  • ☑ 禁止发布广告,拉群,贴个人联系方式:找人请去🔗同学同事飞友,拉群请去🔗拉群结伴,广告请去🔗跳蚤市场,和 🔗租房广告|找室友
  • ☑ 论坛内容在发帖 30 分钟内可以编辑,过后则不能删帖。为防止被骚扰甚至人肉,不要公开留微信等联系方式,如有需求请以论坛私信方式发送。
  • ☑ 干货版块可免费使用 🔗超级匿名:面经(美国面经、中国面经、数科面经、PM面经),抖包袱(美国、中国)和录取汇报、定位选校版
  • ☑ 查阅全站 🔗各种匿名方法

本版积分规则

>
快速回复 返回顶部 返回列表