想象你是一家网红餐厅的老板。周末晚上,门口排着长长的队伍,客人络绎不绝。你最关心的指标是什么?不是“今天来了多少客人”(那是总客流量),而是“一秒钟内有多少位客人成功入座点餐”——这才是餐厅真正的“瞬时接客能力”。如果这个数字太低,说明餐厅内部某个环节卡住了:可能是厨师出菜太慢,可能是服务员顾不过来,也可能是收银台排起了长队。 AI 推理服务就像这家餐厅。QPS(Queries Per Second,每秒查询数)就是衡量 AI 服务“一秒能接待多少请求”的核心指标。它不像总调用量那样是一个“积累量”,而是一个“瞬时速度”。就像汽车仪表盘上的时速表,你能随时看到当前是 60 码还是 120 码。QPS 监控,就是给 AI 服务装上这块速度表——它能告诉你系统现在是“畅通无阻”还是“堵死瘫痪”,是“刚刚好”还是“资源浪费”。 这篇文章将用“餐厅经营”这条主线贯穿始终,带你从零理解 QPS 监控:从基本定义、测量指标、影响因素,到瓶颈定位、优化策略,再到生产环境中的容量规划和告警,让你不仅能看懂 QPS 曲线,还能像经营餐厅一样,把 AI 服务的“接客效率”调到最佳状态。

岗位关联

QPS 监控是 AI 工程化落地中衡量推理服务健康度的“体检报告”。掌握它,你就具备了定位系统瓶颈、规划算力资源、保障服务稳定性的核心能力,是从“能调模型”到“能上线扛流量”的关键一跃。

目录
  1. 可视化演示
  2. QPS 基本概念
  3. 测量指标
  4. 影响因素
  5. 瓶颈定位
  6. 优化策略
  7. 容量规划
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

展示QPS流量曲线、Little定律延迟关联及弹性伸缩告警策略的三模态交互动画。

本节配有交互动效(进入视口后自动加载,约 3KB)。

QPS流量曲线监控 实际 阈值 QPS=req/time_window 每秒查询数监控流量曲线实时采集请求计数滑动窗口计算QPS值

QPS 基本概念

想象餐厅门口的迎宾员手里有一个计数器。每当一位客人成功入座,他就“咔哒”按一下。一天下来,计数器上的总数是“总接客量”。但如果你是老板,你更想知道的是:“现在这一刻,一秒能进来几位客人?”这就是 QPS——Queries Per Second,每秒查询数。它不是一个累计数值,而是一个“流速”,就像自来水管里水的流速,你随时可以问:“现在每秒流过多少升水?”

在 AI 推理服务中,“客人”就是一个个推理请求(Query)。客户端把一张图片发过来,让模型判断“这是猫还是狗”,这就是一次查询。QPS 衡量的是:这一秒钟之内,系统成功处理了多少个这样的请求。注意关键词是“成功处理”——不是“接收了多少”,而是“完成了多少”。如果系统接收了 1000 个请求,但只成功返回了 800 个结果,那 QPS 只能算完成的那部分。

QPS 与响应延迟(Latency)是一对“欢喜冤家”。延迟是“每位客人从进门到坐下花了多久”,QPS 是“一秒钟能坐下几位客人”。餐厅里如果每桌客人要吃 2 小时(延迟高),那翻台率就低,一秒能接待的新客人就少。但如果你把上菜速度从 2 小时压到 30 分钟(降低延迟),同样数量的桌子就能接待更多客人,QPS 自然就上去了。

回到餐厅的比喻:你请了一个数据分析师,让他统计“10 分钟内进来了多少客人”,除以 600 秒,得到一个“平均每秒接客数”。这个数字很有用,但它会掩盖一个事实——晚上 7 点到 7 点 05 分可能挤进来 80 人,而 7 点 15 到 7 点 20 只有 10 人。平均 QPS 是 90/600=0.15 人/秒,但峰值时刻的瞬时 QPS 可能是平均的好几倍。所以,光看平均 QPS 远远不够,我们还需要一套更精细的“尺子”。

QPS=成功处理的请求总数统计时间窗(秒)\displaystyle \text{QPS} = \frac{\text{成功处理的请求总数}}{\text{统计时间窗(秒)}}
该公式说明:QPS 本质是一个“速率”,用一段时间内成功处理的请求数除以秒数。例如 10 秒内成功处理了 500 个请求,QPS 就是 50。
  1. 成功处理的请求总数指在统计窗口内,AI 服务真正完成并返回结果的请求数量。如果请求超时或报错,不算入分子。
    Successful Requests=Total Requests−Errors−Timeouts\displaystyle \text{Successful Requests} = \text{Total Requests} - \text{Errors} - \text{Timeouts}
  2. 统计时间窗(秒)计算 QPS 的时间范围。生产环境通常以 1 分钟或 10 秒为一个窗口,窗口太短会抖动明显,太长则会“抹平”尖峰。
    Δt=tend−tstart\displaystyle \Delta t = t_{\text{end}} - t_{\text{start}}
  3. 整体比值的含义求出的 QPS 是该窗口内的“平均流速”。要捕捉瞬时高峰,需要缩小窗口或用下面要讲的峰值百分位数。
    QPS=NsuccessΔt\displaystyle \text{QPS} = \frac{N_{\text{success}}}{\Delta t}

