“脉冲流量”一来,你的限流算法真的扛得住吗?

🔑 关键词:脉冲流量,限流算法,令牌桶,突发流量,自适应限流

📖 摘要:从一次真实的夜间接警讲起,对比令牌桶、漏桶、滑动窗口在脉冲流量下的失效原因,分享自适应限流与请求降级的实战经验。

先说一件真事。上个月凌晨两点,我被值班电话叫起来,说核心接口的错误率飙到了90%。打开监控一眼,那一瞬间的灰绿色折线像被打了肾上腺素,直接从几十QPS窜到了四千多。原因是一个科技大V在微博引用了我们的数据,顺手给了个链接。那种流量来得快,去得也快,整个过程不到十五分钟,但已经把数据库连接池打穿,应用服务器CPU处于饱和状态。这就是脉冲流量——不是普通的波峰,而是能量密度极高的瞬间冲击。

图片

做限流的人通常都喜欢聊令牌桶或漏桶。理论上,令牌桶允许一定程度的突发,比如你设置速率为每秒100个令牌,桶容量200,那么瞬间涌进来300个请求,前200个能通过,后面100个会被限到下一轮。听起来合理,但真实脉冲是每秒几千个,200个令牌一瞬就没了,剩下的全被拒掉。而漏桶干脆把请求排进队列,队列深度假设是500,结果填满后新请求直接丢弃,于是大部分真实用户的请求反而成了牺牲品。滑动窗口和计数器就更尴尬,它们面对这种高密度流量会出现边界跳变,导致明明上一秒放行了,下一秒却直接拦截,客户端不断重试,系统雪上加霜。也就是说,在脉冲面前,这些算法的核心假设都半真半假。

图片

我的看法是:不要把限流单独拎出来玩逻辑游戏,要把它当成系统对‘快速压力输入’的动态吸收过程。一个有效的解决思路是自适应限流——具体做法是,每100毫秒采集一次应用的平均响应时间、线程使用率和连接数,一旦发现响应时间超过比如500ms,就启动按比例降权,随着压力消退再逐步放开。这种策略不关心请求从哪来,因为波形不重要,重要的是系统的‘实时剩余容量’。还有一点是要区分请求类型。我们当时把分享链接的请求、往飞书推消息的请求、内部数据上报的请求标记成低优先级,在脉冲来临时先丢弃这部分。那次救了我们命的就是这个,它保住了数据查询的主链路。配合K8s的HPA,设置Pod CPU超过70%就扩容,虽然冷启动需要几十秒,但正因为扩张和降级同步做,峰值才没有变成雪崩。

图片

所以别迷信什么‘平滑限流’,也别指望一个固定参数能覆盖所有场景。我见过很多团队拿着令牌桶代码一贴,调完参数就高枕无忧,但从不拿脉冲波形做压力测试。压测的时候建议用wrk或自己写一个按矩形波调度的脚本,比如先空跑3秒,再在0.5秒内砸进3000个请求,循环20次,看看服务复位后还能不能恢复如初。真正的工程经验就是:限流是最后一道保险,不是设计目标。你要在设计上就允许脉冲流量把队列打满,但保证队列时间最短;允许后端抖动,但保证不杀掉关键请求。这样一来,哪怕半夜再响起报警,你也能安心说一句‘没事,让它冲’。这种自信,不是靠公式堆出来的,靠的是对脉冲流量真正的敬畏和数据上的推演。

图片

🏷️ 标签: