说实话,接到这个任务的时候我心里是有准备的,但真正跑完这七天,还是有很多没想到的地方。国产算力集群的稳定性测试,和以往在常规GPU集群上做压测,完全是两种体验:工具链要自己拼、监控要自己搭、驱动日志要自己啃。这篇就把我们这次7×24小时压测的完整过程写出来,从指标设定、工具选型、执行编排到问题排查,希望能给正在做或者准备做国产算力集群稳定性测试的朋友一些参考。
1. 国产算力集群稳定性测试到底在测什么
1.1 为什么“能跑通”和“扛得住”是两回事
很多团队对稳定性测试有个误解,觉得功能测试都过了,接口也通了,模型推理结果也正确,那系统就是稳定的。但长期压测要暴露的恰恰是功能测试覆盖不到的那类问题:性能衰减、资源泄漏、累积性故障。
拿我们这次测试的大模型推理链路举例。功能测试阶段,一条请求进来,模型正常返回,耗时200毫秒,看起来一切正常。但当你用固定并发持续压测几小时后,问题就开始冒头:显存碎片越来越多,KV Cache的分配策略开始退化,算子调度出现间歇性等待,最终表现就是QPS从最初的900一路跌到350,响应时间的P99从300毫秒涨到3秒。这种问题是功能测试无论如何都发现不了的,因为它不是“坏了”,而是“慢慢变差了”。
所以7×24小时长稳测试关注的核心是三件事:性能是否随时间衰减、是否存在累积性资源泄漏、故障发生时系统能不能自愈或被快速拉起。
1.2 国产算力集群和常规GPU集群的差异决定了方案不能照搬
这句话我说得很直白:如果你之前做过GPU集群的压测,然后把那套方案原封不动搬到国产算力集群,大概率会踩坑。
第一个差异是监控体系。常规GPU集群有DCGM、nvtop这些成熟工具,指标采集开箱即用。国产加速卡这边,不同厂商提供的能力不一样,有的有类似DCGM的exporter,有的只给一个CLI工具,指标得自己解析,甚至有些功耗、温度、显存利用率的核心指标要自己写脚本去读系统接口。
第二个差异是软件生态。驱动和运行时SDK的API命名、日志规范、错误码定义,各家有各家的风格,网上能搜到的资料也少。遇到一个奇怪的错误码,可能就要翻厂商SDK头文件或者提工单才能确认含义。
第三个差异是互联拓扑。国产集群的集合通信性能和卡间互联拓扑,和NVIDIA的NVLink+InfiniBand方案差别很大。全链路压测的时候,多卡并行推理的通信瓶颈会出现在意想不到的地方,这直接决定你要不要调整请求分发策略。
也就是说,做国产算力集群压测,不能只盯着业务层指标,必须有一套覆盖硬件健康状态、驱动日志、通信库状态的监控方案,这些在后面会详细讲。
2. 压测目标与指标基线:动手之前先想清楚三个问题
2.1 并发数怎么确定:阶梯加压才是正路
我最担心看到的就是有人拍脑袋定并发数,比如“线上有500个用户,那就压500并发”。这个思路的问题在于,并发数根本不是一个静态数值,它取决于系统资源、业务复杂度、模型推理时长。拿大模型推理来说,一个请求要占用显存里的KV Cache空间,并发数太高直接OOM,并发数太低又跑不满算力,这个最优值必须在压测中找出来。
我们用的是阶梯加压法,这个过程也是热词里经常提到的“怎么确认系统并发数”的实操答案。具体分三步:
第一步,从1个并发开始,每5分钟增加10个并发,持续观察TPS(每秒事务数)和响应时间的变化。最开始TPS会随并发线性增长,增长到某个点之后,TPS的增长幅度会明显放缓,这个拐点就是系统的软极限。
第二步,在拐点附近做细粒度加压,比如每次只加2个并发,把拐点的位置确认到尽量精确。这个数值你后面定目标并发时要用。
第三步,继续加压到系统开始大量报错或者P99响应时间急剧恶化,记下这个饱和点。这个点的价值是让你知道系统离崩溃还有多远。
最后,7×24小时长稳测试的目标并发,建议定在拐点值的70%到80%,而不是顶着饱和点跑。原因很简单:长稳测试的目的是暴露隐患,不是证明系统能扛住极限。你顶着极限跑7天,大概率第一天就把集群跑挂了,什么都验证不了,还得花两天恢复环境。
2.2 指标体系:不能只盯QPS和CPU
长稳压测的指标要分成四层来看,缺一层都容易出盲区。
- 业务层:TPS、响应时间P50/P95/P99、错误率、超时率。这是最直观的,也是给老板看的核心数据。
- 系统层:CPU使用率、内存占用、磁盘IO和磁盘剩余空间、网络带宽和连接数。重点是看有没有缓慢增长的趋势。
- 硬件层:芯片温度、功耗、显存占用、ECC纠错次数、风扇转速、PCIe链路错误计数。这些指标在普通压测里经常被忽略,但长稳测试里恰恰是关键。芯片温度受机房空调策略影响,夜间温度波动可能触发降频;显存占用如果随时间单边上涨,基本就能断定有显存泄漏。
- 框架层:这是大模型链路特有的,包括排队请求数、实际Batch Size、首Token延迟(TTFT)、Token间延迟(TPOT)、KV Cache命中率。
我们可以用京东那种削峰填谷的比喻来讲指标趋势:QPS可能一直在波动,但波动不能有单边下行的趋势;显存占用可以有波峰波谷,但谷底必须回到初始水平;温度可以随负载变化,但变化幅度不能超过硬件规格。
3. 压测工具选型与脚本设计:从JMeter到k6再到自研中间层
3.1 JMeter做协议层压测的边界在哪里
JMeter是绝大多数人接触压测的第一个工具,它的生态确实完善,HTTP、WebSocket、gRPC都有对应的Sampler,而且有图形界面,配置线程组加监听器就能跑。简单场景下,JMeter压测的基本步骤就是:创建线程组、配置并发数和循环次数、添加HTTP请求Sampler、添加聚合报告和结果树、启动并查看结果。这套流程对普通Web接口完全够用。
但到了大模型推理链路,JMeter的短板非常明显。首先是资源开销,JMeter本身是Java写的,单机模拟高并发时JVM内存和GC开销都很大,跑7×24小时还要考虑JMeter自身会不会先挂掉。其次是协议支持,大模型推理走的是流式响应,客户端要解析SSE(Server-Sent Events)数据流,还要处理多轮对话中动态拼接的Prompt,JMeter写这些逻辑非常别扭。第三是分布式压测的数据汇聚,用JMeter分布式模式跑长稳,Agent的角色胜率要看网络可靠性,Agent挂掉一个,压测数据就不连续了。
所以我们的定位是:JMeter可以用来做网关层的短时专项压测,比如验证某个API的限流配置是否正确,或者压测鉴权服务的并发上限。但全链路长时间压测,我们换成了别的方案。
3.2 k6在长稳场景下的优势
k6是我们这次重点使用的开源工具,它在长稳场景下的优点值得一说。第一,k6的并发模型基于Go协程,单机支撑的并发数远超JMeter,而且自身资源占用很低,跑7天基本不操心。第二,脚本用JavaScript编写,写起来比JMeter的XML配置直观得多,而且支持模块化组织场景。第三,内置的阈值触发机制很适合长稳测试——你可以设定“错误率连续5分钟超过5%就自动停止”,这在夜间无人值守时太重要了。
k6还有一个好处是结果导出方便,可以一键导出到Prometheus远程写入端点,或者通过StatsD协议推送到InfluxDB,省去自己写采集脚本的麻烦。我们用k6做了网关层的长稳压测,脚本里通过stages配置渐进式加压,比如前30分钟从0升到目标并发,然后维持48小时,再逐步降为0,整个加压曲线在Grafana里看非常清晰。
3.3 大模型链路全量压测为什么必须自研中间层
虽然k6很好用,但覆盖不了全链路。大模型推理的请求和普通HTTP请求最大的区别是:请求内容动态变化,Prompt长度随机、输出长度随机、多轮会话有上下文依赖。用压测工具硬编码URL和参数,根本模拟不出真实业务形态。
我们的做法是自研了一个基于Python asyncio的压测客户端。这个客户端做的事情是:从Kafka回放线上真实日志流量,每条请求根据业务分布动态生成不同长度的Prompt,随机模拟多轮对话,通过流式接口读取结果并校验响应内容摘要。它本身也内置了并发控制模块,可以在运行过程中动态调整并发数,不需要重启任务。
这里要澄清一个点:不是说JMeter和k6没用,而是它们属于组件级工具,适合定点验证,全链路压测必须要有能够模拟真实流量特征的“流量产生器”。这个中间层是压测方案里投入成本最高的部分,但也是价值密度最高的部分。
4. 7×24小时长稳压测的完整执行过程
4.1 压测前的环境清洗与基线验证
长稳压测最忌讳的就是在环境不干净的时候直接开跑。我们的准备流程是这样的:
第一步,确认集群上没有其他任务。这一点容易忽视,很多集群有自动调度系统,你以为这块区域闲置了,结果半夜调度器又塞了一个训练任务进来,压测数据全废了。我们是在测试开始前手动检查了集群的作业列表,并且在测试期间给这个队列加了作业提交白名单。
第二步,统一镜像和权重,记录启动日志。确保每台节点上跑的推理服务镜像相同、模型权重一致、配置文件版本锁定。这个步骤看起来很基础,但真出问题的时候,你会庆幸自己留了基线。
第三步,先跑30分钟短时压测做校准。把目标并发先拉起来,看当前系统的QPS、响应时间、错误率是否和之前小规模测试的结论一致。如果差距超过10%,先排查环境差异,不要带着问题启动长稳。
第四步,检查时间同步。所有节点统一的NTP时间校准,这点长稳测试里特别关键。7天的日志如果时间基准都不一致,问题定位时看谁先谁后都看不出来。
第五步,检查日志轮转和磁盘空间。7天跑下来,推理服务的access log、错误日志、监控agent的采集日志,加起来可能塞满几百G。我们提前配置了logrotate策略,确保日志不会写满磁盘导致服务异常。这一步我在多个项目里都踩过坑,建议当成SOP固定下来。
4.2 分四个阶段推进的编排逻辑
7×24小时不是简单地把压测工具开着跑一天,而是分成四个阶段,每个阶段有明确的验证目标。
阶段一(第1到12小时):1倍目标并发,观察各层指标是否平稳。这个阶段的主要任务是建立正常基线,并把监控告警配置调准确。如果前期有漏配的指标,前12小时还能补救。
阶段二(第12到48小时):把并发提到目标值的1.2倍,做超负荷试探。这个阶段是资源泄漏最容易暴露的时间窗。以显存为例,如果存在泄漏,12到48小时内曲线会呈现明显的阶梯式上升。为什么要加压到1.2倍?因为有些泄漏在低负载下不明显,只有在高压力下才会因为资源分配更加频繁而显现。
阶段三(第48到120小时):回到目标并发稳定运行,重点观察夜间环境变化的影响。机房的空调策略一般不会为压测单独调整,夜间的温度波动、供电波动都会在这时候体现出来。我们这次就在这个阶段抓到了一个小问题:某一排机柜在凌晨温度偏高,导致部分芯片小幅降频,虽然没影响业务,但确认了冷却系统的余量不足。
阶段四(第120到168小时):混合场景冲刺,模拟业务高峰和低峰交替,并在低峰时段插入突发流量脉冲。这个阶段验证的是系统应对真实业务节奏的能力,而不是均匀载荷下的稳定性。
4.3 七天里真实遇到的三个典型问题
第一个是显存泄漏。现象从第二个阶段开始:QPS从900逐步回落到350,但奇怪的是,芯片利用率和显存占用一直往上走。我们在国产加速卡的监控工具里看到显存占用率的曲线呈现锯齿状上升,每处理一批请求,释放的显存比分配的要少一点。排查思路是先定位是哪个模块泄漏:用详细的性能分析工具抓算子级别的显存分配,最终定位到一个自定义的归一化算子没有释放中间张量。修复验证的方法是连续观察48小时,确认显存曲线恢复平稳。
第二个是句柄耗尽。跑到第60小时左右,新请求开始大量连接超时,日志里出现了很多包含“too many open files”的报错。我们先用lsof统计了进程的文件句柄数,发现它从初始的1500涨到了接近系统上限65535。根因是推理服务的HTTP客户端在长时间运行后,健康检查逻辑存在缺陷:每次探测都新建连接,但对旧连接只做了关闭标记,没有真正调用close。长稳测试最大的价值就在这里:小程序在功能上完全正确,但长时间运行就会让资源耗尽类问题暴露。
第三个是加速卡在运行72小时后被系统自动隔离。现象是某台节点的算力单元从集群状态中消失,整体QPS瞬间下降了15%,但服务没有完全中断。通过厂商提供的固件日志排查,确认是卡的温度过高触发了硬件保护机制,保护机制主动把算力单元置为不可用状态,等待冷却后重新初始化。根因是这排机柜的散热策略配置不当,机柜尾部热空气回流严重。调整方案包括修改空调出风策略、增大机柜风扇转速、调低温度保护的触发阈值,并在监控里新增了卡温度变化率指标,温度在5分钟内上涨超过15度就提前告警。
这三个问题有一个共同特点:都不是“瞬间崩溃型”故障,而是“缓慢劣化型”故障,恰好是7×24小时长稳测试必须抓的问题。
5. 监控告警与日志收集
5.1 监控体系怎么搭才能覆盖全维度
监控是长稳压测的生命线,不是可选项。我们的监控体系包含三层。
底层是数据采集。Prometheus作为核心时序数据库,业务指标通过自研压测客户端的Prometheus端点暴露,系统指标用node_exporter采集,硬件指标用国产加速卡厂商提供的exporter采集。这里强调一句:国产卡的硬件指标尽量用厂商原生的exporter,不要自己写脚本去解析系统接口,因为不同版本的固件输出的格式可能变化,你会花大量时间在调试采集程序上。
中间层是告警规则。我们建了一套分级告警规则,核心指标包括芯片温度、显存占用率、QPS趋势、P99响应时间、错误率。所有告警都配置了持续时间条件,比如错误率必须连续5分钟超过5%才触发,避免瞬时抖动导致的告警风暴。
上层是可视化看板。Grafana看板拆成两页:第一页是业务总览,包含QPS、错误率、响应时间分布,适合给团队和管理层看;第二页是硬件健康矩阵,把每台节点的温度、功耗、显存、ECC错误用热力图方式展示,一眼能看出哪台机器有异常趋势。
5.2 夜间告警分级与无人值守策略
长稳测试大概率会跨多个夜晚,如果每个告警都要打电话叫醒人,团队撑不过第二天。我们把告警分成了三个等级:
- P0级:服务完全不可用、加速卡批量掉线、整节点宕机。这类必须立刻电话通知,因为如果不及时处理,后续几十个小时的压测数据都会失效。
- P1级:性能指标大幅劣化(比如QPS下跌超过50%)、显存占用持续增长接近阈值、节点温度连续多次超过警告线。这类要求1小时内确认,值班人员需要起来看一眼监控。
- P2级:单次抖动、指标小幅波动、单卡温度短暂偏高。这类只记一条日志,第二天复核,不通知任何人。
想要做到夜间安心,额外有两个小工具很值得做。一个是自动巡检脚本,每15分钟检查一次核心指标并生成摘要日志,异常时自动抓取相关日志片段保存到临时目录。另一个是看门狗脚本,监控压测客户端本身是否存活,如果压测进程挂了,自动重启任务并记录中断时间。长稳测试里最有挫败感的事就是压测工具在凌晨4点挂了,早上9点才发现,7个小时的数据全白费。
5.3 日志收集的三个注意点
日志在长稳测试中的价值比一般测试更大。我们在日志收集上犯了几个错误,花了代价才修过来,这里直接说结论:
第一,所有节点和组件的日志时间戳必须统一格式,统一时区,毫秒级精度。第二,集中式日志系统(比如ELK或Loki)必须在压测前就部署好并验证可用,不要压测到一半发现日志采集进程内存溢出挂了。第三,关键问题段落的原始日志要保留原始文件路径,方便回溯,压测结束后再压缩归档到冷存储。
6. 压测报告怎么写才真正有参考价值
6.1 报告结构的安排
一份压测报告如果只堆数据,那和没做测试差不多。我们的报告分成四个部分。
第一部分是结论。结论必须是经过逻辑校验后的“输出决策”,比如“系统当前适合承接目标负载,但存在某某风险,需要在一个月内完成某某优化后再次验证”或“系统未通过稳定性验证,主要卡点在某某指标”。这部分放在最前面,因为评审人最关心的就是结论。
第二部分是关键数据。用表格列出7天每天的QPS平均值、P95/P99响应时间、错误率、资源利用率范围,以及对比第一天的性能衰减程度。表格一定要有趋势列,注明某一天是上升、下降还是平稳。
第三部分是问题清单。这是整份报告最有价值的部分。每个问题需要包含现象描述、排查过程、根因分析、修复方案、验证结果五个要素。我们这次处理了三个P1级问题,每个问题的排查过程都写成了可复现的步骤,这样后续如果出现类似问题,新同学也能快速上手排查。
第四部分是原始数据和监控截图归档。Prometheus的历史数据、Grafana的看板截图、压测客户端的请求日志,全部打包归档到对象存储,保留至少一个月。这看起来不起眼,但真到了有的问题在测试结束后才被业务指标暴露出来的时候,你会发现原始数据是唯一可以回溯的线索。
6.2 复盘会上那些不好回答的问题
压测报告写完,接下来就是评审会。根据我的经验,技术负责人大概率会追问三个问题,需要提前准备。
第一个问题:“你这个压测覆盖了真实业务场景吗?”回答这个问题的底气来自测试前的流量分析。我们当时从生产环境收集了3天的日志,分析了Prompt长度的分布、请求到达的时序特征、多轮对话的比例,然后把这些特征完整复现到压测脚本里。
第二个问题:“切到国产算力集群之后,性能比原来差多少?”这个问题前面如果没做基线对比就答不上来。我们在压测前特意用同一个模型、同一份数据、同量级并发在旧集群上跑了一套对标测试,结论就是要给出两张表的对比数据。
第三个问题:“压测通过了,容量规划和扩容策略是什么?”这要求你在报告里不仅写测试结果,还要写业务建议。比如根据7天压测的数据,建议目标并发控制在当前规模的70%,当平均资源利用率连续30分钟超过85%时触发扩容,扩容建议按线性扩展估算。
这种问题提前想清楚,评审会你就能掌握主动权。
这段压测经历实际上比预期更值得记下来——不光是输出的数据有什么,更重要的是把长期运行环境下那些探测的做法沉淀了下来。集群稳定性的问题,从来没有“没问题”这个选项,只有“还没被发现”的状态。这套方案里的指标分层、分段压测、告警分级和问题排查链路,已经被我固定成内部的项目模板。下次再遇到国产算力集群的稳定性测试,直接套用这套流程,至少能少走一半弯路。