ARTICLE DETAIL

资讯详情

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

TPS、并发数、响应时间三者底层关系详解:从公式推导到JMeter实测

TPS、并发数、响应时间三者底层关系详解:从公式推导到JMeter实测 先抛一个面试中经常出现的问题你说你会做性能测试那 TPS、并发数、响应时间三者之间存在什么样的底层关系很多同学能背出“TPS 是每秒事务数并发数是同时请求数响应时间是请求耗时”但一旦被问到“假设响应时间从 200ms 涨到 400ms并发数不变TPS 会怎么变”就卡住了。更常见的是压测报告里写着 TPS 很高结果一上生产就崩。原因往往不是压测工具用得不对而是没有真正理解这三个指标背后的数学关系。这篇文章不打算只讲概念而是从公式推导、排队论视角、JMeter 实测、常见“TPS 虚高”现象以及面试答题思路几个维度把三者的底层关系彻底讲清楚。无论你是刚接触性能测试的新手还是准备跳槽的性能测试岗位面试者都可以把这篇当作一份系统性的参考笔记。1. 性能测试的三个核心指标到底在衡量什么在推导公式之前先把三个指标的定义边界理清楚。很多性能测试的误判都是从概念混淆开始的。1.1 TPS系统每秒能处理多少笔完整事务TPS 全称是 Transactions Per Second即每秒事务数。这里的“事务”可以是一个 HTTP 请求、一笔数据库交易、一次消息发送甚至是一段完整的业务操作链路。在 JMeter 中TPS 通常通过聚合报告中的 Throughput 来查看单位可以是“/sec”也就是每秒完成的请求数。需要特别注意的是TPS 衡量的是系统端的处理能力而不是客户端发了多少请求。如果服务端处理不过来即使客户端每秒发 1000 个请求TPS 也可能只有 300。容易混淆的概念是 QPSQueries Per Second很多文章把两者混用。严格来说QPS 更多用于描述查询类接口的每秒查询数而 TPS 用于描述完整事务的处理能力。如果你的接口只是简单的查询操作两者可以近似相等如果涉及下单、支付、回调等多步操作TPS 就要按完整业务链路来统计。1.2 并发数同一时刻有多少请求在系统内流转并发数的定义看似简单同一时刻有多少请求同时打向系统。但这里有一个常见的误区。在 JMeter 里线程组配置的线程数并不完全等于“真实并发数”。一个线程在脚本里可以循环发请求它发出第一个请求、等待响应、处理数据、再发第二个请求这个过程是有间隙的。真正处于“系统内部处理中”的请求数量才是有效的并发数。更严谨的说法是并发数指的是同一时刻处于系统中的请求数量包括正在排队等待的、正在被服务端处理的以及正在网络传输中的请求。举个例子如果线程组设置了 100 个线程每个线程都在不停地发请求服务端平均响应时间是 100ms那么同一时刻可能有接近 100 个请求正在被处理或等待。但如果脚本里加了思考时间Think Time每个线程发完一个请求后要等 3 秒再发下一个那么系统内实际的并发请求数量就会远小于 100。1.3 响应时间用户从发出请求到收到结果要等多久响应时间也叫 RTResponse Time通常指从客户端发起请求开始到客户端收到完整响应为止的总耗时。在 JMeter 聚合报告中你会看到 Average、Median、90% Line、95% Line、99% Line 等指标。很多新手只看 Average这其实很危险。举个例子一次压测中900 个请求耗时 100ms100 个请求耗时 5000ms。平均值是(900 * 100 100 * 5000) / 1000 590ms。从平均值看590ms 似乎还能接受但实际上这部分慢请求可能来自超时重试或服务端线程阻塞对用户体验的影响远远大于平均值体现的程度。所以在分析响应时间时建议重点关注 95% Line 和 99% Line。这两个值能更准确反映大多数请求的真实体验也能暴露长尾延迟问题。2. 三个指标之间的底层数学关系这一节是整篇文章的核心。三个指标之间不是孤立的它们通过一个非常简单的公式建立关联而实际系统中的表现又会因为排队效应变得复杂。2.1 从定义推导TPS、并发数、响应时间的最小公式先回到最基本的关系并发数 TPS × 响应时间这个公式也可以写成TPS 并发数 / 响应时间为什么成立我们用单位来推导更容易理解。TPS 的单位是“事务/秒”响应时间的单位是“秒”。两边相乘事务/秒 × 秒 事务得到的“事务”数量可以理解为同一时刻系统内正在处理的请求数量也就是有效并发数。举个例子系统平均响应时间 RT 200ms 0.2s目标 TPS 500需要的并发数 N 500 × 0.2 100也就是说如果要让系统每秒处理 500 个请求并且每个请求平均耗时 200ms那么同一时刻大约需要有 100 个请求在系统中流转。反过来如果固定并发数为 100响应时间从 200ms 涨到 400ms那么 TPS 会变成TPS 100 / 0.4 250TPS 直接下降到原来的一半。这就是三者的底层关系响应时间的变化会直接影响 TPS而并发数更像是一个“中间变量”。在实际压测中你往往是通过设置线程数并发来观察 TPS 和响应时间的变化但决定系统吞吐上限的通常是服务端的资源处理能力和响应时间共同作用的结果。2.2 Little 定律用排队论理解系统吞吐上面这个公式本质上就是排队论中的 Little 定律Littles Law。Little 定律的经典形式是L λ × W其中L 表示系统中平均请求数量也就是并发数λ 表示请求到达率也就是 TPSW 表示每个请求在系统中停留的平均时间也就是响应时间这个定律在稳定的系统中是恒成立的。它不要求请求到达的分布是均匀的也不要求服务时间是固定的只要系统处于平稳状态平均值之间就有这个关系。理解 Little 定律的意义在于它能帮助你判断一份压测数据是否“自洽”。比如一份压测报告声称平均并发 200平均响应时间 50msTPS 是 3000。我们来验算一下200 / 0.05 4000理论 TPS 应该是 4000但报告里写的是 3000这时就要警惕了。数据之间不自洽说明压测过程中可能存在线程阻塞、请求排队、脚本等待、断言错误或者统计口径出了问题。反过来如果报告给出平均并发 200平均响应时间 100ms实测 TPS 是 2000那么这份数据是自洽的因为200 / 0.1 2000。你可以用这个方式来交叉验证 JMeter 聚合报告、Grafana 监控数据和服务端日志很多“看起来没问题”的压测数据一验算就露馅了。2.3 拐点效应为什么并发翻倍 TPS 不一定翻倍很多不了解底层关系的人会有一个直觉线程数从 100 涨到 200TPS 应该也会翻倍。实际压测中几乎不会出现这种情况。原因在于系统资源是有限的。当并发数较低时服务端处理能力有富余请求基本不需要排队TPS 随并发增长而线性上升。此时系统处于“轻负载区”。随着并发继续增高服务端资源逐渐被打满部分请求开始排队。此时 TPS 的增速放缓响应时间开始明显上升。系统进入“拐点区”。当并发数继续增长到超过系统的最大处理能力时TPS 不再上升甚至会下降响应时间急剧恶化大量请求排队超时。系统进入“过载区”。可以用一个简单的示意图来理解TPS ^ | * | * * | * * | * * * * * * - 过载区TPS 不再上升 | * (拐点) | * | * | * ------------------------- 并发数这个拐点对应的并发数在面试中经常被问到。它其实就是“系统能支撑的最大合理并发数”。实际工作中建议在拐点附近的并发区间多做几次重复压测观察 TPS 和响应时间是否稳定再结合业务高峰时段的流量模型确定一个安全的容量水位。2.4 思考时间Think Time对公式的影响实际压测脚本里几乎不会让线程无间隔地疯狂发请求。真实用户的每一步操作之间都有停顿比如浏览页面、填写表单、思考下一步。这个停顿就是思考时间Think Time。加入思考时间后公式要扩展为并发数 TPS × (响应时间 思考时间)推导逻辑和之前一样只是每个请求占用的时间变长了。原来一个请求从开始到结束只占 RT 秒现在占 RT T 秒。举个例子RT 200ms思考时间 T 3000ms目标 TPS 100需要的并发数 100 × (0.2 3) 320对比无思考时间的情况100 × 0.2 20两者差了整整 16 倍。这就是为什么在压测和峰值流量预测时必须先明确业务模型用户平均一次会话会调用几次接口每次操作间隔多久如果忽略思考时间用无停顿脚本压出来的并发数根本不能代表真实用户场景TPS 会虚高后面的容量规划也会全线跑偏。3. 用 JMeter 实测验证三者关系理论讲完了接下来用 JMeter 实际压一次看看 TPS、并发数、响应时间在真实场景下是怎么联动的。这里以 JMeter 5.x 为例新版 6.x 界面略有差异但配置思路完全一致。3.1 环境准备与线程组设计用 JMeter 压测之前要有一个明确的目标接口。本地可以先用一个简单的 Spring Boot 接口做示例接口内部模拟 100ms 耗时方便观察三者的变化。// 文件路径src/main/java/com/example/demo/PerfController.java RestController public class PerfController { GetMapping(/api/perf) public String perf() throws InterruptedException { // 模拟业务处理耗时 100ms Thread.sleep(100); return ok; } }JMeter 脚本的核心配置如下线程数先用 20 跑一轮再用 50、100 递增Ramp-Up Period10 秒让线程逐步启动避免瞬时冲击循环次数设置一个较长时间比如 5 分钟便于观察稳定态HTTP 请求指向本地 Spring Boot 服务的/api/perf线程组在 JMeter 里的 GUI 配置对应如下参数配置项示例值说明Number of Threads (users)逐步递增线程数对应压测并发Ramp-Up Period (seconds)10线程启动时间防止瞬间灌入Loop Count300单线程循环次数保证压测时长Duration (seconds)300也可以直接配置压测运行时长这里需要注意如果同时设置了循环次数和 DurationJMeter 以 Duration 为主。推荐使用 Duration 方式控制压测时长线程数设置得足够大让 JMeter 在指定时间内持续产生负载。3.2 通过阶梯加压观察 TPS 曲线拐点确认系统支持的最大并发数最直观的方式不是“一次性给到很大并发”而是阶梯加压。所谓阶梯加压就是把并发数按梯度逐级升高每一级保持 1 到 2 分钟观察 TPS 和响应时间的变化。举例阶段线程数观察 TPS观察 RT结论第 1 级20约 190约 100ms线性区TPS 随并发上升第 2 级50约 480约 105ms线性区接近拐点第 3 级80约 520约 150ms拐点区TPS 增速放缓第 4 级120约 510约 400ms过载区TPS 不再上升第 5 级200约 450约 800ms过载区RT 明显恶化注意上表的数据只是为了说明趋势真实的数值取决于你的服务器配置、接口逻辑和网络环境。但从趋势上可以明显看到20 到 50 并发时TPS 接近线性增长。80 并发附近出现拐点TPS 增速明显放缓。120 并发以后TPS 开始持平甚至下降响应时间快速飙升。这个拐点位置就是系统在当前硬件和配置下的吞吐上限。实际操作时建议使用 JMeter 的 Ultimate Thread Group 插件来实现阶梯加压它可以在一个线程组内配置多个阶段每个阶段指定不同的线程数、启动时间和持续时间。3.3 如何确认系统能支撑的最大并发数阶梯加压之后可以通过三个指标综合确认最大并发数TPS 是否还在增长如果并发增加但 TPS 不再增长说明系统吞吐已经达到瓶颈。响应时间是否可以接受如果响应时间已经超出业务要求的安全水位比如原本要求 200ms现在已经 800ms即使 TPS 还在微涨也不能继续加压。错误率是否明显上升一旦出现大量超时或连接异常说明系统已经过载。更科学的做法是多次重复测试。比如在拐点附近的并发数下跑三次每次持续 5 到 10 分钟观察 TPS 曲线是否平稳。如果三次测试的 TPS 波动范围小于 5%可以认为这个并发规模下系统是稳定的。另外推荐使用非 GUI 模式执行测试jmeter -n -t /path/to/test-plan.jmx -l /path/to/result.jtl -e -o /path/to/report参数说明-n表示非 GUI 模式-t指定测试计划文件-l指定结果日志文件-e测试结束后生成 HTML 报告-o指定 HTML 报告输出目录用非 GUI 模式避免 JMeter 自身界面消耗系统资源压测数据更准确。3.4 通过公式反推合理并发数如果已经知道目标 TPS 和期望响应时间可以通过公式反推并发数。假设业务目标目标 TPS 1000期望平均响应时间 ≤ 200ms用户平均思考时间 2000ms业务侧调研得到那么并发数 TPS × (响应时间 思考时间) 1000 × (0.2 2) 2200这个 2200 是 JMeter 中需要配置的线程数近似值它考虑了真实用户操作中存在思考时间的场景。如果不加思考时间同样达到 1000 TPS 只需要并发数 1000 × 0.2 200两种方式得到的“并发数”差了 11 倍。所以面试中如果被问到“系统能支撑多少并发”一定要先反问你说的并发指的是线上用户数还是压测工具里的线程数两者完全是不同量级的。4. 实战中常见的 TPS 虚高问题热词里提到“tps虚高”这是性能测试里非常典型的问题。所谓 TPS 虚高是指压测报告里的 TPS 数据看起来很漂亮但并不能真实反映系统的处理能力。4.1 什么是 TPS 虚高TPS 虚高通常有以下几种来源第一脚本只打了一个无状态、无逻辑的接口。比如直接请求一个返回固定字符串的静态接口而真实业务中客户端的请求链路包含鉴权、参数校验、数据库查询、第三方调用等两者完全不在一个量级。第二断言被关闭或写错了。JMeter 的断言如果配置不合理服务端返回 500 错误也会被统计成成功事务。TPS 数据自然虚高。第三响应时间极短大量请求瞬时完成。比如本地压测访问静态页面RT 只有 1msTPS 算出来自然很高但生产环境不存在这种请求模型。第四忽略思考时间和真实用户行为。把所有线程都配置成无停顿疯狂发请求一个线程每秒可以打几十次接口TPS 当然高但没有业务参考价值。4.2 现象与根因用一个场景来说明。压测报告显示 TPS 为 5000平均响应时间 20ms并发 100。按照公式验算100 / 0.02 5000数据是自洽的看起来没有任何问题。但是如果你去看被压接口发现它只是一个内存缓存接口不查数据库、不调远程服务、不做任何业务计算那么这 5000 TPS 代表的是“缓存读取能力”而不是“业务系统能力”。更隐蔽的情况是压测脚本里写了一个 JSR223 采样器但脚本本身只做了简单循环真实业务中的复杂处理逻辑完全没有模拟。// 示例JSR223 采样器中模拟业务处理耗时 def start System.currentTimeMillis() // 模拟业务处理 200ms Thread.sleep(200) def elapsed System.currentTimeMillis() - start log.info(business elapsed: elapsed)这段脚本的问题在于它把业务处理简化成了固定 sleep。真实业务中200ms 里可能包含数据库查询、缓存读写、MQ 发送、外部接口调用等多个环节负载模型完全不同。用固定 sleep 模拟出来的 TPS在生产环境再现度很低。4.3 如何避免虚高要避免 TPS 虚高需要做到以下几点脚本必须基于真实业务链路对核心接口进行取样而不是只测一个“最容易的接口”。请求参数要尽可能贴近真实值。压测一个查询接口如果所有请求都查同一条数据数据库缓存命中率会变得极高TPS 就虚高了。配置合理的断言。至少校验 HTTP 状态码必要时要校验响应体中的关键业务字段。加入合理的思考时间。除非压测目标是“极限饱和”例如全链路压测中模拟瞬间洪峰流量否则都应该按真实用户操作模型加入思考时间。压测前清理外部依赖的不确定性。如果接口依赖第三方服务可以使用 Mock 或测试桩避免第三方抖动造成数据失真。4.4 用结果验证聚合报告和压测日志怎么对照压测结束后不要直接看聚合报告里的 TPS 就下结论建议做一次数据交叉验证。第一步看聚合报告中的三个关键数据Samples总请求数Average平均响应时间ThroughputTPS第二步用公式验算并发数 Throughput × Average将计算出的并发数和 JMeter 线程组配置的活跃线程数对比。如果差距很大说明压测过程中线程没有保持饱和状态可能存在思考时间、断言失败、等待超时等情况需要进一步排查脚本逻辑。第三步查看服务端日志和监控。TPS 上涨时数据库的连接数、CPU 使用率、内存占用是否同步变化。如果 JMeter 显示 TPS 很高但服务端监控指标异常平静压测数据大概率是有问题的。5. 高频面试题与答题思路性能测试岗位面试中关于这三个指标的问题几乎是必考项。这一节整理几个典型问法和回答框架。5.1 面试官问“三者的底层关系”怎么答推荐分三层回答第一层直接给出公式并发数 TPS × 响应时间同时用单位推导说明这个公式为什么成立体现你理解的是本质而不是背答案。第二层结合 Little 定律解释公式的适用范围。说明在系统稳定的前提下平均并发数等于平均到达率乘以平均响应时间。能说出来 Little 定律会让面试官觉得你有理论深度。第三层结合压测实践说明三者的动态关系。比如增加并发时TPS 先线性增长到达拐点后不再上升响应时间逐渐恶化。最后点出真正决定 TPS 上限的不是并发数多少而是系统资源和业务逻辑的处理能力。5.2 如果系统并发数上不去怎么排查这个问题考察的是实际排查能力可以从以下几个方面回答检查服务端资源CPU 是否打满、内存是否频繁 GC、磁盘 IO 是否繁忙。检查连接池配置数据库连接池、HTTP 连接池、线程池是否设置过小。检查锁竞争是否存在数据库行锁、表锁、分布式锁导致的串行处理。检查脚本本身线程组配置的线程数是否真的全部跑起来JMeter 日志中是否有线程启动失败。检查网络链路压测机到服务端之间是否存在带宽瓶颈。重点是不要一上来就猜“配置问题”要先看监控数据用数据定位瓶颈。5.3 如何设计一个可复现的性能测试场景设计压测场景时至少要明确以下几点目标是什么是验证系统能支撑多大业务量还是排查某个接口的性能瓶颈。业务模型是什么核心接口有哪些、占比多少、调用链有多深。数据模型是什么压测数据集是否覆盖真实环境的数据分布比如数据库表数据量是否接近生产。量级模型是什么目标 TPS 怎么定、最大并发怎么算、压测环境能提供多大负载。验收标准是什么TPS 要达到多少、95% 响应时间不超过多少、错误率不超过多少。把这些点讲清楚比单纯说“我用 JMeter 压了一下”更有说服力。6. 最佳实践与工程建议最后这部分从工程落地的角度补充一些长期有用的建议。6.1 性能测试脚本编写规范脚本尽量做到一个人写的、别人能看懂、半年后自己还能维护。使用 CSV 数据文件管理测试数据不要在脚本里写死大量请求参数。用用户自定义变量统一管理服务器地址、端口、超时时间、线程数等常用配置。将断言放到关键业务请求上不要每个请求都加重量级断言否则无效响应时间会拉高。使用循环控制器和事务控制器组织业务链路确保一个线程可以完整模拟一个用户操作路径。压测脚本建议放进 Git 管理和代码一样进行版本控制。接口变更时同步更新脚本。6.2 结果分析要结合业务模型压测得到的 TPS 不是越高越好而是要“够用”。举例来说一个面向企业内部用户的系统日活 5000高峰期集中在上午 9 点到 10 点平均每个用户操作 20 次接口。高峰期 1 小时内大约产生5000 * 20 100000次请求平均每秒约 28 TPS考虑 2 到 3 倍的峰值波动和错误重试目标 TPS 定在 100 到 200 就相对合理了。不要把性能测试的目标定为“把系统压到极限”而是要根据业务模型反推合理水位再确认系统在这个水位下是否稳定。6.3 生产环境验证原则与安全边界性能测试最好不要一上来就打生产。如果确实需要做生产环境的小流量验证一定要遵守以下原则获得明确授权提前和管理层、研发、运维、DBA、业务方同步压测时间窗口。选择业务低峰期执行避免影响真实用户。从极小流量开始例如 1 到 5 个并发观察服务端监控指标稳定后再逐步加压。设置熔断机制一旦错误率超标或响应时间超过阈值立即停止压测。准备回滚和降级方案比如摘除压测流量对应的负载均衡权重。压测结束后检查慢查询日志、错误日志、GC 日志和告警记录确认系统恢复平稳。安全边界和授权问题不是一句空话。在未授权环境下执行压测可能触发限流、封禁、甚至服务不可用。除非是专门的测试环境或明确允许的生产压测窗口否则不要随意对线上地址发起高并发请求。6.4 AI 辅助生成性能测试脚本的注意事项“AI 生成性能测试脚本”是当前比较热门的方向。用 AI 工具确实可以快速生成 JMeter 脚本框架、JSR223 辅助脚本、参数化数据生成逻辑等能节省不少时间。但使用 AI 生成的脚本时要注意以下几点AI 生成的多为“模板”和“示例思路”不代表真实业务链路必须逐行核对逻辑。JMeter 版本差异容易导致脚本不兼容。AI 生成的 JMX 文件可能在旧版本中无法打开建议生成后用目标环境的 JMeter 实际验证。涉及 CSV 路径、JDBC 连接、鉴权方式等配置项时AI 容易出现想当然的写法这些最容易在压测时暴雷。最关键的是AI 无法替代你对业务模型的理解。TPS 虚高的问题往往不是因为脚本不会写而是因为负载模型设计错了。所以我的建议是用 AI 辅助生成脚本框架但性能测试的方案设计、结果分析、瓶颈定位这些核心能力最终还是得靠自己对系统底层的理解。7. 总结TPS、并发数、响应时间三者的底层关系可以浓缩成一个公式并发数 TPS × 响应时间在此基础上加入思考时间后并发数 TPS × (响应时间 思考时间)理解这个关系不是为了背公式而是为了在实际工作中做到三件事通过压测数据判断系统是否还有余量而不是只看 TPS 单个指标。通过公式交叉验证压测报告是否自洽识别“TPS 虚高”问题。根据业务目标和响应时间要求反推需要的并发规模。如果你要准备性能测试面试建议把 Little 定律、拐点效应、阶梯加压方法、TPS 虚高的常见原因都梳理一遍并用 JMeter 亲身跑一次阶梯加压记录下每级并发对应的 TPS 和响应时间。只有亲手试过才能在被问到“三者的底层关系到底是什么”时不只是背答案而是真正讲出系统的行为规律。
返回列表