脉冲流量到底该怎么扛?从QPS 800飙到47000的那90秒,我把参数全摊开

🔑 关键词:脉冲流量,突发流量,限流配置,削峰,峰值QPS

📖 摘要:用一次真实直播活动的监控数据,拆解脉冲流量的量化方法、Nginx限流参数、Redis与MQ的分层挡流策略,以及被验证过的降级清单,顺带说清脉冲流量在仪表和运营语境里的另外两层意思。

搜「脉冲流量」的人其实至少分三拨:一拨在仪表和液压圈,说的是脉冲输出型流量计(涡轮、椭圆齿轮这类);一拨做后端,说的是突发流量、毛刺流量;还有一拨干运营,说的是平台突然甩给你的一波推荐流量。我三种都碰过一点,这篇主要讲第二种,因为坑最多、最花钱,顺带把另外两种的区别说清楚,免得你搜错方向白看半天。先声明,我不是什么架构专家,就是个在业务线上被脉冲流量捶过几次的普通开发,下面写的全是我们自己系统上跑过的数,环境不一样你得自己再压一遍。

图片

先给脉冲流量一个能量化的定义,别再说「能扛高并发」

我听过最没用的一句话就是「我们系统扛得住高并发」。扛多少?扛多久?从多少开始涨、涨到多少、几秒钟涨完?答不上来就等于没答。脉冲流量真正要看的是三个数:上升沿时间、峰值倍数、持续时长,少一个都算不清账。

举个我们自己的例子。2023 年做过一场直播带货的技术保障,那天的曲线我到现在还存着截图:开播前 5 分钟,订单创建接口的 QPS 稳稳在 800 上下,波动不超过 ±80;8:00:12 开始往上爬,到 8:00:41 摸到峰值 47000;峰值维持了大约 90 秒,8:02 回落到 3000 左右,8:15 回到 900 的日常水位。

这里面最扎心的是:那 90 秒贡献了当晚 62% 的订单创建请求,但只占整场直播(3 小时 40 分,13200 秒)的 0.68%。也就是说,你有 99.3% 的时间在为一个几乎不出现的水位付钱。上升沿只有 29 秒,这意味着任何依赖「慢慢扩容」的方案在这 29 秒里都是废的——你 Auto Scaling 的检测周期加实例启动时间,快的话也要 40 秒。

图片

决定你是扛住还是雪崩的三个参数

第一个是利用率 ρ = λ/μ。 到达速率比服务速率,经验值是 0.7 安全、0.85 警戒、0.9 以上排队长度开始指数上升(M/M/1 模型里这个拐点很清楚)。那次峰值 47000 QPS,如果老老实实按 ρ ≤ 0.7 反推,集群得具备 67000 QPS 的稳定处理能力,而我们当时的真实容量压测出来是 52000。按教科书算,这单子必挂。结果没挂,后面讲为什么。

第二个是队列深度,用 Little's Law 估:L = λ × W。 47000 QPS 乘上允许的 0.3 秒等待,等于瞬间有 14100 个请求在途。这个数直接决定你的连接池、线程池、MQ 缓冲区要开多大。我们线上 HikariCP 的 maximumPoolSize 从默认 10 调到 80,Tomcat maxThreads 从 200 调到 600,acceptCount 从 100 调到 1000——不是越大越好,超过这个数只会把雪崩从入口挪到数据库。

图片

第三个是上升沿的斜率,这个最容易被忽略。 同样从 800 涨到 47000,30 秒爬完和 3 秒爬完完全是两码事。3 秒爬完的情况下,本地缓存还没热、JIT 还没编译、连接池还没建满,你容量标称 52000,实际能打出来的可能只有 26000。我们那次是 29 秒,算是运气好。

具体怎么削峰,按性价比排个序

第一层,入口限流,别一上来就扩容。 Nginx 我们最终跑在线上的配置大概长这样:

limit_req_zone $binary_remote_addr zone=api_per_ip:10m rate=20r/s;
limit_req_zone $server_name zone=api_global:10m rate=8000r/s;



![图片](http://img0.baidu.com/it/u=3491650136,2769644198&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=667)


location /api/order {
    limit_req zone=api_per_ip burst=40;
    limit_req zone=api_global burst=2000;
    limit_req_status 429;
    proxy_pass http://order_backend;
}

注意这里我没加 nodelay。第一次上线我们是加了 nodelay 的,想着 burst=2000 一下子就放过去多痛快,结果洪峰原封不动传到 upstream,接口 RT 从 40ms 飙到 1.2s,429 比例才 0.3% 但后端已经半死。改成不加 nodelay、让 burst 里的请求排队之后,429 反而更少了,因为后端有了喘息时间。这个坑我踩过一次,不希望你再踩。

第二层,Redis 挡读,MQ 挡写。 读请求尽量在缓存层就终结,商品详情页的 QPS 47000 里大概 43000 是纯读,命中率 96% 的时候 Redis 单节点压力其实很轻(我们那台 8C16G 的实例平时也就 4 万 QPS 左右,峰值冲到 6.8 万还撑得住)。写请求全部改成投递 MQ 异步落库,Kafka 那个 topic 开了 12 个分区,峰值写入大概 380MB/s 分摊下来每分区 30MB/s 出头,这个数对 Kafka 来说很轻松,真正吃紧的是消费端,消费组从 8 个实例紧急扩到 24 个才把 lag 压下去。

第三层,降级开关,这个必须提前写好,不能临时加。 我们那次实际拉掉的开关有四个:首页推荐位降级成静态兜底数据、商品详情页的价格和库存改成异步加载、用户等级和积分这类非核心字段直接不返回、下单结果页的推荐商品模块整个隐藏。这四个开关加起来大概省了 20% 的请求量,听着不多,但那 20% 正好压在数据库最脆弱的地方。

图片

一个可能有点反直觉的观点

大部分团队把脉冲流量当成「容量问题」,我觉得它本质上是「时间问题」。你按 47000 QPS 常备集群,一年可能只有 0.1% 的时间用得上,机器成本大概是平时的 4.2 倍;我们把峰值削到 31000(另外 16000 要么进队列要么被限),成本只多了 1.4 倍,订单创建成功率 99.2%,比平时只低 0.5 个百分点。

削峰不是妥协,是把「确定性」卖给用户,把「不确定性」留给系统内部消化。反过来讲,如果你为了那 0.68% 的时间付了 4 倍成本,那笔钱本来可以用来做两件事:把日常链路的 RT 从 40ms 降到 25ms,或者给运营多买一轮流量。哪个更划算,做业务的心里应该都有数。

图片

如果你搜的是另外两种「脉冲流量」

仪表和液压那个方向,脉冲输出型流量计(涡轮、椭圆齿轮、部分电磁)输出的是频率信号,厂家会给你一个仪表系数 K,单位通常是脉冲/升,不同口径差得很远,DN25 和 DN100 能差十几倍,必须按出厂标定值来。用 PLC 高速计数器读的时候有个经典矛盾:输入滤波时间设大了会丢脉冲,设小了现场干扰又会多计数,这跟后端限流里「采样窗口设多长」的纠结其实是一回事。

运营那个方向,平台给的脉冲流量窗口通常也就是 30 到 90 秒,跟直播那 90 秒本质上没区别——峰值不值得高兴,值得看的是回落之后的基线抬了多少。我们那次直播结束第二天,日常 QPS 从 800 抬到了 1100,这个 37% 的抬升才是真正留下来的东西,其余的都是一次性的。

最后一句话总结:脉冲流量的核心从来不是「扛住」,是「算清楚它值多少钱」。

🏷️ 标签: