ARTICLE DETAIL

资讯详情

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

性能测试核心指标全解析:响应时间、TPS与瓶颈定位

性能测试核心指标全解析:响应时间、TPS与瓶颈定位 做性能测试这些年我踩过最多的坑不是脚本写不出来也不是压测工具不会用而是拿到一堆性能指标之后根本不知道该怎么看、怎么下结论。很多人觉得性能指标就是响应时间、TPS、错误率这几个数字跑完压测看一眼报表就完事了。但实际上指标与指标之间是有内在逻辑的它们不是孤立的数据点而是一套能够反映系统真实运行状态的信号系统。如果只盯着某个单一数值很容易得出错误的性能判断。这篇内容我就专门围绕性能测试的基础指标来拆把核心概念、原理、计算公式、工具实操和排查思路一次说透。适合刚接触性能测试的测试工程师、开发工程师也适合那些已经会跑压测但不太清楚指标背后含义的同学看到最后你会发现性能测试的瓶颈分析其实就是指标关联分析。1. 指标体系的设计思路为什么性能测试必须先定指标很多初级测试人员拿到性能测试任务之后第一反应是“先赶紧把JMeter脚本录出来然后跑一轮看看”。这样做的结果通常就是压测跑完了报告出来了但完全不知道怎么评估系统到底“行不行”。问题的根源就在于指标定义先行这个关键步骤被跳过了。1.1 指标体系的三层结构性能测试指标体系本质上分为三层用户视角指标、系统视角指标、组件视角指标。用户视角指标解决的是“用户体验怎么样”的问题最典型的就是响应时间和错误率。这层指标直接决定了业务是否可用、用户是否愿意继续使用系统。系统视角指标解决的是“后端扛住了没有”的问题包括吞吐量TPS/QPS、并发用户数、资源利用率CPU、内存、磁盘IO、网络带宽等。这层指标反映的是整个服务端集群的处理能力。组件视角指标则深入到更细的层面比如数据库的连接池使用率、GC暂停时间、线程池活跃线程数、缓存命中率、消息队列堆积量等。这些指标是定位瓶颈根因的“显微镜”当用户视角和系统视角的指标出现异常时要靠它们来定位到底是哪一层出了问题。这三层之间是层层因果的关系。用户响应时间变长了大概率是系统吞吐到了瓶颈而吞吐瓶颈的背后可能是某个组件指标出现了异常。所以性能测试的指标体系不能只选一层三层都要覆盖只是为了不同的测试目标关注的侧重点不同。1.2 指标选型必须跟着测试目标走不是说所有的性能测试都要把所有指标全部统计一遍那样成本太高而且注意力分散。指标选型的核心逻辑是测试目标决定指标维度。如果当前做的是容量测试目标是确定系统最高能支撑多少并发用户那么核心指标应该是TPS、并发用户数、资源利用率这三者之间的变化曲线。最终要找到的是一个“性能拐点”也就是TPS不再随并发数线性增长的那个临界点。如果是稳定性测试比如7x24小时长时间压测重点就不是峰值TPS了而是要关注内存是否缓慢增长排查内存泄漏、GC频率是否越来越频繁、句柄数是否持续上涨、响应时间是否有慢趋势。这类测试需要用时间序列指标来观察变化趋势而不是看某一时刻的截面数据。如果做的是压力测试验证系统在极端负载下是否会崩溃那就要加上错误率、超时比例、队列堆积度这些容忍性指标。所以在写性能测试方案的那一刻就应该把本次测试要关注的指标清单列出来并明确定义每个指标的正常范围、警告阈值和不可接受阈值。没有这套标准压测结束后的每一张图表都可能引起争议——你说性能好我说性能差最后谁也说服不了谁。2. 核心性能指标深度解析定义、计算与易混淆点性能测试的常用指标数量并不算多但真正把每个指标的数学含义和边界条件搞清楚的人其实不多。下面我把最核心的指标逐个拆开讲。2.1 响应时间别被平均值骗了响应时间是从客户端发出请求到收到完整响应所经历的总时长。它通常可以拆解为网络传输时间客户端到服务器、应用处理时间、数据库访问时间等几个部分。响应时间最常见的统计口径有四种平均值ART、中位数、百分位值如TP99、TP95、最大值。这里必须注意平均值是最有迷惑性的指标。举个例子假设有100个请求99个请求耗时100ms1个请求耗时10秒平均值约等于199ms单看平均值似乎性能还不错但实际上有1%的请求已经严重超时真实体验非常糟糕。所以我在实际项目中响应时间核心指标只看两个TP95和TP99。TP99的含义是有99%的请求耗时在该值以下只有1%的请求比这个更慢。对于高并发业务系统一般要求TP99小于200ms到500ms取决于业务场景对于数据库查询类接口TP99通常要求更严苛一些。还有一个经常被忽略的点响应时间的计算起点。是客户端发出请求的时刻还是服务端收到请求的时刻如果用JMeter这类端到端工具统计的是包含网络传输的完整时间如果只看服务端日志里的处理时间网络开销就被排除了。这两者在诊断时需要结合使用不能混为一谈。2.2 吞吐量TPS与QPS的区别与换算吞吐量是单位时间内系统处理的请求数量常见指标是TPSTransactions Per Second每秒事务数和QPSQueries Per Second每秒查询数。在性能测试语境下两者经常混用但严格来说有区别。QPS更偏向查询类操作一次“查询”就是一次请求TPS则强调完整业务事务一个事务可能包含多个请求。比如一个下单操作可能前端要调用创建订单接口、扣减库存接口、生成支付单接口对整个事务来说TPS是1但对后端接口来说QPS可能是3。做性能测试设计时必须明确事务的粒度。我见过有人把一个登录接口压测出来的TPS说成是整个系统的TPS这就是典型的事务粒度混淆。系统级容量评估一定要基于端到端业务场景来统计TPS而不是单个接口的QPS。吞吐量和响应时间的关系也值得说。在系统未达到瓶颈之前提高并发用户数会同时提升TPS响应时间也基本平稳但一旦过了拐点并发继续增加TPS不再上升甚至下降响应时间则急剧上升。整个系统的吞吐量是有“天花板”的这个天花板通常由某个底层资源决定这就是后面要说的瓶颈分析。2.3 并发用户数在线用户、并发请求与并发用户并发这个概念在性能测试里被讨论得最多也被误解得最多。在线用户数指的是当前登录系统、处于连接状态的用户数量这部分用户绝大多数处于“挂机”状态并没有实际发起业务操作。并发用户数则是指同一时间窗口内真正对服务器产生压力正在发出请求或处于请求处理过程中的用户数量。而对于服务器端来说它感知到的其实是并发请求数即某一时刻正在处理的请求数量。这三者的典型比例关系在常规Web业务系统中大概可以这样估算并发用户数通常占在线用户数的5%到20%视业务操作频率而定并发请求数又会小于并发用户数因为一个用户在一次交互中通常只有一个主请求在读等待。在JMeter中线程数设置的就是模拟的并发用户数。但要注意如果脚本里没有思考时间Think Time每个线程会以最大速度发请求这时候实际产生的并发请求压力是大于真实业务场景的。所以在容量测试中要不要加思考时间需要根据测试目标来定如果是压测系统极限可以不加如果是模拟真实业务负载建议加。2.4 错误率容忍度必须提前定义错误率是返回错误或超时的请求数占总请求数的比例。它是判断系统是否可用的硬性指标。但“错误”的定义需要提前统一。HTTP 500算错误HTTP 504算超时HTTP 200但是业务响应码为失败比如下单失败返回“库存不足”算不算错误严格来说后者应该算业务错误率反映的是业务逻辑层面的问题前者算系统错误率反映的是基础设施或代码层面的故障。性能测试报告里要把这两种情况分开统计。业界一般以错误率低于0.1%99.9%成功率作为系统正常状态的参考线。对于核心交易链路甚至可以要求错误率为0对于非核心的弱依赖接口容忍度可以适当放宽。2.5 资源利用率CPU、内存、磁盘、网络资源利用率反映的是系统在压测过程中的资源消耗情况。通常关注四类CPU使用率是最直接的指标。但单看整体CPU使用率还不够还要关注CPU是消耗在用户态执行应用程序代码、系统态内核操作还是iowait等待磁盘IO。如果iowait很高说明磁盘是瓶颈如果用户态很高说明应用在做大量计算或频繁GC。内存使用率需要结合JVM等运行时来看。操作系统层面的内存使用率上升不一定意味着应用有问题要重点观察的是是否存在内存持续增长而不回落的情况这大概率是内存泄漏。磁盘IO看的是IOPS和吞吐量以及磁盘队列长度。如果磁盘队列长时间大于2到4说明存储系统已经明显过载。网络指标要看带宽使用率、TCP重传率、连接数。TCP重传率是一个非常有效的网络质量信号如果超过了1%到2%说明网络链路存在丢包或拥塞。这里提一下经验判断当CPU使用率长时间超过85%时通常意味着处理能力出现瓶颈而内存使用率超过90%时需要结合GC情况判断不一定是故障。3. 指标采集实操从JMeter到全链路监控指标定义清楚了接下来就是实操环节。性能测试最大的尴尬点之一就是压测工具本身统计的指标和服务器端监控采集的指标对不上、时间戳不一致导致后期分析困难。这一步我就按工具链条展开讲。3.1 JMeter的指标采集聚合报告与全量日志的差别JMeter跑完压测后最常看的就是聚合报告Aggregate Report。它能够列出每个请求标签的平均响应时间、中位数、90%/95%/99%百分位、吞吐量、错误率等核心指标。对于快速验证压测结果这个报告足够了。但注意聚合报告是汇总后的聚合数据它丢失了时间维度的趋势信息。你只知道整个压测期间的TPS平均值是800但你不知道是不是前10分钟跑到1500后10分钟掉到300。所以我更推荐在做正式性能测试时除了聚合报告还要启用后端监听器Backend Listener把原始指标实时上报到时序数据库如InfluxDB再用Grafana画趋势曲线。命令行的JMeter压测比GUI模式更稳定因为GUI模式本身会消耗系统资源影响压测结果。建议用这样几个参数保证数据可复用jmeter -n -t test_script.jmx -l result.jtl -e -o report_dir -j log/jmeter.log其中-l result.jtl会把每个样本的原始数据写入JTL文件-e -o report_dir在压测结束后生成HTML报表。原始JTL文件一定要保留下来因为它记录了每个请求的时间戳、线程名、响应时间、响应码等最细粒度信息后续可以用脚本做二次分析。还有一个关键参数是-R或-r用于远程分发压测。单台机器压测时存在端口号和文件描述符上限一般建议用分布式压测JMeter的驱动程序会汇总各Agent的数据。最常遇到的坑是远端Agent的时钟不同步导致各Agent产生的时间戳对不上。所以分布式压测前务必用NTP统一所有压测机和被压服务器的时间。3.2 客户端指标与服务器端指标必须双向采集很多性能测试报告只有JMeter的客户端指标却没有服务器端的CPU、内存、磁盘、网络指标。这样一旦发现TPS上不去完全没有数据支撑去定位是“压测机压不动了”还是“服务端到顶了”。服务端指标采集常见的方案有三类第一类是用系统自带工具临时采集。比如Linux下的top、vmstat、iostat、sar、mpstat适合测试过程中随时看一眼但不适合做全程记录分析。用法上vmstat 1可以每秒钟输出一次CPU、内存、IO的当前状态iostat -x 1可以看更详细的磁盘利用率。第二类是性能监控平台方案。比如Prometheus加node_exporter加Grafana这是目前最流行的开源组合。node_exporter可以采集几乎所有的操作系统级指标Prometheus负责存储和查询Grafana负责可视化。这套方案的优点是可以和JMeter的Backend Listener对接形成客户端和服务端同一时间轴上的对比视图。第三类是针对Java应用的专用监控比如用jstat观察GC情况用jstack抓取线程快照用JVisualVM或Arthas做在线诊断。这些工具尤其适用于出现CPU飙升、线程死锁、内存溢出等典型问题时的现场分析。我在实践中形成的一个习惯是压测开始前先采集5分钟的服务器基线数据压测过程中每5分钟记录一次变化压测结束后再采集10分钟的恢复期数据。这样就能清晰地看到负载上升、持续、释放的全过程判断系统是否存在“压力解除后指标无法回落”的异常。3.3 测试脚本中的高频注意点线程组、监听器和关联JMeter脚本设计对指标数据的影响远超想象三个高频注意点必须单独说。第一个是线程组的设计。如果只是简单测试可以选Thread Group设定线程数、Ramp-Up时间启动所有线程所需时间和循环次数。但是正式性能测试最好用Stepping Thread Group或Ultimate Thread Group它们可以精确控制“每秒递增多少个线程”方便观察系统在不同压力阶梯下的指标变化。不要一次性把所有线程在1秒内全部拉起那样会给服务器造成瞬时冲击既容易触发限流也看不出渐进式瓶颈点。第二个是监听器。聚合报告、查看结果树View Results Tree这类监听器在正式压测中尽量不要挂在GUI运行特别是“查看结果树”——它会保存每一个响应数据在高并发压测时疯狂消耗压测机内存把压测机自己弄到OOM。如果你真的需要调试脚本用小并发短压测先跑一遍确认无误后再切换到命令行模式跑正式场景。第三个是参数化和关联。写死参数的性能测试没有任何参考价值。比如登录接口如果所有并发用户都用同一个账号那缓存命中率、秒杀校验逻辑全部失真。实际项目里一般用CSV数据文件来驱动不同用户的不同参数。如果测试的接口有动态token或sessionId要从前一个接口的响应中提取这就是关联。这一步做不好压测流量有大概率在到达被测系统之前就被拦截掉了跑出来的TPS再高也是无效数据。4. 性能分析与瓶颈定位把指标串成因果链指标采集完成后真正的考验才开始。性能分析的核心方法论是推理因果链从结果指标入手层层下沉最终定位到具体的瓶颈组件或代码位置。4.1 典型性能拐点分析TPS上不去的时候先看哪个图拿到一段压测数据之后我建议先画三张图TPS随时间变化曲线、响应时间随时间变化曲线、TPS与并发用户数的散点图。这三张图基本能给出第一轮判断方向。如果TPS曲线是一条比较平的线且不管并发数怎么加都上不去优先怀疑两条路径要么压测机自身已经到达瓶颈CPU打满、端口耗尽要么被测系统的某个组件设置了并发上限比如Nginx的worker_connections、Tomcat的maxThreads、数据库的连接池上限、微服务网关的限流阈值。如果TPS在某一时刻突然断崖式下降大概率是服务端已经处于过载状态触发了熔断、降级或限流机制。这时候需要立刻看服务端日志里是否有对应的熔断记录同时观察错误率曲线是否同步跳变。如果TPS上升但响应时间成线性增长说明系统的处理队列在加长每个请求都在排队等待。此时观察线程池活性线程数和队列长度如果线程池已满且队列开始堆积说明系统在处理能力上的扩容还没有跟上并发压力的增长这是典型的资源不足信号。4.2 响应时间异常时的资源指标对照法响应时间变慢时要对照资源指标来做排除。我总结了一个简洁的排查思路如果CPU使用率很高超过85%同时GC日志显示GC次数频繁、单次GC暂停时间长那么问题大概率在应用层的计算逻辑或内存分配回收上。用jstat -gcutil观察Eden区、Old区使用率变化如果Old区持续增长且Full GC频繁就是内存压力导致应用停顿直接表现为响应时间变长。如果CPU不高但磁盘iowait很高优先看数据库和数据落盘操作。可以用iostat -x看%util和await如果await明显高于正常值说明磁盘访问延迟大可能是慢SQL产生大量全表扫描也可能是日志写入过于频繁。如果CPU、磁盘都正常但TPS和响应时间依然不达标那就要怀疑网络层。netstat查看是否存在大量TIME_WAIT或CLOSE_WAIT连接sar -n DEV看网络接口的利用率ping或traceroute看基础连通性。尤其要重视CLOSE_WAIT持续增长的情况这通常意味着应用程序没有正确关闭连接最终会耗尽文件描述符导致新请求无法建立连接。4.3 资源竞争与互斥高并发场景的隐藏杀手有一种情况比较隐蔽所有宏观指标看起来都正常但单个请求的响应时间呈现周期性尖峰。隔几十秒出现一次毫秒级甚至秒级的响应飙升然后又恢复平稳。这种周期性尖峰通常指向资源竞争。常见的元凶有三种。第一种是JVM的Full GC。如果Old区容量偏小到达阈值后在某个时间点突然触发Full GC会导致整个应用停顿所有在途请求全部等待然后集中返回形成尖峰。第二种是定时任务与业务请求的资源竞争比如每个整点跑一次数据批处理把CPU和IO瞬间拉满第三种是连接池的回收重建长时间空闲连接被断开然后高并发场景下重新建连导致慢请求。这种问题的排查方式是把响应时间的分布直方图拉出来观察是不是存在两个明显不同的响应簇。如果是再配合GC日志、定时任务日志、连接池监控去精确定位尖峰时刻的触发源。5. 常见问题与排查技巧实录这一节把我在性能测试项目里频繁遇到、并且非常典型的问题记录下来基本可以当作速查表来用。5.1 JMeter聚合报告数据显示异常问题描述压测跑完了聚合报告里TPS显示为0或者部分Label的样本数为0。排查思路先检查JTL文件是否正常生成文件大小是否在持续增长再检查脚本中是否有断言失败导致请求被标记为错误但仍计样本最后检查聚合报告是否有强制清空旧数据的设置。还有一个非常容易踩的坑就是用CSV输出格式时结果文件被Excel打开占用导致JMeter无法写入。建议每次压测前清空历史聚合数据在命令行加参数-f强制删除旧的输出文件避免新旧数据叠加。5.2 压测结果与服务端监控数据对不上问题描述JMeter显示TPS达到2000但服务端监控看到QPS只有800。排查思路这类问题绝大多数是压测机和服务端之间出现了中间缓存或网络丢弃。检查是否有Nginx或网关做了请求合并、缓存响应检查防火墙或安全组是否对高频连接做了限制检查压测机还有没有足够的内存和文件句柄。另外一个重要因素是JMeter统计的是客户端发出的请求但部分请求因为连接池耗尽而失败了错误率可能就是掩盖在漂亮TPS下的漏洞。压测前用ulimit -n确认压测机文件描述符上限如果不够要调大。通常单机至少需要65535以上否则并发一上来压测机先崩了。5.3 响应时间曲线周期性毛刺问题描述整体响应时间平稳但每隔5分钟出现一次响应时间尖峰。排查思路优先排查是否有定时任务在整点或固定周期触发。用crontab -l检查服务器上的计划任务顺便看应用内的调度任务配置。然后看GC日志如果Full GC的时间间隔和尖峰周期吻合基本可以确认是GC问题。最后再看是否有日志框架在进行归档切割Log4j2或Logback在日志文件切割瞬间因为磁盘IO竞争也可能出现极短时间的响应尖峰。5.4 JVM内存持续上涨但始终不OOM问题描述压测过程中JVM堆内存持续上涨但长时间运行下来并没有抛出OutOfMemoryError不过GC越来越频繁响应时间越来越长。排查思路这大概率是一个内存泄漏的前兆。用jmap -histo:live对比不同时间点的对象分布找到那些只增不减的类再用jstat -gcutil观察Old区的变化斜率如果Old区在每次Full GC后都不能回到一个稳定的低位那基本可以确定有对象被错误地长期持有。后续可以用MAT分析堆转储文件找到引用链定位到具体的业务代码。这里分享一个排查技巧在压测时每隔10分钟导出一份堆转储至少保留三份不同时间点的快照。相比只抓一次现场多快照之间的对象数量差异能更快暴露泄漏点。5.5 性能测试指标速查表指标名称核心含义正常参考线关键注意点响应时间RT请求从发出到收到响应的总耗时视业务而定TP99在200-500ms只看平均值没有价值必看TP95/TP99TPS每秒完成的事务数与业务目标挂钩事务粒度必须明确定义QPS每秒查询数与TPS配合分析一个事务可能包含多个QPS并发用户数同时向系统发起请求的用户数通常在在线用户的5%-20%区分在线用户、并发用户、并发请求错误率错误请求占比核心链路0.1%系统错误和业务错误分开统计CPU使用率处理器繁忙程度长时间超过85%视为瓶颈区分用户态、系统态、iowait内存使用率物理内存使用比例超过90%需关注结合GC和换页情况判断磁盘IO磁盘读写压力await、util结合看队列长度长期2-4即为过载网络重传率数据包重传比例超过1%-2%需关注判断网络链路质量6. 一个完整的指标分析案例订单查询接口的性能测试理论讲完了用一个我实际验证过的案例把整个流程串起来。这是一个典型的订单查询接口核心链路是客户端请求到Nginx转发到订单服务订单服务查Redis缓存缓存未命中则查数据库订单表。测试目标验证该接口在2000个并发用户下是否满足TP99小于500ms的错误率小于0.1%的性能要求。测试设计并发用户从200开始每5分钟增加200直到目标3000观察每个压力阶梯下的各项指标变化。第一轮压测结果并发不到800的时候TP99在200ms左右表现理想并发到1000时TP99飙升到1.5秒TPS从1800掉到900错误率从0开始上升到0.4%左右。此时对照资源指标看CPU使用率只有40%内存正常但数据库监控显示连接池活跃连接数接近上限。继续查发现订单表和订单明细表数据量超过百万且查询条件里没有覆盖索引缓存命中率在并发超过800后从95%暴跌到60%。原因其实不难判断数据库索引缺失导致缓存未命中后的查询代价极高数据库连接被慢查询拖住连接池耗尽后新的请求全部等待响应时间急剧上升超时后触发错误。定位到这里解决方案就是两条给高频查询增加联合索引把缓存过期策略进一步优化避免集中失效。做这两个调整后重新压测在2000并发下TP99稳定在320ms错误率降到0.03%性能达标。这个案例的核心价值就在于如果只盯着JMeter出来的响应时间曲线你可能只知道系统变慢了但只有把TPS、错误率、CPU、连接池、缓存、SQL执行计划这些指标串成一条因果链才能精准找到问题到底出在哪个环节。像这样的指标关联分析能力是在一次次的性能测试项目里磨出来的。看得多了你会形成一种直觉一看到响应时间曲线走形脑子里就会自动浮现出对应的排查路径。这种直觉没有捷径核心方法就是每轮压测都坚持把客户端指标、服务端指标、组件指标放在同一个时间轴上去对照、去复盘长此以往数据在你眼里就不再是孤立数字而是一张能够快速定位问题的地图。
返回列表