测量指标

继续经营你的餐厅。你决定在门口装一个智能摄像头,每秒记录一次“当前排队人数”。这个摄像头每秒产生一个数据点,积累起来就是一条随时间变化的曲线——这就是 QPS 时间序列。但面对成千上万个数据点,你如何快速判断餐厅经营得怎么样?你需要几个“浓缩指标”。

第一个是均值(Average)。把所有数据点加起来除以总数,得到平均 QPS。它告诉你系统“通常”处于什么水位。但均值有个大问题:它会被极端值“平均掉”。假设系统每秒稳定处理 100 个请求,偶尔有一秒处理了 1000 个(比如热点事件),均值会被拉高,让你误以为系统很空闲。反过来,若系统经常抖动到 0,均值也可能“看起来还行”。

第二个是峰值 QPS(Peak)。取所有数据点中的最大值。峰值决定了系统“最忙的那一刻”能不能扛住。如果峰值超过系统容量,就会产生超时和错误。就像餐厅的极限接待能力,不取决于平均客流,而取决于“最汹涌的那一波”能不能接住。

第三个是TP99(99th Percentile)。把所有 QPS 数据点从小到大排序,取第 99% 位置的那个值。它意味着“99% 的时间里,系统 QPS 都没超过这个值”。TP99 比峰值更稳健,因为它丢掉了最极端的 1% 的噪声数据。对应到延迟监控中还有个常用的 TP99(延迟的 99 分位),但这里我们关注的是 QPS 的 TP99。你可以把 TP99 理解为“去掉最疯狂的那 1% 时刻后,系统最忙的常态”。

用餐厅来理解:你的摄像头记录了 1000 秒的排队数据,按人数从少到多排好序。第 990 个位置对应的排队人数,就是“TP99 排队量”——它告诉你,在 99% 的时间里,队伍最长也就这么长。这对你决定“什么时候需要加开临时窗口”非常关键。同理,QPS 的 TP99 告诉你系统的“高水位常态”是多少,是容量规划的第一参考值。

无论用哪个指标,都必须关联成功率一起看。想象餐厅疯狂接客,但每道菜都做错了,客人纷纷退菜——这时候“每秒入座数”再高也是虚的。AI 服务也一样:如果 QPS 上去了但错误率飙升,说明系统正在“硬撑”,请求虽然收到了,但大量返回 5xx 错误。所以生产监控中,QPS 曲线要和成功率曲线放在同一张图里看。

TP99=排序后第 ⌈0.99×N⌉ 个数据点的值\displaystyle \text{TP99} = \text{排序后第 } \lceil 0.99 \times N \rceil \text{ 个数据点的值}
该公式说明:将 N 个 QPS 采样值升序排列,取排在 99% 位置的那个值。如果 N=100,就取第 99 个;如果 N=1000,取第 990 个。
  1. 采样排序假设系统每 10 秒采集一个 QPS 值,一共采集了 1000 个值。先把这 1000 个数从小到大排队。
    x(1)≤x(2)≤⋯≤x(1000)\displaystyle x_{(1)} \le x_{(2)} \le \cdots \le x_{(1000)}
  2. 确定百分位位置TP99 要找“99% 的数据都小于等于它”的那个位置。计算索引 index = 0.99 × 1000 = 990。
    index=⌈0.99×N⌉=990\displaystyle \text{index} = \left\lceil 0.99 \times N \right\rceil = 990
  3. 取出该位置的值排序后第 990 个值,就是 TP99。它比最大值小(因为丢了最后 1% 的极端值),但比均值大得多(因为它代表了高水位)。
    TP99=x(990)\displaystyle \text{TP99} = x_{(990)}

影响因素

为什么有的 AI 服务一秒能处理 1000 个请求,有的只能处理 10 个?这背后有四个核心影响因素,如同餐厅的“硬件设施”和“运营流程”决定了你的接客上限。

第一是单请求延迟(Latency)。这是最根本的因素。如果一次模型推理平均耗时 100 毫秒,那么理论上单线程每秒最多处理 10 个请求(1000ms ÷ 100ms)。就像一位厨师做一道菜要 10 分钟,那他一个人一小时最多出 6 道菜。延迟越低,单个“服务员”能服务更多客人。推理的延迟主要来自模型计算量(FLOPs)、输入长度、模型结构(如 Transformer 的层数)等。

