ARTICLE DETAIL

资讯详情

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

性能测试指标评估与通过标准:TPS、P95、JMeter实战

性能测试指标评估与通过标准:TPS、P95、JMeter实战 1. 性能评审会上最容易吵翻的三个问题口径、分位、阈值我参加过不少性能评审真正吵起来的从来不是工具用 JMeter 还是 LoadRunner而是同一份报告测试同学说我们压到 400 TPS、平均响应 80 毫秒可以上线运维同学立刻接一句CPU 都顶到 90% 了这也叫能上两边说的都是实话但结论完全相反。问题不在数据在于彼此嘴里的TPS响应时间通过根本不是同一套定义。后来我慢慢总结出一个习惯任何一场性能评审开始之前先问三句话。第一句你的 TPS 是接口级、事务级还是业务级统计口径第二句响应时间你看的是平均值还是P95/P99 分位数第三句这次的通过标准是谁定的、写在哪份文档里这三句话答不上来那份报告基本就是一张纸——数字再漂亮也没法用来做上线决策。本文想聊的就是这三件事常用性能指标到底有哪些、这些指标该怎么评估、性能测试的通过标准该怎么定。不管你是刚开始接触性能测试、准备用 JMeter 跑第一轮压测的同学还是已经跑了几轮但对达标与否始终心里没底的中级工程师这里面的坑和判断逻辑都值得过一遍。顺带说一句性能测试这个领域的工具迭代很快但指标体系和分析方法十几年来几乎没变过——工具只是采集器真正决定结论质量的永远是你有没有把口径锁死。我见过最典型的失败案例是这样的一个订单查询接口压测报告写着平均响应 120 毫秒、TPS 320、错误率 0%结论性能达标。上线第二天用户投诉卡顿。回头翻日志才发现那 0.5% 落到 5 秒以上的慢请求全被平均值稀释掉了而那部分请求正好集中在运营最常用的多条件组合查询上。平均值把一个右偏分布抹平成了正态分布这是性能分析里最贵的错觉。2. 别把指标堆成一锅粥四层指标体系与各自的采集位置性能指标最容易犯的错是全都想要。报告里塞了几十个数字CPU、内存、RT、TPS、GC 次数、慢 SQL、缓存命中率……看完之后没人说得清到底哪里有问题。我的做法是按观测距离分层离用户越近的指标越优先看离用户越远的指标只在定位瓶颈时才深挖。这四层各有各的采集位置混在一起看就是自找麻烦。2.1 第一层用户体感层决定能不能上这一层只关心用户真实感受到的东西页面/接口首字节时间TTFB、完整响应时间RT、报错和超时的比例、前端资源加载耗时。它是最有话语权的一层因为老板和业务方只认这个。但它的采集位置也最容易被搞错——如果你只在压测机侧统计 RT那你测的是网络服务端的总和如果只统计服务端内部耗时那你漏掉了网络传输和排队等待。做接口压测一般看施压端侧的时间戳差做前端性能则必须上真实浏览器或合成监控。这一层我通常会额外看一个指标慢请求占比。定义很简单响应时间超过某个业务可接受上限比如 1 秒的请求数占总请求数的比例。它的价值在于它比 P95 更直观——每 100 个用户里有 3 个要等 1 秒以上业务方一听就懂。2.2 第二层应用与接口层定位哪里慢这一层是工程师的主战场事务 TPS、接口 QPS、响应时间分布、错误码分布、线程池活跃数、连接池等待数、JVM 堆使用与 GC 停顿。采集位置在应用进程内部——APM 的探针、JMeter 的事务控制器、Spring Boot Actuator、或者自己埋点。我特别想强调连接池等待这个指标。很多响应时间突然变长的现场根因不是服务本身算得慢而是下游数据库连接池被打满请求在拿连接这一步排队。这个等待时间通常不会体现在业务方法的执行耗时里如果你只看方法级耗时就会得出服务端处理很快问题在网络的错误结论。2.3 第三层中间件与依赖层看清外部账数据库、缓存、消息队列、第三方接口这一层的指标包括DB 的 QPS/TPS、慢 SQL 数量与耗时、锁等待、主从延迟、缓存命中率、大 key 数量、MQ 消费延迟与堆积量、第三方接口的 RT 与错误率。压测时最怕的就是被测服务一切正常但数据库 CPU 已经 100%——那说明你的容量瓶颈在依赖方服务本身再优化也是白费。2.4 第四层主机与资源层最后一道兜底CPU 使用率区分用户态/系统态/IO 等待、内存与 Swap、磁盘 IOPS 与利用率、网络带宽与重传率、文件描述符与端口占用。这一层的作用不是发现问题而是验证猜想。当你怀疑瓶颈在磁盘时去看 iowait怀疑在 GC 时去看 GC 日志的时间分布。层级关注指标典型采集位置什么时候必须看用户体感层RT、TTFB、错误率、慢请求占比施压端、浏览器、合成监控每一轮都必须看应用接口层TPS、RT 分布、线程池、连接池、GCAPM、Actuator、JMeter 监听器每一轮都必须看中间件依赖层DB QPS、慢 SQL、缓存命中率、MQ 堆积数据库监控、缓存面板、MQ 控制台应用层指标异常时优先看主机资源层CPU、内存、IOPS、网络、句柄系统监控、node_exporter 类工具定位瓶颈时验证用提示四层指标不要并列写进报告结论。报告结论只写第一层和第二层的判定结果第三、四层放在瓶颈分析章节里作为证据否则很容易把读者带偏。3. 几个核心指标的准确定义RT、TPS、并发、错误率指标名字人人会念但口径经常是错的。这一节我把最常用的四个指标拆开讲每个都配上计算方式和常见误读。3.1 响应时间把平均值换成分位数平均响应时间 所有请求响应时间之和 / 请求数。它的致命缺陷是对长尾极不敏感。假设 1000 个请求里995 个耗时 50 毫秒5 个耗时 5 秒平均值只有约 74.75 毫秒看起来非常健康但那 5 个用户已经处于不可用状态了。正确做法是看分位数。P95 500 毫秒的意思是95% 的请求在 500 毫秒内完成剩下 5% 超过这个值。分位数不受极端值干扰又能真实反映尾部体验。我一般会同时报三个数P50中位数代表典型用户、P95代表偏慢的那批人、P99 或 Max代表最差体验和潜在故障。分位数的计算方式不止一种不同工具结果会有细微差异。常用的线性插值实现大概是这样def percentile(values, p): p 取值 0~1例如 0.95 表示 P95 if not values: return None s sorted(values) if len(s) 1: return s[0] k (len(s) - 1) * p lo int(k) hi min(lo 1, len(s) - 1) return s[lo] (s[hi] - s[lo]) * (k - lo)注意报告里报分位数时一定写清楚是哪个工具算的、样本量多大。样本量小于 100 的时候P99 基本没有参考意义——一个样本就能让结果翻倍。3.2 TPS、QPS 与吞吐量别看总量看统计窗口TPS 通常指每秒完成的事务数QPS 指每秒完成的查询/请求数吞吐量则是一个更宽泛的概念可以是每秒字节数、每秒消息数。三者最容易被混淆的地方在于**事务的边界**一个下单流程可能包含 5 个接口调用、3 次数据库写入它算 1 个事务还是 5 个请求这个边界必须在压测方案里写死否则测试和运维对不上账。另一个隐形问题是统计窗口。TPS 完成请求数 / 统计时长如果统计时长取整个压测周期比如 30 分钟那么加压阶段和稳定阶段的差异就被平均掉了。我习惯按10 秒或 1 分钟一个窗口记录画成曲线看平稳段的均值而不是看总平均值。3.3 并发数业务并发、系统并发、线程数不是一回事这是最容易被数字游戏误导的地方。业务并发是同一时刻正在使用系统的人系统并发是同一时刻正在被处理的请求数而 JMeter 里的线程数只是施压端的虚拟用户数它和系统并发之间差着一个思考时间。三者的关系可以用利特尔法则串起来我在第 4 节详细展开。一个常见误区是把线程数直接等同于并发用户数。如果你在线程组里设置了 200 线程、每个请求后停顿 1 秒而接口响应时间是 200 毫秒那实际到达服务端的系统并发只有 200 × 0.2 / (0.2 1) ≈ 33 左右服务端压力远小于你以为的 200。3.4 错误率分母选错结论全错错误率 失败请求数 / 总请求数。听起来没歧义但总请求数的口径很有讲究。如果你的脚本里包含了登录、获取 token 这类前置准备请求把它们算进分母会稀释真实业务接口的错误率反过来如果统计周期内有大量连接超时这些请求根本没被记录成请求错误率会凭空变好看。我的做法是用事务控制器把一次完整业务操作包成一个事务错误率以事务为单位统计同时单独统计超时率和连接异常率。这样得到的结论才站得住脚。指标常见误读建议口径响应时间只看平均值报 P50 / P95 / P99标注样本量TPS只看总平均值按 10s 窗口取平稳段均值并发数线程数等于并发按利特尔法则换算系统并发错误率分母混入准备请求以业务事务为单位统计4. 把数字算准利特尔法则、脉冲系数与阶梯加压前面讲的是怎么读这一节讲怎么算。容量估算算错后面所有测试都是在验证一个错误的前提。4.1 利特尔法则并发 TPS × RT利特尔法则是一个排队论结论系统中的平均并发数 到达速率 × 平均停留时间。翻译成性能测试的语言就是系统并发数 目标TPS × 平均响应时间(秒)假设目标是 400 TPS、平均响应时间 300 毫秒那么系统并发就是 400 × 0.3 120。这个数字才是你压测时应该让服务端同时处理的请求数。而如果你在 JMeter 里加了思考时间Think Time线程数需要放大线程数 系统并发数 × (响应时间 思考时间) / 响应时间按上例若思考时间设为 0.5 秒线程数 120 × (0.3 0.5) / 0.3 320。这个换算我每次都手算一遍因为一旦弄错要么压不出目标压力要么把被测系统压穿导致结论失真。4.2 二八原则估峰值算完还要乘脉冲系数很多同学估容量是拿日活 ÷ 86400这个数往往低得离谱。业务量的分布从来不是均匀的二八原则更贴近现实80% 的业务量集中在 20% 的时间内完成。单接口峰值TPS (日业务总量 × 80%) / (86400 × 20%)拿日均 200 万单举例(2000000 × 0.8) / 17280 ≈ 92.6 TPS。这个数字还是太平滑了。真实业务存在脉冲——秒杀开场、整点推送、定时任务集中触发这时候要再乘一个脉冲系数经验值 3 到 5 倍。上例取 4 倍目标就是约 370 TPS取整到 400 TPS和我前面用的数字对上了。这个推算链条我建议写进压测方案的第一页。它不只是一个数字而是你和业务方对齐测到什么程度算够的依据。没有这个推导评审时你说 400 TPS 达标业务方问为什么是 400你答不上来。4.3 阶梯加压找拐点最大 TPS 与容量水位恒定压力只能验证这个量级能不能扛住阶梯加压才能回答还能扛多少。我常用的模型是从目标压力的 20% 开始每 2 到 3 分钟递增 20%一直加到错误率突破阈值或响应时间出现明显拐点为止。拐点出现的典型特征是TPS 不再随线程数上升甚至开始下降而响应时间快速拉长。这说明系统已经过了最优点进入了排队恶化的区间。我把拐点对应的 TPS 称为最大处理能力把目标 TPS 占最大处理能力的比例称为水位。生产环境一般建议稳定运行水位控制在 50% 到 70% 之间留出应对突发流量的缓冲。加压阶段时长建议观测重点预热1~2 分钟缓存、连接池、JIT 是否充分预热阶梯递增每级 2~3 分钟TPS 是否线性上升、RT 是否平稳稳定保持10~30 分钟错误率、内存增长、GC 频率峰值冲击1~3 分钟极限承载与恢复能力4.4 施压端别自己先倒下这一条是用血换来的。有一次我们压一个目标 2000 TPS 的接口怎么调线程数都上不去TPS 卡在 800 就不动了。排查了两小时被测服务资源一切正常最后发现是施压机自己的 CPU 跑满了JMeter 的 GUI 模式加上实时监听器光渲染就吃掉了大半算力。结论很直接压测必须用非 GUI 模式监听器尽量精简施压机数量按目标压力评估必要时分布式施压。命令大致是这样jmeter -n -t order_peak.jmx -l result.jtl -e -o ./report --logfile jmeter.log参数含义-n非 GUI 模式-t指定测试计划-l输出结果文件-e -o生成 HTML 报告并指定输出目录。记得每次执行前清空result.jtl否则历史数据会混进来污染统计。5. 指标评估从一堆数字到一句站得住脚的结论采集到数据只是开始真正的活儿是评估。同样是P95 800 毫秒在不同上下文里可能是灾难也可能是正常。评估要解决的就是这个上下文问题。5.1 先对齐时间窗口再看趋势评估的第一步永远是把时间轴对齐。施压端的 RT 曲线、应用的 TPS 曲线、数据库的 QPS 曲线、主机的 CPU 曲线如果时间基准不统一有的用本地时间有的用 UTC有的采集间隔不同你会得出完全错误的因果关系。对齐之后看趋势而不是看某一点的数值。我习惯把关键曲线叠在一张图上重点观察两件事一是同时起跳的曲线它们大概率存在因果关系二是先动和后动的曲线先动的那个更可能是根因。比如 CPU 先涨、RT 后涨那瓶颈在计算RT 先涨、CPU 后涨那多半是排队导致的连锁反应。5.2 采样粒度分钟级均值会吃掉瞬时尖峰监控系统默认的采样间隔常常是 1 分钟而性能问题往往在几秒内爆发。一个每秒抖动、峰值持续 3 秒的 CPU 尖峰在分钟级均值里可能只表现为 60% 的使用率看起来毫无问题。定位这类问题时我会把采样粒度降到 1 秒甚至更细并且优先看Max 值和分位数而不是均值。5.3 现象、根因与验证方式下面这张表是我自己排错时常用的对照清单遇见异常现象先按这个方向找证据比漫无目的地翻日志效率高得多。现象可能原因验证方式TPS 平稳但 RT 缓慢上升内存泄漏、连接泄漏、日志堆积看堆内存曲线是否单调上升、连接池活跃数是否不回落TPS 卡住不再上升施压端瓶颈、线程池/连接池上限看施压机资源、线程池队列长度错误率突然爬升超时阈值触发、下游限流、连接被拒看错误码分布、下游服务日志RT 抖动剧烈GC 停顿、锁竞争、缓存击穿看 GC 日志、慢 SQL、缓存命中率数据库 CPU 高但 QPS 不高慢 SQL、缺索引、锁等待看慢查询日志与执行计划5.4 基线对比有没有基线决定结论的可信度单次压测的数据只能说明这次是什么样说明不了是不是变差了。真正有价值的评估是版本间对比同一个场景、同一套数据量、同一份脚本跑上一版和这一版看关键指标的变化幅度。行业里常用的经验阈值是P95 波动超过 10%、TPS 下降超过 5%就需要给出解释。所以我的建议是每轮压测都要归档脚本版本、数据量、机器规格、关键指标快照一个都不能少。半年后有人问这个接口是不是变慢了你才有得比。这份归档的成本很低但省下来的排查时间是以天计的。6. 通过标准怎么定分层阈值加场景准入终于说到核心问题了。性能测试通过标准这件事很多团队压根没有全靠压测结束后大家拍脑袋。我见过的最离谱的情况是标准写在某个人的聊天记录里。这不行标准必须是文档化的、可量化、可复现的。6.1 一个合格的通过标准包含四要素范围对哪些场景、哪些接口生效哪些不适用。指标用哪几个指标判定口径是什么。阈值每个指标的上限或下限。容错允许的例外情况比如冷启动前 1 分钟不计入统计。缺了任何一个标准都会在执行时产生争议。尤其是容错这一项几乎所有人都会漏掉结果就是每次压测报告都要为预热阶段的异常数据算不算讨论半小时。6.2 分层阈值不同层级用不同严苛度我给一个可以直接借鉴的阈值框架具体数字需要按你的业务调整层级指标参考阈值判定方式用户体验层P95 响应时间≤ 500 ms全场景统计排除预热 1 分钟用户体验层P99 响应时间≤ 1500 ms全场景统计用户体验层事务错误率≤ 0.1%以业务事务为单位应用接口层平稳段 TPS≥ 目标 TPS取 10s 窗口均值应用接口层线程池队列积压峰值 容量 80%峰值采样资源层CPU 使用率平均 ≤ 70%峰值 ≤ 85%排除预热段资源层内存无持续增长趋势长稳测试 1 小时以上稳定性GC 停顿单次 ≤ 200 ms频率稳定长稳测试观察这里面我个人最看重两条内存无持续增长趋势和GC 停顿稳定。它们不写在标准里也能测但写进去之后团队才会真正去做长稳测试——而生产事故的相当一部分恰恰是长稳测试才能暴露的。6.3 稳定性与劣化标准要单独立项功能压测达标不代表系统能稳定跑一整天。长稳测试通常在 2 小时到 12 小时之间视业务周期而定要看三件事内存是否在 GC 后回落到基线水平、连接池活跃数是否回落到低位、错误率是否随时间漂移。单调上升的内存曲线几乎必然指向泄漏别抱侥幸心理。6.4 红线项和观察项分开写标准里最好明确区分两类红线项不达标不允许上线比如错误率超标、核心接口 P95 超标和观察项需要记录并跟踪但不阻断上线比如非核心接口的 P99、资源层的峰值利用率。这样分的好处是评审时不需要为每个指标都争个你死我活团队的执行成本会低很多。全都要卡死的结果往往是标准定了没人执行最后又回到拍脑袋。7. 用 JMeter 跑一轮时指标采集和判定落在哪几个点上工具是采集器但采集位置选错数据就是错的。这一节讲讲用 JMeter 做一轮完整压测时哪些配置点直接决定了指标口径。7.1 线程组参数不这么设就是白测线程数、Ramp-up 时间、循环次数或持续时间这三个参数决定压力模型。我的习惯是能不用循环次数就不用改用持续时间Scheduler因为固定循环次数在响应时间变化时会自动改变实际压力导致结果不可比。参数建议设置理由线程数按利特尔法则换算保证系统并发符合目标Ramp-up目标线程数的 1/10 到 1/5避免瞬间冲击造成误判持续时间至少 10 分钟让指标进入平稳段思考时间用常数或随机定时器模拟更接近真实用户行为7.2 监听器别乱开用后端监听器落库GUI 模式下开聚合报告、查看结果树会让施压机性能暴跌。正确做法是正式压测全部用非 GUI 模式结果写入 jtl 文件事后生成 HTML 报告。如果需要实时观测用后端监听器把指标推到外部时序库在另一台机器上看。查看结果树在正式压测时一定要关掉它会把每个请求的完整响应都保存下来几百万请求能把磁盘写满也会严重拖慢施压机。7.3 断言与事务控制器错误率的口径在这里定死JMeter 默认把 HTTP 5xx 视为失败但业务失败往往返回的是 200 错误码。必须在响应断言里加上业务码校验否则错误率永远是 0。另外把一次完整业务操作比如登录 → 查商品 → 下单 → 支付放进事务控制器并勾选生成父样本这个事务的耗时和成功率就是你要的核心指标。这样统计出来的错误率才是业务视角的而不是接口视角的。7.4 施压机与被测机资源都要采JMeter 侧可以用 PerfMon 类的插件采集被测机的 CPU、内存、磁盘、网络也可以直接对接外部监控系统。关键是要保证施压机本身的资源不会被自己压满——如果施压机 CPU 超过 80%那这一轮数据基本可以作废。7.5 报告里必须有这几样东西我审报告时先看有没有这几项测试环境规格与数据量、脚本与参数化数据说明、压力模型线程数、ramp-up、持续时间、分层指标统计表、瓶颈分析、以及结论对通过标准的逐条比对。缺了压力模型数据无法复现缺了环境说明结论无法迁移缺了逐条比对结论就是主观判断。这三样凑齐一份报告才算能用。8. 几个看着达标、其实不达标的现场最后说说我踩过或者见过的几个坑都属于数字很漂亮但结论是错的这一类。8.1 压测环境的数据量只有生产的百分之一这是最普遍也最致命的问题。测试库只有 10 万条订单生产有 1 亿条同样是走索引的查询执行计划可能完全不同——小表可能走全表扫描反而更快大表走索引才有优势或者反过来小表命中缓存的概率高得多。数据量不一致的压测只能验证逻辑正确性不能验证性能。我的做法是至少让测试库的数据量达到生产的一个可接受比例比如 10%并且分布特征要一致——订单的时间分布、用户分布、状态分布都得用脱敏后的生产数据构造不能随机生成。8.2 缓存预热之后测出的漂亮数字压测脚本通常从第一条数据开始跑跑几轮之后缓存全热了指标自然好看。但生产环境是冷热混合的而且缓存会因为扩容、重启、过期而周期性地变冷。所以我习惯在压测方案里明确必须包含冷启动场景以及在缓存被清空后的恢复能力测试。这一轮的数据往往比热缓存下的数据有价值得多。8.3 只压单接口不压混合场景单接口压到 1000 TPS 不代表系统能撑住 1000 TPS 的混合流量。真实流量里下单、查询、支付、退款同时存在它们共享线程池、数据库连接、缓存资源互相之间会有干扰。混合场景才是生产流量的正确抽象。我的做法是按真实流量的接口占比配置吞吐量控制器让各接口按比例施压同时观察整体资源消耗。这样做出来的容量结论可用性高一个档次。8.4 忽略了慢请求累积有一类问题特别隐蔽系统在压力下不会立刻崩而是慢请求逐渐堆积队列越排越长直到某个时刻突然雪崩。表现就是错误率在前 20 分钟都是 0第 25 分钟突然跳到 30%。如果你只压 10 分钟永远发现不了这个问题。这也是我坚持长稳测试至少跑 1 小时的原因——故障的种子往往在系统看起来最健康的时候已经埋下了。8.5 只盯阈值不看余量标准写的是CPU ≤ 70%测试结果 68%看起来通过。但如果这个数字是在目标 TPS 下测出来的而生产峰值可能是目标的 1.5 倍那 68% 对应的就是 100% 以上。所以我评估通过与否时从来不只看当前压力下的指标一定会看压力曲线上的余量从目标压力到拐点之间还有多少空间。余量不足的系统即使当期达标也建议在上线前做一轮扩容或优化。实际操作中我一般会要求在目标 TPS 的 1.3 倍压力下核心指标仍不突破红线。这条要求救过我两次——一次是发现了缓存容量不足一次是发现了异步任务队列在高压力下会阻塞主线程。这些在刚好达标的压力下都是看不到的。提示慢请求累积和余量不足这两类问题只有在阶梯加压加长稳测试的组合下才会暴露。如果你的压测流程只有恒定压力 10 分钟建议至少先把时长拉长到 30 分钟投入很小收益很大。我个人在实际操作中的体会是性能测试这件事工具熟练度只占三成剩下七成全在口径对齐、数据构造和结论解读上。把指标定义写清楚、把通过标准文档化、把每轮数据归档好这三件事做扎实比换什么工具都管用。
返回列表