ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

MindIE Benchmark实战:服务化推理压测与性能分析指南

MindIE Benchmark实战:服务化推理压测与性能分析指南 进昇腾推理这条线之前我做性能压测的习惯很简单模型加载到设备上脚本灌一批数据看平均时延和吞吐差不多就完事了。等接手服务化MindIE推理项目要把模型封装成常驻服务对外提供推理能力之后我发现之前那套做法压出来的数据根本没法回答线上值班同学问我的问题服务到底能扛多少并发P99是多少换一个batch策略会怎样这些问题只能靠专门针对服务化场景设计的MindIE Benchmark工具来回答。这篇文章把我从接触这个工具到最终把它落到日常迭代流程里的完整经验写出来。内容不追求跑分好看重点是讲清它到底怎么用、测出来的数字怎么读、哪些坑会误导结论。1. 为什么服务化之后原先的离线Benchmark思路全部失效1.1 离线推理和服务化推理性能观测的根本差异离线推理的压测本质上是在测引擎本身。请求一条条进来模型算完返回测的是纯计算吞吐和单次延迟。服务化推理不一样模型封装成常驻服务之后请求要经过网络传输、HTTP/gRPC解包、调度排队、动态batch聚合、推理引擎执行、响应序列化再传回去。任何一个环节抖动用户看到的就是延迟变高或者请求失败。我用一个餐厅的例子给团队解释过。离线benchmark就像后厨单独炒菜计时一道菜多久能出锅服务化benchmark则是客人在门口排队从点菜到菜上桌要多久以及一晚上最多能翻多少台。翻台率服务吞吐和上菜时间端到端延迟才是线上真正关心的单道菜炒得再快客人多了照样排队。这也是为什么我把精力转到MindIE Benchmark工具上——它测的是整个服务链路的综合表现而不是单一计算环节的极限速度。1.2 服务化压测真正想回答的三个问题做服务化压测要回答的问题跟离线压测完全不一样。第一个是服务稳定运行的情况下最多能接到多大的流量。第二个问题是当流量逐渐上涨端到端延迟会怎样劣化是平缓上升还是突然断崖。第三个问题是当前配置下NPU算力、显存、CPU这些资源有没有被用到位。这三个问题离线benchmark都回答不了。所以我用MindIE Benchmark工具来做三件事做负载注入、做指标统计、做可供多次对比的基准记录。它的定位不是帮我把某个并发下的响应时间测漂亮而是帮我画出一条完整的服务能力曲线。1.3 为什么不能直接拿curl脚本或者ab来压刚开始我也偷懒写了个多线程curl轮询服务地址。结果压出来的数据乱七八糟一方面curl没有合理的连接复用和异步控制客户端机器自己先成了瓶颈另一方面没有统一的输入输出长度控制请求内容长短不一模型的处理时间浮动很大统计出来的指标根本不可比。ab这类通用HTTP压测工具更不适用。它擅长压静态页面不会按模型推理特征构造请求更不会统计TTFT和TPOT这些生成式模型特有的指标。MindIE Benchmark工具至少在请求组织、并发模型和指标统计上跟服务化推理场景对齐了。这也是我后来坚持用它做回归测试的原因同一个工具、同一套参数条件下出来的结果才有可比性。2. MindIE Benchmark工具的角色定位与架构2.1 工具到底压的是什么从客户端视角出发严格说MindIE Benchmark不是服务端代码而是一个独立运行的压测程序。它把自己当成普通调用方按照设定好的并发数持续往MindIE Serving服务发送推理请求然后记录每一次请求的关键时间点。这样的设计有一个好处它测出来的不是纯推理耗时而是用户真正能感知到的端到端耗时。整个数据流大致是压测程序按固定并发数发起请求网络传输到服务端MindIE Serving按模型和batch策略调度推理响应原路返回压测程序记录耗时和结果。我们不需要关心服务端内部每个阶段分别花了多少毫秒工具先保证外部观测口径是正确的之后再配合服务端日志定位细节。2.2 不能只看吞吐服务化压测的指标群服务化压测工具输出的指标很多别只盯一个吞吐。下面是我在实际工作中最常看的指标指标含义什么时候最关键吞吐量每秒完成请求数或每秒处理token数评估服务容量上限TTFT首token延迟流式接口从请求发出到第一次返回耗时对话式、流式输出场景TPOT每个输出token的平均生成耗时生成式模型输出速度端到端延迟完整请求从发出到收到全部结果耗时非流式推理、离线批量任务P95/P99排在95%/99%位置的延迟值发现长尾问题成功率成功响应占比判断服务是否健康为什么生成式模型要把TTFT和TPOT分开因为用户在聊天界面的第一段文字出来快不快和后面每秒蹦多少字体验上是两回事。人感知的是首屏等待和后续滚动速度这两个指标单独记录才能定位到具体瓶颈。2.3 工具能不能模拟真实流量是唯一判断标准判断这类工具值不值得用我只有一个标准它能不能模拟真实流量。真实流量不是一次性把所有请求灌进去而是同一时刻有N个客户端在发请求每个请求又有不同的到达间隔。好的Benchmark工具会维护一个并发池每个请求完成后立即补一个新请求使服务端始终维持固定并发压力。这就是常说的open-loop和closed-loop的区别具体原理不展开但MindIE Benchmark这种方式更适合服务化压测。另外工具还应该允许设置输入长度和输出长度。一个只有几十个token的请求和一个要生成上千token的请求压出来的数据完全不是一回事。没有这个能力所有数字都只能算“实验噪声”。3. 动手前必须准备的环境与部署要点3.1 版本匹配是第一个坑MindIE和CANN的版本匹配关系很严格。碰到服务起不来先去查版本。我一般会先用npu-smi info确认NPU驱动和固件版本再翻MindIE安装目录下的版本文件。具体路径以你用的安装版本为准有的是version.cfg有的是version.info。记住一个原则驱动、固件、CANN、MindIE四个版本要在同一个兼容矩阵里。npu-smi info # 检查NPU设备状态和驱动信息版本不对最常见的表现是服务进程能起但模型加载到NPU上报错或者推理时显存报错。不要在这种状态下直接压测数据全是垃圾。我踩过的坑是驱动版本旧了一版模型单帧推理看着正常一旦并发超过4就频繁报显存越界排查了两天才发现是版本不匹配。3.2 把模型跑成服务MindIE服务化部署的模型需要先转换成MindIE能加载的格式。以PyTorch模型为例我会先导出为ONNX再用MindIE的建模工具转成.mindir。转换时要注意把动态shape的维度放开或者至少支持你压测要用的几种shape否则服务化运行时会反复重新编译或者直接失败性能惨不忍睹。服务配置会涉及模型路径、设备ID、最大batch、最大序列长度等。不同版本的字段名会有差异但思路是固定的下面是一个简化版思路{ model_config_list: [ { model_name: text_generation, model_path: /data/mindie_models/text_generation.mindir, device_id: 0, max_batch_size: 32, max_seq_len: 2048 } ] }启动服务这一步各个版本的命令差异更大有的是可执行文件有的是python脚本。但核心都是把配置路径传进去然后保证服务端口不冲突。我会先确认端口状态ss -lntp | grep 8080 # 如果不是8080就替换成实际端口3.3 用健康检查接口确认服务状态服务启动成功不等于可以压测。我曾犯过一个错误看到进程起来了就去跑Benchmark结果前几十个请求全部超时因为模型还在预加载。所以压测前一定要做一次健康检查。常见方式是发一个最小的推理请求确认返回码正常且输出内容合理curl -X POST http://127.0.0.1:8080/v1/chat/completions \ -H Content-Type: application/json \ -d {model: text_generation, prompt: hello, max_tokens: 16}如果这个请求能在合理时间返回我再等几秒让服务稳定然后进入压测。另外顺手看一眼NPU状态确认显存和利用率没有异常波动npu-smi info watch -c 30这一步是排除环境干扰的关键。如果压测过程中NPU利用率一直很低那问题多半不在Benchmark工具而在请求没有真正打进去或者服务端调度配置不对。4. 用MindIE Benchmark跑一轮完整压测4.1 配置一次压力场景的字段说明MindIE Benchmark的参数形式在不同版本里不太一样但核心配置项是相通的。我常用的参数大概长这样benchmark_client \ --server 127.0.0.1:8080 \ --model text_generation \ --protocol grpc \ --concurrency 16 \ --requests 2000 \ --warmup 100 \ --input-len 128 \ --output-len 128 \ --timeout 30000我一个个解释。server是服务地址protocol用grpc还是http要跟服务端保持一致。concurrency是同时挂着的请求数量不是每秒请求数它决定服务端同时承受多少路压力。requests是总请求数给太少结果不稳定给太多又浪费时间。warmup用于把模型和服务预热起来这段数据不会进最终统计。input-len和output-len直接控制请求内容长短这对生成式模型尤其重要。timeout是单请求超时阈值超过这个时间会被记为失败。这里最容易被忽略的是concurrency和requests的关系。很多新手把concurrency写成100requests只写100以为打了100个并发实际上只发了100个请求服务压力还没起来就结束了。正确做法是让requests远大于concurrency至少是5到10倍才能形成稳定的压力流。4.2 启动压测的完整流程我的标准流程分三步。第一步先做冒烟测试用concurrency1requests10请求长度跟真实场景一致确认链路通和延迟数量级符合预期。第二步做小压力验证用concurrency4requests100看结果是否稳定顺便观察服务端日志有没有异常。第三步才真正跑梯度压测比如把concurrency设为1、4、16、32、64分别跑一遍每轮记录结果。这样能画出一条完整的性能曲线而不是只拿到一个孤零零的数字。压测过程中我会开着三个终端一个盯Benchmark进度一个盯NPU状态一个盯服务端日志。看到日志里大量timeout或error时马上停掉不要等一轮跑完浪费时间。有时候问题很明显是配置错误继续跑下去只会浪费时间和算力。4.3 单轮压测的产物和标准输出一轮跑完后工具会输出一份结果摘要。不同版本的输出格式不一定一样但关键指标大致如下Concurrency: 16 Requests: 2000 Success rate: 100.00% Throughput: 128.5 req/s, 16448 tokens/s Average latency: 124.6 ms P50: 112.3 ms P95: 198.7 ms P99: 245.2 ms TTFT avg: 32.1 ms TPOT avg: 12.4 ms/token我特意说“大致”是因为我见过有的版本只输出req/s和平均延迟有的版本会给出更细的分位统计。这不重要重要的是你会读这些数。Success rate到不了100%要警惕P95和P99的差距如果特别大说明延迟长尾明显可能是网络抖动、显存换页或者服务端排队不均。5. 输出结果怎么解读才不会被指标骗5.1 吞吐和时延的跷跷板服务化压测最常见的误区是拿一组并发下的数据说服务性能好。实际上服务的吞吐和时延是一对矛盾。刚开始并发上升时吞吐快速增长时延增加得不多继续加并发吞吐增速放缓时延开始明显抬头再往后排队占满吞吐甚至下降时延和超时同步飙升。下面这组是示意数据真实数据可能不像这样平滑但趋势一定相似并发数吞吐(req/s)P95时延(ms)成功率备注11095100%基线438112100%线性增长16120220100%接近拐点3215541099.9%吞吐高但延迟超标6412898098.2%过载如果只看吞吐32并发是峰值如果业务要求P95小于300ms那16并发才是容量上限。压测不是找一个“最优并发”而是找“在满足SLA的前提下服务最多能承载多少并发”。5.2 从压测曲线找服务的稳定边界我建议每次梯度压测都做一张类似的表然后找两个拐点。第一个拐点在吞吐上并发继续增加吞吐不再明显增长甚至开始掉头说明服务已经到处理极限。第二个拐点在延迟上P95或P99开始偏离线性增长说明排队效应已经占据主导。最稳的是把这两个拐点里更靠前的那一个作为容量边界再留20%到30%余量。比如压测结果显示16并发P95是220ms32并发P95到了410ms线上实际高峰想控制在P95小于300ms我会把部署容量按16并发的70%到80%来规划而不是按32并发。因为压测环境跟生产环境有差异比如真实请求的输入长度波动、突发流量、日志和监控开销都会让服务比压测结果差一些。5.3 识别异常数据的几种信号读结果时我会先扫一遍是否出现这几个信号成功率跌到99.9%以下哪怕只超时几次也要排查原因可能某个并发下的batch过大。P99和P50差距超过5倍说明有严重的尾部延迟别用平均延迟糊弄过去。服务端日志大量出现同一个错误码基本可以确定是配置问题不是负载问题。吞吐随并发增加不升反降先查NPU利用率利用率100%说明算力打满利用率不高说明服务端有锁、串行化或CPU瓶颈。这些信号能帮你在下一轮压测前做出调整而不是对着一个平均延迟数字发呆。6. 实测路上的坑和调优经验总结6.1 最容易误导结论的五个坑第一个坑是不预热直接压。模型首次推理要完成权重加载、图优化、显存分配延迟会偏高。我不止一次看到有人把冷启动的慢当成服务能力不足然后在配置上乱改一通。第二个坑是压测机跟服务部署在同一台机器。压测程序本身要吃CPU和内存并发一高服务端资源被抢测出来的数据既不是服务端能力也不是客户端能力两头都不靠谱。第三个坑是固定并发下用长度不一致的请求。真实场景里请求长度确实有波动但压测是为了比较不同配置之间的差异必须先控制变量。请求长度一乱时延波动会被错误地归因到服务端。第四个坑是超时阈值设置太短。长输出场景下一个请求可能正常要跑几秒钟你把timeout设成1秒必然会得到一堆假超时。第五个坑是只盯平均延迟。平均延迟被少数小请求拉低掩盖了长尾的大延迟线上事故往往就是从P99恶化开始的。6.2 让压测结果更稳定的实操手法第一固定输入输出的长度和内容。虽然真实场景里请求长度千变万化但压测是为了比较不同配置之间的差异必须控制变量。我会尽量用同一批prompt模板只是改变长度。第二每档并发跑三轮取中位数或最接近中位数的一轮。第三记录NPU利用率和HBM占用作为辅助指标一起看。第四压测开始前等待服务完全就绪warmup请求跑到没有timeout再正式计时。还有一个容易被忽略的点检查服务端的日志级别。如果MindIE Serving开启了全量调试日志磁盘和CPU开销会明显抬高延迟。压测时把日志级别调回warning甚至error测出来的才是接近生产的性能。6.3 从Benchmark到容量规划的建议最后的建议是把Benchmark当回归工具而不是当擂台赛。不必追求某个数字比别的团队高“胜率”好看没有意义重要的是每次调整后有据可查。给每个模型维护一份性能基线里面至少包含并发梯度、P95、P99、成功率、NPU利用率这几行数据。以后模型版本升级、batch策略调整、MindIE配置改动都先跑一遍同样的Benchmark看基线是否漂移。如果有人问我某个模型能不能上线我会先问他三个问题SLA里P95要求多少毫秒高峰期每秒请求数大概多少请求平均输入输出长度是多少这三个问题定了再翻Benchmark基线就能给出一个相对靠谱的容量建议。我现在的习惯是每台服务上线前先在测试环境跑一轮五档并发的基准压测把吞吐、P95、成功率三个数存档。以后无论是模型换版本、调整batch参数还是改MindIE配置都先拉一份新数据对比。只有这些数字波动在合理范围内我才敢跟业务方说这版可以上。别把Benchmark工具当跑分玩具它本质上是一把尺子尺子越稳你心里越有底。
返回列表