第二是批量大小(Batch Size)。现代 GPU 擅长“并行做事”。一次推理可以同时处理 8 张图片,成本远低于单独处理 8 次。这就是批处理(Batching)的威力。假设单次推理处理 1 张图需要 100ms,处理 8 张图需要 200ms,那 8 张图平均每张只花 25ms——吞吐量翻了 4 倍!这就像厨师一次炒一大锅菜,比一盘一盘炒快得多。

第三是显存带宽与算力上限。GPU 的计算能力(FLOPS)和显存带宽决定了“批量能开多大”。批量太大,显存装不下,或者计算单元已经饱和,再增大批量只会增加延迟而不再增加吞吐。这就像餐厅厨房面积有限,灶台就那么多,厨师再多也挤不进去。

第四是并发数(Concurrency)。服务能同时处理多少个请求?如果模型服务是单线程的,那一次只能处理一个请求;如果有多个 worker 进程或开启了多线程,就能同时处理多个。并发数越高,QPS 上限越高,但每个请求的延迟也可能变长(因为资源竞争)。

回到餐厅:你的“并发数”就像餐厅的包厢数——可以同时接待几桌客人;“批量大小”就像一个包厢能坐几个人;“单批时间”就是一桌客人从入座到离开的时长。QPS 就是“一小时内所有包厢累计接待的人数 ÷ 3600 秒”。要提高这个值,要么加包厢(提高并发)、要么每桌多坐几人(增大批量)、要么加速翻台(降低延迟)。理解了这四个因素,你就知道优化该往哪个方向使劲了。

QPSmax≈并发数×批量大小单批推理延迟\displaystyle \text{QPS}_{\text{max}} \approx \frac{\text{并发数} \times \text{批量大小}}{\text{单批推理延迟}}
该公式说明:系统最大 QPS 约等于“并发通道数乘以每通道每秒能处理的批次数”。这是一个估算模型,实际还受 CPU 预处理、网络 IO 等环节影响。
  1. 并发数(Concurrency)可以同时处理请求的通道数。若服务开了 4 个 worker 进程,每个进程可同时跑 2 个推理任务,则总并发数为 8。
    C=workers×threads per worker\displaystyle C = \text{workers} \times \text{threads per worker}
  2. 批量大小(Batch Size)每个推理任务中打包的请求数。GPU 一次前向传播处理的样本数。
    B=请求数 per 一次推理\displaystyle B = \text{请求数 per 一次推理}
  3. 单批推理延迟(Latency per Batch)处理完一整批请求所需的时间。注意批量增大时延迟会增长,但不是线性增长——8 张图的推理时间通常远小于 8 倍单张时间。
    LB=处理 B 个请求的总耗时\displaystyle L_B = \text{处理 B 个请求的总耗时}
  4. 整体估算每秒能处理的总请求数 = 并发数 × 每批大小 ÷ 每批耗时。
    QPSmax=C×BLB\displaystyle \text{QPS}_{\text{max}} = \frac{C \times B}{L_B}

瓶颈定位

餐厅经营惨淡,QPS 上不去,问题出在哪?是门口接待太慢?是后厨出菜太慢?还是服务员传菜太慢?你需要“全链路排查”。AI 推理服务也一样,一个请求从到达服务器到返回结果,要经过多个阶段。要定位 QPS 瓶颈,必须给每个阶段计时。

一条典型的推理请求链路包括五个环节:

1. 网络接收:请求从客户端到达服务器,经过负载均衡、网关(如 Nginx、Envoy)。

2. 预处理:CPU 上执行——解码 JSON、图像缩放、文本 Tokenization、归一化等。

3. 排队等待:请求在推理服务队列中等待 GPU 资源。

4. 模型推理:GPU 上的核心计算——Transformer 前向传播。

5. 后处理:CPU 上执行——softmax 求结果、拼装响应 JSON、返回客户端。

用“埋点计时”的方式,给每个环节打上时间戳,你就能看到时间花在哪了。这就像给餐厅的每个环节装上计时器:客人几点到门口、几点坐下、几点点上菜、几点吃上饭、几点离开。哪个环节耗时最长,哪个就是“瓶颈环节”。

定位瓶颈除了分段计时,还要看资源利用率。如果 GPU 利用率已经 99% 但 QPS 还是低,说明计算本身是瓶颈;如果 GPU 只有 30% 但 QPS 低,说明 CPU 预处理或数据传输(Host-to-Device 拷贝)在拖后腿。可以做一个实验:增大并发请求数,看 QPS 是跟着涨还是停滞——如果 QPS 涨到了一定程度就再也上不去,那个“天花板”就是瓶颈的位置。

餐厅的例子:你发现客人来了之后迟迟吃不上饭,于是让服务员记录每一桌“点完菜到上菜”的时间(相当于 T_infer 的逆过程——厨房出菜时间)和“坐下到点完菜”的时间(相当于 T_pre——接待效率)。结果发现,坐下后平均要等 20 分钟才能点菜,而出菜只要 5 分钟——瓶颈在服务员,不在厨师!同理,AI 服务的瓶颈可能根本不在 GPU 算力,而在 CPU 预处理环节。

