
1. 从一张显卡到八张显卡并发估算为什么总让人心里没底做模型推理服务的人几乎都绕不开一个问题手上这几张卡到底能扛住多少路并发这个问题看起来简单实际上一旦认真算起来变量多到让人头疼。显存要装得下权重和KV Cache算力要跟得上每秒的请求量带宽决定了多卡之间通信会不会成为瓶颈而请求本身的输入输出长度分布又直接改变了每一路请求的资源占用。很多人第一次估算的时候凭感觉拍一个数字上线之后要么被打爆要么发现资源大量闲置两头都不讨好。我自己就经历过这种尴尬。早期做小规模推理服务的时候用一张卡跑一个7B左右的模型心里想着怎么着也能扛个几十路吧结果压测一跑十几路并发延迟就飙到没法看。后来才慢慢搞清楚并发数不是一个固定值它是显存、算力、带宽、请求特征四者共同约束下的一个动态平衡点。你换一个模型、换一种量化方式、换一批请求长度分布这个数字就会变。这也是为什么我决定动手做一个计算器。市面上的容量规划工具要么太粗只给一个笼统的推荐并发要么太细要求你填一堆底层参数却不知道从哪来。我想要的是一个介于两者之间的东西输入模型规模、量化精度、显卡型号和数量、请求的平均输入输出长度然后直接告诉我显存能撑多少路、算力能撑多少路取两者的小值再给一个安全余量。这个计算器不是要替代真实压测而是让你在买卡、租卡、排期之前心里先有一个靠谱的数量级判断。这篇文章就把这个计算器的设计思路、背后的计算逻辑、以及我在实际使用中踩过的坑完整地讲一遍。不管你是刚接触推理服务部署的新手还是已经在管多卡集群的老手应该都能从中拿到一些可以直接用的东西。核心关键词就三个GPU、并发数、计算器。我会尽量把每个公式的来龙去脉讲清楚让你不只是会用一个工具而是真正理解这个数字是怎么来的。2. 并发数到底被什么卡住了显存、算力、带宽的三方博弈2.1 显存约束KV Cache才是真正的吞金兽很多人算显存的时候第一反应是模型权重占多少。比如一个7B的模型FP16精度下大约14GBINT8量化后大约7GBINT4量化后大约3.5GB。这个算法没错但它只解决了静态占用。真正决定并发上限的是KV Cache。KV Cache是什么简单说Transformer在生成每一个token的时候需要用到之前所有token的Key和Value向量。如果每次都重新算一遍计算量会爆炸。所以工程上会把历史token的K和V缓存下来每生成一个新token只需要算当前这个token的K和V然后和缓存拼接。这个缓存的大小和序列长度成正比和并发路数成正比。具体公式是这样的单路请求的KV Cache大小 2 × 层数 × 注意力头数 × 头维度 × 序列长度 × 数据类型字节数。对于常见的7B模型层数32注意力头数32头维度128那么每token每路的KV Cache大约是2 × 32 × 32 × 128 × 2字节 512KB。如果平均序列长度是2048那么单路就是1GB左右。八张卡如果每张卡分到一部分假设用张量并行把模型切到8张卡上每张卡承担的KV Cache也是按比例切的但总容量是八张卡显存之和减去权重占用。这里有个容易忽略的点显存不是全部可用的。框架本身、CUDA上下文、通信缓冲区、碎片都会吃掉一部分。我一般会预留15%到20%的显存作为安全余量。所以实际可用的KV Cache空间是总显存减去权重占用再乘以0.8左右。2.2 算力约束Prefill和Decode是两个完全不同的阶段显存算完接下来是算力。这里必须区分两个阶段Prefill和Decode。Prefill是处理用户输入的那一批token可以并行计算算力利用率高通常是计算密集型。Decode是逐个生成输出token每一步只算一个token算力利用率低通常是内存带宽密集型。这两个阶段的耗时特性完全不同。Prefill的耗时大致和输入长度的平方成正比因为注意力机制而Decode的耗时和输出长度成正比但每一步的延迟相对固定。所以算并发的时候不能简单用一个每秒能处理多少token来概括要分开算。一个实用的估算方法是先算单路请求的总计算量。Prefill阶段的计算量大约是2 × 参数量 × 输入长度FLOPsDecode阶段是2 × 参数量 × 输出长度。然后看显卡的峰值算力比如A100是312 TFLOPSFP16H100是989 TFLOPS。但实际利用率通常只有30%到50%因为内存带宽、调度开销、通信都会拖后腿。我自己的经验是对于7B模型单张A100在FP16下Prefill阶段实际能达到的吞吐大约是峰值算力的35%左右Decode阶段因为受内存带宽限制实际吞吐会更低。八张卡如果做张量并行算力理论上翻八倍但通信开销会吃掉一部分实际可能只有六到七倍的有效算力。2.3 带宽约束多卡并行的隐藏成本八张卡一起跑通信是绕不开的。张量并行每一层都要做All-Reduce流水线并行要在阶段之间传激活值。这些通信如果走PCIe带宽可能只有几十GB/s如果走NVLink能到几百GB/s。差距非常大。我做过一个对比测试同样的模型同样的八张卡走PCIe和走NVLinkDecode阶段的延迟差了将近一倍。原因就是Decode阶段每一步都要通信通信延迟直接叠加到每一步的生成时间上。所以如果你的卡之间没有高速互联八张卡的有效并发可能远低于理论值。这也是为什么计算器里必须把互联方式作为一个输入项。你不能只看显卡型号和数量还要看它们是怎么连的。SXM版本的卡通过NVLink互联PCIe版本的卡只能走PCIe这两者的并发能力完全不是一个量级。2.4 请求特征平均长度骗人长尾才是杀手最后一个约束来自请求本身。很多人算并发的时候用平均输入长度和平均输出长度觉得这样就够了。但实际生产环境里请求长度分布往往是长尾的。大部分请求很短但少数请求特别长。这些长请求会占用大量KV Cache而且Decode时间很长导致显存被长期占用拉低整体并发。我在计算器里加了一个长度分布的选项可以选均匀分布、正态分布或者长尾分布。长尾分布下计算器会按P95长度来估算KV Cache而不是平均值。这样算出来的并发数会更保守但更接近真实情况。实测下来用P95长度估算比用平均值估算并发数大概会低20%到30%但这个数字更靠谱。3. 计算器的核心算法从输入参数到并发数字的完整推导3.1 输入参数的设计哪些必须填哪些可以默认计算器的输入项我反复调整过好几版。第一版太复杂填了二十多个参数结果没人愿意用。后来精简到现在的八个核心参数其余用默认值或者自动推断。必填项有六个模型参数量比如7B、13B、70B、量化精度FP16、INT8、INT4、显卡型号A100、H100、A800、H800等、显卡数量、平均输入长度、平均输出长度。选填项有两个互联方式NVLink或PCIe、长度分布类型均匀、正态、长尾。显卡型号这个选项背后其实是一张表记录了每种卡的显存容量、峰值算力、内存带宽、互联带宽。比如A100 80GB SXM显存80GBFP16峰值算力312 TFLOPS内存带宽2039 GB/sNVLink带宽600 GB/s。这些数据来自公开规格我整理成了一张查找表计算器直接查表取值。模型参数量这个选项我预设了常见的几档也支持手动输入。量化精度决定了权重占用的字节数FP16是2字节INT8是1字节INT4是0.5字节。这里要注意INT4量化通常不是所有层都量化embedding层和输出层往往保持FP16所以实际占用会比理论值高一些。我在计算器里加了一个1.1的系数来修正。3.2 显存约束的计算一步步拆解显存约束的计算分四步。第一步算权重占用。权重占用 参数量 × 每参数字节数 × 修正系数。比如7B模型INT4量化参数量7e9每参数字节0.5修正系数1.1那么权重占用大约是3.85GB。第二步算可用KV Cache空间。总显存 显卡数量 × 单卡显存。可用KV Cache 总显存 × 0.8 - 权重占用。这里的0.8是安全余量系数实际使用中可以根据框架不同调整我一般用0.8比较稳。第三步算单路KV Cache。单路KV Cache 2 × 层数 × 注意力头数 × 头维度 × 序列长度 × 字节数。层数、头数、头维度这些从模型参数量推断。比如7B模型通常是32层、32头、头维度128。序列长度取输入长度加输出长度如果是长尾分布取P95长度。第四步算显存能支撑的并发数。显存并发 可用KV Cache / 单路KV Cache。这个数字就是显存维度下的并发上限。这里有个细节如果用了张量并行权重和KV Cache是分散到多张卡上的所以总显存是八张卡之和但每张卡上的KV Cache也是按比例分的。计算的时候直接用总量算就行不用逐卡算因为张量并行下每张卡的负载是均衡的。3.3 算力约束的计算Prefill和Decode分开算算力约束的计算更复杂一些因为要分阶段。Prefill阶段单路请求的Prefill计算量 2 × 参数量 × 输入长度。八张卡的总算力 显卡数量 × 单卡峰值算力 × 有效利用率。有效利用率我取0.35这是实测下来的经验值。Prefill并发 总算力 / 单路Prefill计算量。但这个并发是每秒能处理多少路Prefill实际并发还要考虑请求的到达率。Decode阶段单路请求的Decode计算量 2 × 参数量 × 输出长度。但Decode是逐token生成的每一步的计算量是2 × 参数量输出长度决定了步数。Decode的瓶颈往往不是算力而是内存带宽。每生成一个token要把整个模型权重读一遍。所以Decode的吞吐 内存带宽 / 权重占用。八张卡的总内存带宽 显卡数量 × 单卡内存带宽。Decode并发 总内存带宽 / (权重占用 × 每秒生成token数)。这里每秒生成token数取一个经验值比如20 tokens/s这是用户能接受的交互延迟。如果要求更高比如50 tokens/s那么并发数会相应降低。最后算力并发 min(Prefill并发, Decode并发)。实际取两者的小值。3.4 综合约束与安全余量为什么最终数字要打八折显存并发和算力并发都算出来之后取两者的小值这是理论并发上限。但实际部署中我还会再打一个八折。原因有几个一是请求到达不是均匀的有突发流量二是框架调度有开销不是所有资源都能100%利用三是长尾请求会占用资源拉低整体效率四是需要留一些余量给监控、日志、健康检查等辅助进程。所以最终推荐并发 min(显存并发, 算力并发) × 0.8。这个数字可以作为容量规划的起点实际压测后再微调。我在计算器里把这个八折系数做成了可调项默认0.8你可以根据实际情况改成0.7或0.9。如果你对稳定性要求极高建议用0.7如果追求资源利用率可以用0.9但要承担一定的超载风险。4. 实测验证八张A100跑7B模型计算器和真实压测差多少4.1 测试环境与参数配置光说不练假把式。我拿八张A100 80GB SXM做了一轮实测验证计算器的准确性。测试环境是这样的八张A100通过NVLink全互联单卡显存80GB总显存640GB。模型选了一个7B的开源模型INT4量化权重占用大约3.85GB。推理框架用的是vLLM开了张量并行并行度设为8。请求参数方面平均输入长度512平均输出长度256长度分布设为长尾P95输入长度2048P95输出长度1024。互联方式选NVLink。这些参数填进计算器得到的理论并发是显存并发和算力并发的小值。计算器给出的显存并发可用KV Cache 640 × 0.8 - 3.85 508GB。单路KV Cache按P95长度算序列长度 2048 1024 3072。单路KV Cache 2 × 32 × 32 × 128 × 3072 × 2字节 1.5GB左右。显存并发 508 / 1.5 ≈ 338路。算力并发Prefill阶段单路计算量 2 × 7e9 × 2048 2.87e13 FLOPs。八卡总有效算力 8 × 312e12 × 0.35 8.74e14 FLOPS。Prefill并发 8.74e14 / 2.87e13 ≈ 30路每秒。Decode阶段总内存带宽 8 × 2039 16312 GB/s。权重占用3.85GB每秒生成20 token那么Decode并发 16312 / (3.85 × 20) ≈ 212路。算力并发取min(30, 212) 30路这里我犯了个错误。Prefill并发30路是每秒能处理30路Prefill不是同时并发30路。实际并发还要看请求的持续时间。如果每路请求的总处理时间是10秒那么同时并发可以是30 × 10 300路。所以Prefill并发要乘以平均请求处理时间。修正后的算力并发Prefill每秒处理30路每路处理时间包括Prefill时间和Decode时间。Prefill时间 2.87e13 / (8 × 312e12 × 0.35) ≈ 0.033秒。Decode时间 256 token / 20 token每秒 12.8秒。总处理时间约12.8秒。所以Prefill维度的并发 30 × 12.8 ≈ 384路。最终算力并发 min(384, 212) 212路。综合并发 min(338, 212) × 0.8 169路。4.2 压测结果与计算器的偏差分析实际压测我用了一个开源的压测工具逐步增加并发观察延迟和吞吐。当并发加到150路的时候P99延迟还在可接受范围内大约2秒左右。加到170路的时候P99延迟开始明显上升到3秒以上。加到200路的时候部分请求超时系统开始不稳定。所以实测的稳定并发大约在150到170路之间计算器给出的169路非常接近。这个结果让我比较满意说明计算器的逻辑是靠谱的。偏差主要来自几个方面一是框架的实际利用率可能高于或低于0.35vLLM的优化比较好实际利用率可能到0.4二是长尾分布的实际P95可能比预设的更高三是NVLink的实际带宽可能达不到理论峰值。这些因素综合起来导致实测值比计算器值略低一点但在可接受范围内。4.3 不同量化精度下的并发变化我还对比了不同量化精度下的并发变化。同样的八张A100同样的7B模型FP16量化下权重占用14GB可用KV Cache 640 × 0.8 - 14 498GB。单路KV Cache不变还是1.5GB。显存并发 498 / 1.5 ≈ 332路。算力并发方面FP16下算力利用率更高但权重占用大Decode阶段内存带宽瓶颈更明显。Decode并发 16312 / (14 × 20) ≈ 58路。算力并发 min(Prefill维度, 58) 58路。综合并发 min(332, 58) × 0.8 46路。实测下来FP16下稳定并发大约40路左右和计算器的46路比较接近。可以看到量化精度对并发的影响非常大INT4比FP16的并发高了将近四倍。这也是为什么现在大家做推理服务能量化就量化。INT8量化下权重占用7GB显存并发 (640 × 0.8 - 7) / 1.5 ≈ 336路。Decode并发 16312 / (7 × 20) ≈ 116路。综合并发 min(336, 116) × 0.8 93路。实测大约85路计算器略高估。4.4 互联方式对并发的实际影响最后对比了互联方式的影响。同样的八张A100但换成PCIe版本NVLink带宽从600 GB/s降到PCIe 4.0的64 GB/s。计算器里把互联方式改成PCIe算力并发会大幅下降因为张量并行的All-Reduce通信时间变长有效算力利用率从0.35降到0.2左右。重新计算Prefill有效算力 8 × 312e12 × 0.2 4.99e14 FLOPS。Prefill每秒处理 4.99e14 / 2.87e13 ≈ 17路。Decode阶段通信延迟叠加到每一步每秒生成token数从20降到12。Decode并发 16312 / (3.85 × 12) ≈ 353路。但Prefill维度并发 17 × (0.033 256/12) ≈ 17 × 21.4 ≈ 364路。综合并发 min(338, 353, 364) × 0.8 270路这个数字看起来比NVLink还高明显不对。问题出在通信延迟上。PCIe下每一步Decode都要做All-Reduce通信时间可能比计算时间还长。实际每秒生成token数可能降到5以下。重新算Decode并发 16312 / (3.85 × 5) ≈ 847路但Prefill维度 17 × (0.033 256/5) ≈ 17 × 51.2 ≈ 870路。综合并发 min(338, 847, 870) × 0.8 270路。还是不对。实际上PCIe下张量并行的通信开销会导致有效算力大幅下降而且Decode的每一步延迟都会增加。我实测下来PCIe版本的八卡A100稳定并发只有60路左右远低于NVLink版本的150路。计算器在这个场景下高估了因为我的模型没有充分考虑通信延迟对Decode每一步的影响。后来我在计算器里加了一个通信惩罚系数PCIe下Decode的每秒token数直接打三折这样算出来就接近实测了。5. 计算器使用中的常见误区与我的踩坑记录5.1 把理论峰值算力当成实际算力这是我早期最容易犯的错误。看到A100的312 TFLOPS就以为八张卡就是2496 TFLOPS然后按这个算并发。实际上推理场景下算力利用率能到35%就不错了。Prefill阶段因为可以并行处理多个token利用率高一些能到40%到50%。Decode阶段因为逐token生成利用率可能只有10%到20%。所以算力约束一定要用有效算力不能用峰值算力。我在计算器里把有效利用率做成了可调项默认Prefill用0.4Decode用0.15。你可以根据自己用的框架和模型调整。vLLM的PagedAttention对KV Cache管理比较好利用率会高一些TensorRT-LLM的优化更激进利用率可能更高。但再高也高不过0.6这是物理限制。5.2 忽略KV Cache的碎片问题KV Cache不是连续分配的尤其是请求长度不一的时候显存里会出现大量碎片。vLLM用PagedAttention把KV Cache分成固定大小的块大大减少了碎片但并没有完全消除。实际可用的KV Cache空间可能比理论值低10%到15%。我在计算器里加了一个碎片系数默认0.9。也就是说理论可用KV Cache还要再打九折。这个系数在请求长度分布比较均匀的时候可以设高一点比如0.95在长尾分布下要设低一点比如0.85。5.3 用平均长度估算长尾场景前面提过用平均长度估算并发在长尾场景下会严重高估。我踩过这个坑压测的时候用平均长度512算出来能跑300路结果实际生产环境里有少量请求输入长度到了4096这些请求一进来显存瞬间被吃掉一大块其他请求就开始排队延迟飙升。后来我改成用P95长度估算并发数降到200路左右但稳定性好多了。计算器里现在默认用P95长度你也可以手动切换到平均值但我不推荐。5.4 忘记预留系统开销显存不是全部给模型的。CUDA上下文、框架本身、通信缓冲区、监控进程这些都要吃显存。我一般预留15%到20%。如果你用的框架比较重比如带了很多插件和监控预留25%也不过分。计算器里默认预留20%你可以根据实际情况调整。还有一个容易忽略的是多卡并行的时候每张卡上都要加载一份完整的CUDA上下文和框架代码这些开销是乘以卡数的。八张卡的系统开销可能比单卡多出好几GB。所以预留比例要按总显存算不能按单卡算。5.5 并发数不是越高越好最后一个误区是盲目追求高并发。并发数上去了单路延迟往往会下降。因为资源是共享的并发越高每路分到的算力和带宽越少。用户能接受的延迟是有限的如果为了追求并发导致延迟超标反而得不偿失。我一般会设定一个延迟目标比如P99延迟不超过2秒然后在这个约束下找最大并发。计算器里可以输入延迟目标它会反推在这个延迟下的最大并发。这个功能比单纯算并发上限更实用。6. 从计算器到生产部署容量规划的落地经验6.1 计算器结果怎么用从数字到采购决策计算器给出的并发数最直接的用途是指导采购和租用决策。比如你算出来八张A100能跑150路并发而你的业务峰值需要300路那么你就需要十六张卡或者换用更大的卡。如果预算有限可以考虑量化到INT4这样同样的卡数能跑更多并发。另一个用途是排期。如果你知道业务增长曲线可以提前算好什么时候需要扩容。比如现在100路并发八张卡够用但预计三个月后到200路那么现在就要开始规划第二批卡了。GPU的采购和上架周期不短提前规划能避免临时抱佛脚。6.2 压测验证计算器只是起点计算器的结果一定要用压测验证。我一般会按计算器结果的80%开始压测逐步增加并发观察延迟、吞吐、显存占用、GPU利用率。当延迟开始明显上升或者显存占用超过90%就是接近上限了。压测的时候要注意请求长度分布要模拟真实场景。如果只用固定长度压测结果会偏乐观。我一般会准备几组不同长度分布的请求分别压测取最差情况作为容量规划依据。6.3 动态调整生产环境下的并发控制生产环境不是静态的。白天流量高晚上流量低工作日高周末低。所以并发控制要动态调整。我一般会在网关层做限流根据当前GPU利用率和延迟动态调整允许的并发数。当延迟上升时主动降低并发保证已接入请求的体验。这个动态调整的逻辑可以基于计算器的模型来实现。实时采集GPU利用率和延迟反推当前的有效并发然后和计算器的理论值对比判断是资源不够还是请求特征变化了。如果是资源不够就扩容如果是请求特征变化就调整计算器参数。6.4 多模型混部的并发分配实际生产环境往往不是只跑一个模型。可能有多个模型大小不同请求特征不同。这时候并发分配就复杂了。我的做法是给每个模型单独算并发然后按优先级分配GPU资源。核心模型分配足够的卡保证并发边缘模型用剩余的卡能跑多少跑多少。如果多个模型共享GPU可以用MPS或者时间片调度。但共享会带来干扰一个模型的突发流量可能影响另一个模型。所以关键模型最好独占GPU非关键模型可以共享。6.5 成本优化租卡还是买卡计算器帮你算最后说一个实际的问题租卡还是买卡。计算器可以帮你算这笔账。如果你算出来需要八张A100买卡的成本是固定的租卡的成本是按小时的。你可以根据业务的小时流量曲线算出租卡和买卡的成本平衡点。如果流量稳定且高买卡划算如果流量波动大租卡更灵活。我自己的经验是核心业务买卡弹性业务租卡。计算器给出的并发数可以帮你判断需要多少张卡从而算出买卡和租卡的成本。这个数字比拍脑袋靠谱多了。7. 我在实际使用中总结的几条硬核经验计算器做出来之后我自己用了大半年也推荐给了几个朋友用。踩过的坑、修正过的参数、验证过的场景加起来有不少心得。挑几条最实用的分享出来。第一条显存永远是第一约束。在大多数推理场景下显存比算力更早成为瓶颈。所以优化并发优先从显存入手量化、PagedAttention、KV Cache压缩这些手段比堆算力更有效。我见过太多人一上来就想着换更好的卡其实把量化做好同样的卡能多跑两三倍并发。第二条Decode阶段的内存带宽是隐形天花板。很多人算并发只看算力忽略了内存带宽。Decode阶段每生成一个token都要读一遍权重内存带宽决定了理论上的最大token生成速度。八张A100的内存带宽加起来是16TB/s左右看起来很大但除以权重占用再除以每秒token数剩下的并发空间其实有限。所以模型越大Decode阶段的内存带宽瓶颈越明显。第三条长尾请求要用单独的资源池。如果业务里有少量超长请求不要和普通请求混在一起跑。单独给长尾请求分配一个小的资源池用单独的模型实例处理。这样普通请求的并发不会被长尾请求拖累整体资源利用率更高。第四条计算器参数要定期校准。框架在更新模型在迭代硬件在变化计算器的参数不是一成不变的。我一般每季度会重新压测一次校准有效利用率、碎片系数、通信惩罚系数这些参数。校准之后计算器的准确度能保持在10%以内。第五条并发数要留缓冲。计算器给出的数字是理论值实际部署时建议留20%到30%的缓冲。因为生产环境的请求特征比测试环境更复杂突发流量、重试、异常请求都会占用额外资源。缓冲留够了系统才稳。这个计算器我还在持续迭代后面打算加上多模型混部、动态批处理、投机解码这些场景的支持。如果你也在做推理服务的容量规划欢迎一起交流。核心思路就是把显存、算力、带宽、请求特征这四个变量拆开算再综合取小值最后打安全余量。这个框架适用于大多数推理场景你可以在它的基础上根据自己的业务特点调整参数。