上礼拜五快下班那会儿我的后台监控突然开始报警P99 延迟一路从平时的八百毫秒冲到了快六秒。我心想坏了是不是哪段代码又炸了赶紧拉日志看。结果日志干干净净一个错误都没有就是单纯的慢。我盯着那个数字看了半天突然反应过来——是我手贱早上把服务的最大并发数从 8 调到了 64。先说清楚我说的这个服务是指把大模型封装成一个对外能调的推理服务比如用 vLLM 或者 Triton 这类推理引擎架起来的。模型本身没变参数没动就改了一个并发配置性能就崩成这样。你可能觉得这事有点反直觉——并发开大点不是应该吞吐更高、大家更快吗我也是这么想的结果现实给我上了一课。这里头有个特别关键的误区很多人以为推理服务的瓶颈在算得快不快其实瓶颈在怎么把活排队排好。模型推理不像普通的 Web 接口你请求一个就开一个线程去处理就行。GPU 上的计算是串行的一次只能真正跑一个前向过程你并发开高了请求全堆在 GPU 上排队等着谁也没法插队。这就好比一个只开了一个收费窗口的收费站你把来车从 8 辆放宽到 64 辆结果就是排队的车从一长条变成一眼望不到头单车的通过时间反而被拉长了。我第一次调这个参数的时候其实就踩过这个坑但当时没当回事以为只是偶发。真正让我疼的是这次线上事故。我把并发从 8 调到 64本意是想趁着流量上来之前多扛点并发结果恰恰相反——吞吐不升反降因为单请求延迟翻了好几倍坏请求触发的重试又多了一批雪球越滚越大。有句话怎么说的来着你在本地最多测出个寂寞线上高并发一压那些你以为稳如老狗的东西全现原形了。那是不是并发越开越低越好也不是。并发太低GPU 喂不饱白白浪费算力。这里头有个平衡点跟一个叫批处理batching的机制强相关。现代推理引擎会在同一时刻把多个请求拼成一个 batch 一起喂给 GPU这样虽然单条请求还是串行但多条请求能共享权重加载、共享显存里的KV 缓存key-value cache就是模型算过的中间结果摊下来每条的成本反而低了。所以并发太低吃不到批处理的甜头太高又把排队搞炸中间那一段才是黄金区间。你可能会问那到底开多少合适我没法给你一个万能数字因为它跟你的模型大小、显存、吞吐目标全绑在一起。但有个笨办法挺管用——直接压测把并发从 1 往上慢慢加每次盯着两个指标看一个是 P99 延迟一个是每秒钟能跑多少个 token输出token数/秒。你会发现一个神奇的拐点在拐点之前并发上去吞吐也上去过了拐点并发再上延迟开始断崖式上涨吞吐反而开始回缩。那个拐点就是你这个服务现实的承载力。打岔说一句我那台机器是双卡 A100内存 80G听起来很唬人实际上并发过 16 就开始明显吃紧了。别被显卡的规格唬住以为显存大就能扛住一切显存是能装下模型但不代表能装下同时排队的一堆请求的中间结果。这也是我这次事故里学到最深刻的一课。现在回头想我真正缺的不是并发配置是一套限流和熔断机制。限流rate limiting就是提前规定好这个服务一秒最多接多少个请求超了就排队或者直接拒绝宁可让部分请求快速失败也不让所有请求一起卡死。熔断circuit breaker更狠一旦发现连续失败率超过阈值直接把流量切走先保服务不崩。这两样东西听起来像是后端工程师的活儿但你做 AI 推理服务早晚都得会因为模型推理比普通接口更娇气一堵就是灾难级的。还有个小坑我得提一嘴就是压测的时候别用异步客户端的默认配置去测很多库的重试策略是失败就重试在高延迟下会把请求数又翻个好几倍测出来的延迟是虚高的。我自己就上过这个当测出来的曲线惨不忍睹后来才发现是重试把服务又打了一层。关于吞吐和延迟这笔账我现在的态度是别再盯着并发开到 64这种数字自我感动了先想想你的业务到底要的是低延迟还是高吞吐。如果你的场景是客服问答这种对响应时间敏感、但对量要求没那么极限的那低并发、稳延迟更实在如果是批量生成、离线跑任务这种不着急要结果的那高吞吐、能排队才是你该追求的。那你现在在用的推理服务并发到底开的多少你是靠压测拍出来的还是拍脑袋定的评论区聊聊你的拐点在哪我挺好奇的。