Ttotal=Tnetwork+Tpre+Tqueue+Tinfer+Tpost\displaystyle T_{\text{total}} = T_{\text{network}} + T_{\text{pre}} + T_{\text{queue}} + T_{\text{infer}} + T_{\text{post}}
该公式说明:端到端延迟是各阶段延迟之和。如果某个阶段占比超过 50%,它就是首要优化目标。注意队列等待时间是一个重要信号——若 T_queue 很大,说明 GPU 已经打满,请求在排队。
  1. 网络时间(T_network)请求在网络上传输和网关转发的时间,通常几毫秒。如果这个值异常大,可能是网络带宽或网关配置的问题。
    Tnetwork=Tgateway+Ttransmit\displaystyle T_{\text{network}} = T_{\text{gateway}} + T_{\text{transmit}}
  2. 预处理时间(T_pre)CPU 花在数据转换上的时间。当输入图片很大或文本很长时,预处理可能成为瓶颈——CPU 忙不过来,GPU 却在“等米下锅”。
    Tpre=Tdecode+Ttokenize+Tnormalize\displaystyle T_{\text{pre}} = T_{\text{decode}} + T_{\text{tokenize}} + T_{\text{normalize}}
  3. 排队时间(T_queue)请求在队列里等待 GPU 的时间。这个值最能反映“系统是否过载”——如果它持续增长,说明请求进来的速度超过了处理速度。
    Tqueue=等待被调度执行的时间\displaystyle T_{\text{queue}} = \text{等待被调度执行的时间}
  4. 模型推理时间(T_infer)GPU 上跑神经网络的时间。这是 AI 服务的“主业”,通常占总耗时的大头,但健康的系统中它应当占比 60%-80%。
    Tinfer=一次前向传播耗时\displaystyle T_{\text{infer}} = \text{一次前向传播耗时}
  5. 后处理时间(T_post)把推理结果包装成响应的时间,通常很短。但若返回的 payload 很大(比如生成式 AI 输出长文本),也可能拖慢整体。
    Tpost=Tserialize+Tencode\displaystyle T_{\text{post}} = T_{\text{serialize}} + T_{\text{encode}}

优化策略

找到了瓶颈,接下来就是对症下药。QPS 优化的策略可以归纳为三大类:让每次处理更高效、让资源更饱和、让没必要的计算消失。

策略一:动态批处理(Dynamic Batching)。这是提升 QPS 最有效的通用手段。核心思想是:把一小段时间内到达的请求攒起来,凑成一整批再送给 GPU 推理。就像餐厅把同一时间段入座的客人安排在几张桌上,厨师一次性炒几桌的菜。Triton Inference Server 和 vLLM 都内置了动态批处理功能。关键参数有 max_batch_size(最大批量)和 max_queue_delay(最大攒批等待时间)。攒批时间太长会增大延迟,太短则批量装不满——需要权衡。

策略二:模型加速。通过模型量化(Quantization)、结构剪枝(Pruning)、知识蒸馏(Distillation)等方式,让推理更快。量化把 FP16 的权重变成 INT8,计算量减半,显存占用减半,推理延迟显著降低。这就像厨师改用“预制菜”——提前做好的半成品,客人点菜后只需简单加热就能上桌,出菜速度大幅提升。

策略三:缓存复用(Caching)。如果大量请求是重复的(比如同一个热门问题),可以用缓存把结果存起来,后续相同请求直接命中缓存,不用再算。这就像餐厅的“招牌菜提前做好放在保温柜里”,客人一点就端出来。实际工程中可以用 Redis 或推理框架自带的 Prefix Caching(如 vLLM 的自动前缀缓存,对长对话非常有效)。

以下是量化对 QPS 影响的经验公式思路:

三种策略可以叠加使用,但要记住“木桶原理”——优化永远优先针对瓶颈环节。如果瓶颈在 CPU 预处理,你做再多的模型量化也无济于事,因为 GPU 早就空闲了。正确的做法是:先定位瓶颈,再选择对应的策略。这就像餐厅生意不好,你得先搞清楚是排队太长、上菜太慢还是菜品难吃,再决定是加椅子、换厨师还是换菜单。

QPS量化后≈QPS量化前×延迟量化前延迟量化后\displaystyle \text{QPS}_{\text{量化后}} \approx \text{QPS}_{\text{量化前}} \times \frac{\text{延迟}_{\text{量化前}}}{\text{延迟}_{\text{量化后}}}
该公式说明:如果量化把单请求延迟从 100ms 降到 50ms,在其他条件不变的情况下,QPS 理论上可以提升约一倍。实际提升幅度受批量拼接、显存带宽等限制,通常达不到理论值。
  1. 量化前后的延迟对比先测出优化前单批延迟 L_before 和优化后延迟 L_after。量化模型的推理速度更快,因此 L_after 更小。
    Lbefore=100ms,Lafter=50ms\displaystyle L_{\text{before}} = 100\text{ms}, \quad L_{\text{after}} = 50\text{ms}
  2. 计算加速比加速比 = 优化前延迟 ÷ 优化后延迟。这个比值直接折算成 QPS 的理论提升倍数。
    Speedup=LbeforeLafter=2.0\displaystyle \text{Speedup} = \frac{L_{\text{before}}}{L_{\text{after}}} = 2.0
  3. 估算新 QPS假设系统资源不变,QPS 与单请求延迟成反比。延迟减半,QPS 理论上翻倍。
    QPSnew≈QPSold×Speedup\displaystyle \text{QPS}_{\text{new}} \approx \text{QPS}_{\text{old}} \times \text{Speedup}

容量规划

餐厅开到第三年,你决定开分店。问题来了:新店的厨房要多大?几个厨师?几口灶?这就需要“容量规划”——根据预测的 QPS 需求,倒推出需要多少台服务器、多少张 GPU。

容量规划的关键步骤是压测(Load Testing)。在测试环境用工具(如 Locust、wrk、JMeter)向服务发起不同强度的请求,逐步加大压力,记录 QPS 和延迟的变化曲线。当你发现 QPS 不再增长,而是开始下降,同时延迟和错误率飙升——这个拐点就是系统的“极限容量”。就像测试一个厨师一秒最多能炒几道菜:让他不断加快节奏,直到他手忙脚乱出错的临界点。

压测后你会得到三个关键数据:单实例最大 QPS(QPS_max_per_instance)、目标 QPS 的 TP99 延迟、拐点对应的资源利用率。然后可以用简单的公式估算需要多少个实例:

规划完成后还需要配置梯度告警。别等到 QPS 超过极限才报警——那时候系统已经崩了。建议设置三个梯度阈值,就像水库的“汛限水位”:

  • 黄线(60% 容量):预告警,提示流量正在上升,需要关注。
  • 橙线(80% 容量):提示需要准备扩容或启用限流。
  • 红线(100% 容量):立即自动扩容或触发降级保护。

餐厅的类比:你根据“周末晚上 7 点的预计客流”决定开几桌、雇几个服务员。如果预计客流是 200 人,而一张桌子一晚最多接待 20 人,你就需要 10 张桌子,再加 3 张备用桌(余量)。客流超过 8 成时你就该让服务员“加快翻台”(优化);超过 10 成时,你就得在门口挂“暂停接客”牌子(限流),否则整个餐厅都会乱套。

N实例数=⌈QPS目标QPS单实例极限×1.3⌉\displaystyle N_{\text{实例数}} = \left\lceil \frac{\text{QPS}_{\text{目标}}}{\text{QPS}_{\text{单实例极限}}} \times 1.3 \right\rceil
该公式说明:用目标 QPS 除以单实例能扛的极限 QPS,得到理论需要的最少实例数。乘以 1.3 是为了预留 30% 的余量,防止某个实例故障或流量突增时整体崩盘。
  1. 确定目标 QPS根据业务预测峰值流量。通常参考历史峰值的 1.5-2 倍,或结合业务活动日历预测。
    QPS目标=历史峰值 QPS×增长系数\displaystyle \text{QPS}_{\text{目标}} = \text{历史峰值 QPS} \times \text{增长系数}
  2. 获取单实例极限通过压测得到单个推理实例(一张 GPU)的最大稳定 QPS。这个值不是理论峰值,而是“延迟还在可接受范围内”的 QPS。
    QPS单=压测拐点处 QPS\displaystyle \text{QPS}_{\text{单}} = \text{压测拐点处 QPS}
  3. 计算实例数并取整目标 QPS 除以单实例 QPS,向上取整。
    N理论=⌈QPS目标QPS单⌉\displaystyle N_{\text{理论}} = \left\lceil \frac{\text{QPS}_{\text{目标}}}{\text{QPS}_{\text{单}}} \right\rceil
  4. 加上余量系数乘 1.3(即多备 30% 的冗余),应对突发流量和单点故障。
    N最终=⌈N理论×1.3⌉\displaystyle N_{\text{最终}} = \left\lceil N_{\text{理论}} \times 1.3 \right\rceil

AI 应用场景

场景一:大模型推理服务的容量预估

阶段:模型部署与上线规划

解决的问题:某公司准备将开源大语言模型(如 Llama-3-8B)部署为线上问答服务,CTO 需要知道:买 4 张 A100 够不够?传统做法是“拍脑袋”决定 GPU 数量,结果要么买多了浪费几十万成本,要么买少了上线第一天就被打爆。

具体案例:运维团队用 Locust 对部署好的模型服务进行持续压测,逐步将并发从 1 调到 64,记录每个并发下的 QPS 和 TP99 延迟。压测发现单张 A100 在 TP99 延迟 < 2 秒的约束下最大稳定 QPS 为 15。业务预测上线首月峰值 QPS 为 100,于是按公式计算:100 ÷ 15 × 1.3 ≈ 9 张 GPU。团队最终采购了 10 张 A100(8 张 + 2 张冗余),上线后实际峰值 QPS 达到 95,系统平稳运行。

场景二:交易风控系统的实时告警

阶段:在线监控与运维

解决的问题:某支付公司的风控模型每秒要处理数千笔交易。如果 QPS 突然暴跌,说明模型服务可能挂掉了;如果 QPS 正常但延迟飙升,说明即将过载。传统监控只看 CPU 和内存,无法直接感知“业务吞吐健康度”。

具体案例:监控平台接入 Prometheus + Grafana,每 5 秒采集一次风控模型的 QPS 和 TP99 延迟数据。设置告警规则:QPS 低于基线 50% 持续 1 分钟触发 P0 告警,TP99 延迟超过 800ms 触发 P1 告警。一次真实故障中,某模型因上游特征服务超时导致 QPS 从 3000 跌到 800,系统在 1 分钟内发出告警,值班工程师及时发现并降级了模型,避免了支付链路阻塞。

Python 演示

python90 行
"""QPS 实时监控与容量规划计算器模拟 AI 推理服务的请求处理,计算实时 QPS、TP99,并根据压测结果估算所需实例数。"""import timeimport randomfrom collections import deque  class QPSMonitor:    def __init__(self, window_size=10):        self.window = deque(maxlen=window_size)        self.samples = []  # 存放每个时间窗口的 QPS 记录        self.request_count = 0        self.window_start = time.time()     def record_request(self):        self.request_count += 1     def update(self):        now = time.time()        elapsed = now - self.window_start        if elapsed >= 1.0:            qps = self.request_count / elapsed            self.window.append(qps)            self.samples.append(qps)            self.request_count = 0            self.window_start = now            return qps        return None     def avg_qps(self):        if not self.window:            return 0.0        return sum(self.window) / len(self.window)     def peak_qps(self):        if not self.window:            return 0.0        return max(self.window)     def tp99(self):        if len(self.samples) < 10:            return 0.0        sorted_samples = sorted(self.samples)        idx = int(0.99 * len(sorted_samples)) - 1        return sorted_samples[max(idx, 0)]  def simulate_traffic(monitor, duration=30):    """模拟 30 秒的推理请求流量"""    end_time = time.time() + duration    while time.time() < end_time:        # 模拟请求到达:平稳期每秒约50个,突发期翻倍        if int(time.time()) % 10 >= 8:            rate = 120        else:            rate = 50        for _ in range(rate):            monitor.record_request()        time.sleep(0.02)        monitor.update()  def plan_capacity(target_qps, single_instance_qps, margin=1.3):    import math    return math.ceil(target_qps / single_instance_qps * margin)  def main():    monitor = QPSMonitor(window_size=10)    print("开始模拟推理流量...")    simulate_traffic(monitor, duration=30)     print("\n==== QPS 监控统计 ====")    print(f"平均 QPS: {monitor.avg_qps():.1f}")    print(f"峰值 QPS: {monitor.peak_qps():.1f}")    print(f"TP99 QPS: {monitor.tp99():.1f}")     target = 200    capacity = 80    instances = plan_capacity(target, capacity)    print(f"\n==== 容量规划 ====")    print(f"目标 QPS: {target}, 单实例极限 QPS: {capacity}")    print(f"建议实例数: {instances}(含30%余量)")  if __name__ == "__main__":    main()
目的:演示一个轻量级 QPS 监控器的核心逻辑——按 1 秒窗口计数计算 QPS,实时滚动统计均值、峰值和 TP99,并根据压测数据估算所需的推理服务实例数。
  1. self.window = deque(maxlen=window_size)用固定长度的双端队列保存最近的 QPS 采样值,滚动统计时自动丢弃旧数据。
  2. self.request_count += 1每次收到请求就累加计数器,这是计算 QPS 的原始数据来源。
  3. elapsed = now - self.window_start计算距离上次刷新的时间差,当超过 1 秒时计算一次 QPS。
  4. qps = self.request_count / elapsed用窗口内的请求数除以秒数,得到这一秒的平均速率,即 QPS。
  5. self.window.append(qps)把新算出的 QPS 值加入历史窗口,保留最近 10 秒的数据用于统计。
  6. return sum(self.window) / len(self.window)对窗口内所有 QPS 取平均,得到“平均 QPS”水位。
  7. return max(self.window)取窗口内的最大值,得到“峰值 QPS”——容量规划的关键参考。
  8. sorted_samples = sorted(self.samples)把所有历史 QPS 采样值排序,为计算 TP99 做准备。
  9. idx = int(0.99 * len(sorted_samples)) - 1计算百分位位置,取第 99% 分位的值作为 TP99 的估算。
  10. for _ in range(rate)模拟请求到达:循环生成一批请求并记录,休息 0.02 秒后继续。
  11. math.ceil(target_qps / single_instance_qps * margin)用目标 QPS 除以单实例容量乘以 1.3 余量,向上取整得到实例数。

常见误区

误区“QPS 这个数字越大,说明我的 AI 服务越强,性能越好。我要不惜一切代价把 QPS 刷上去!”

正解QPS 只有在“保证延迟和成功率合格”的前提下才有意义。如果为了提升 QPS 而把批量开得巨大,每个请求的延迟从 100ms 涨到 3 秒,用户体验急剧恶化——这就像餐厅为了多接客,让所有客人拼桌挤在一起,结果每桌客人都吃得很难受,下次再也不来了。正确做法是设定延迟 SLA(如 P99 < 500ms),在其约束下最大化 QPS。

为何常见:很多人看到 QPS 指标就以为是“跑分”游戏,忽略了它背后是延迟、成功率、资源成本的多目标平衡。业务方的“快”是体验指标,而 QPS 只是系统指标。

误区“我看了监控面板,平均 QPS 才 50,系统很空闲啊,不用扩容。”

正解平均 QPS 会严重掩盖峰值风险。假设流量模式是 1 秒来 200 个请求,接下来 9 秒完全空闲,平均 QPS 只有 20,但系统在那一秒已经过载崩溃。正确做法是同时关注峰值 QPS 和 TP99,用峰值(而不是均值)来做容量规划。这就像水库蓄水,你要看的是汛期最高水位,而不是全年的平均水位。

为何常见:人类直觉上习惯用“平均”来总结数据,但在流量具有显著突发性时,均值失真严重。

误区“AI 推理就是 GPU 算的,QPS 上不去肯定是 GPU 不够,加卡就行了!”

正解很多实际案例中,瓶颈在 CPU 预处理、数据传输或网络 IO。比如输入图片需要大量解码和缩放操作,CPU 忙不过来,GPU 闲置率高达 60%。加再多 GPU 也无济于事。通过全链路分段计时(如上文 T_pre / T_infer 分别埋点),先确认瓶颈环节再投入资源,才是正确姿势。

为何常见:AI 服务给人的第一印象就是“GPU 在干活”,容易忽略同样耗时的数据准备环节。这就像人们催“厨师太慢”时,其实可能是传菜员在偷懒。

误区“压测显示单机能扛 200 QPS,那我上 5 台就能扛 1000 QPS 了,就这么定了!”

正解压测环境通常比生产环境“干净”:没有真实流量的波动、没有其他服务的资源争抢、没有网络的随机抖动。生产环境的 QPS 通常只有压测结果的 60%-70%。这也是前面公式里要乘 1.3 余量的原因。同时,生产环境的模型输入长度、并发模型可能和压测差异巨大——压测必须和真实业务形态对齐。

为何常见:工程师容易把实验室数据当成生产承诺,忽略了真实环境的复杂性和不确定性。

面试题

Q1. 以下对 QPS 的描述,最准确的是哪一项?

单选题 · mid

  • A.QPS 是系统接收到的请求总数量
  • B.QPS 是每秒成功处理的请求数,反映瞬时吞吐能力← 正确答案
  • C.QPS 与延迟完全无关,只与硬件有关
  • D.QPS 应该越高越好,不需要考虑延迟约束

答案:B。QPS 是 Queries Per Second,指的是每秒成功处理的请求数,重在“成功”和“每秒”两个限定词。选项 A 错在把速率当成总量;C 错在 QPS 与延迟强相关;D 错在必须在延迟 SLA 约束下追求 QPS,不能盲目求高。

Q2. 关于 TP99 指标,以下说法正确的有哪些?

多选题 · mid

  • A.TP99 是对所有 QPS 采样数据排序后的第 99 百分位值← 正确答案
  • B.TP99 比最大值更能代表系统的常态高水位← 正确答案
  • C.TP99 一定大于等于平均值← 正确答案
  • D.TP99 一定小于等于中位数

答案:ABC。TP99 是排序后取 99% 位置的值,它丢了最极端的 1% 噪声数据,所以比最大值更稳健,且通常明显大于均值,故 A、B、C 正确。对于右偏分布,TP99 必然大于中位数,D 错误。

Q3. 一个 GPU 推理单机压测显示最大 QPS 为 50,目标是支撑 300 QPS 的业务峰值,考虑 30% 余量,至少需要几台实例?

单选题 · mid

  • A.6 台
  • B.7 台
  • C.8 台← 正确答案
  • D.10 台

答案:C。计算公式为 N = ⌈300 ÷ 50 × 1.3⌉ = ⌈7.8⌉ = 8 台。6 台没有考虑任何余量,7 台的理论总容量 350 但乘余量系数后不足 300×1.3=390,只有 8 台才能满足 30% 余量的要求。

Q4. 在推理链路中,哪个信号最能说明 GPU 已经过载、请求在排队等待?

单选题 · easy

  • A.预处理时间突然变短
  • B.排队等待时间(T_queue)持续增长← 正确答案
  • C.后处理时间显著下降
  • D.网络传输时间归零

答案:B。当请求到达速度超过 GPU 处理速度时,请求就会在队列中堆积,表现为 T_queue 持续增大。这就像一个堵车的收费站,排队队伍越来越长。其他选项都是“变快/变短”,与过载现象矛盾。

Q5. 以下哪些措施可以直接提升 AI 推理服务的 QPS?

多选题 · hard

  • A.启用动态批处理聚合多个请求← 正确答案
  • B.对模型进行 INT8 量化降低单请求延迟← 正确答案
  • C.增加请求的输入文本长度
  • D.对热门请求结果做缓存复用← 正确答案

答案:ABD。动态批处理让 GPU 一次处理更多请求,量化降低延迟从而提升单通道吞吐,缓存直接跳过了计算——三者都能提升 QPS。增加输入长度反而会增大计算量和延迟,降低 QPS,所以 C 错误。

Q6. QPS 监控中,为什么要把“成功率”和 QPS 放在一起看?

单选题 · easy

  • A.因为成功率影响报表美观
  • B.因为 QPS 高但错误率高说明系统在硬撑,吞吐可能是虚的← 正确答案
  • C.因为成功率是 KPI,QPS 不是
  • D.因为两者没有关系

答案:B。QPS 只统计“成功处理”的请求,但如果系统过载时大量请求报 5xx 错误,QPS 可能表面正常甚至偏高,实际服务质量已经崩溃。因此必须结合成功率判断“有效 QPS”。这就像餐厅说“每秒接待了 10 桌”,但如果 8 桌都在投诉菜品,这数字没意义。

Q7. 均值 QPS 为 100,峰值 QPS 为 500,这最可能说明什么?

单选题 · easy

  • A.系统非常稳定,不需要关注
  • B.流量分布极度不均,存在明显突发,容量规划应以峰值为参考← 正确答案
  • C.均值计算错误,应该改成中位数
  • D.峰值数据是噪声,可以忽略

答案:B。均值与峰值之间 5 倍的差距说明流量具有强突发性。如果只按均值 100 规划容量,突发时刻到 500 时系统必然过载。正确做法是参考峰值和 TP99 做容量规划,并配置提前告警。这种“平均很空闲、峰值很凶猛”的模式在秒杀、热点事件中很常见。

Q8. 关于推理服务的容量规划,以下说法正确的有哪些?

多选题 · mid

  • A.压测得到单实例最大 QPS 后,直接用它作为生产容量标准
  • B.容量规划应预留一定余量以应对流量波动和单点故障← 正确答案
  • C.压测必须模拟真实的输入规模和并发模型← 正确答案
  • D.告警阈值应该设置到 100% 容量时再触发,避免误报

答案:BC。生产环境比压测环境复杂,通常要预留 30% 余量,所以 A 错误、B 正确。压测若和真实流量形态偏差大,结果就不可信,C 正确。告警应分梯度提前到 60%/80% 触发,D 认为等到 100% 才告警会错过最佳处理时机。

Q9. 其他条件不变,将单请求延迟从 200ms 优化到 80ms,理论上 QPS 提升多少倍?

单选题 · hard

  • A.1.5 倍
  • B.2.0 倍
  • C.2.5 倍← 正确答案
  • D.3.0 倍

答案:C。QPS 与单请求延迟成反比(QPS ≈ 1/延迟 × 并发×批量)。200ms 到 80ms,延迟变为原来的 0.4 倍,QPS 提升 200÷80=2.5 倍。注意这是单通道的理论估算,实际受批处理拼接效率、资源竞争等影响会略低。

Q10. 在 GPU 利用率只有 20% 但 QPS 很低的情况下,最可能的原因是什么?

单选题 · mid

  • A.GPU 算力不足,需要换更贵的卡
  • B.CPU 预处理或数据加载环节存在瓶颈,GPU 在等待数据← 正确答案
  • C.QPS 监控面板坏了
  • D.模型太大,显存放不下

答案:B。GPU 利用率低但吞吐上不去,典型的“供血不足”——数据来不及喂给 GPU。CPU 上做图像解码、文本 tokenize 太慢,或 Host-to-Device 拷贝耗时过长,GPU 只能空转。这就是“厨房里厨师闲坐着,但传菜员没把食材送来”。应该优化预处理管线或增加 CPU 资源,而不是换 GPU。