尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

压力测试实战指南:从核心概念到瓶颈定位全流程解析

压力测试实战指南:从核心概念到瓶颈定位全流程解析 做测试这么多年有一个感受特别深很多系统上线前看着一切正常功能测试全过结果一到流量高峰期就崩了数据库连接池被打满接口响应从几十毫秒变成几秒最后闹到凌晨紧急扩容。这种问题靠功能测试根本发现不了必须靠压力测试提前暴露。压力测试Stress Testing是整个性能测试体系里最硬核、也最容易被误解的一块。很多人觉得压力测试就是拿工具狂发请求看系统什么时候挂其实远没有这么简单。这篇内容我按自己的理解做了一个超详细整理从核心概念、关键指标、工具选型到完整实操流程再到常见的故障排查思路一次讲透。不管你是刚入行的测试新人还是在准备软件测试面试或者即将独立负责一个系统的压测工作这篇都应该能帮上忙。1. 先搞清楚压力测试到底在测什么1.1 压力测试不是使劲点按钮我见过太多人对压力测试的理解停留在用工具并发怼接口。真要这么简单那就不会有那么多系统在双十一、秒杀、抢票这类场景下翻车了。压力测试的定义其实很明确通过逐步增加系统负载观察系统在超过正常预期负载的情况下能否稳定运行以及在何种负载条件下开始出现性能下降、报错甚至崩溃。它回答的核心问题不是系统能处理多少请求而是系统在极端情况下还能不能扛得住扛不住的时候以什么方式失败。这里顺带把几个容易混淆的概念放在一起对比一下这是软件测试面试题里出现频率极高的一组概念区分测试类型核心目的负载特征典型问题负载测试验证在预期负载下性能是否达标模拟正常或略高的并发响应时间是否满足要求压力测试找出系统的性能上限和崩溃点持续加压直到出现拐点系统在什么并发下开始崩稳定性测试验证长时间运行是否可靠保持一定负载持续运行内存泄漏、连接池耗尽容量测试确定系统能支撑的最大规模阶梯式加压寻找最大容量需要多少资源支撑预期用户量压力测试关注的是极限状态。打个比方负载测试是问一个人每天能跑5公里吗压力测试是问这个人连续跑100公里会不会猝死跑到第几公里开始出问题。知道了极限在哪里你才知道日常应该预留多少余量。1.2 为什么非做不可不做压力测试就上线就像不试刹车就上高速不是一定出事但出事就是大事。具体来说压力测试解决以下几个核心问题提前发现性能瓶颈数据库慢查询、缓存穿透、线程池配置不当、内存泄漏这些隐藏问题在低并发下根本不会暴露只有把负载顶上去才会现出原形。为容量规划提供依据业务方问你系统能扛多少用户没有压测数据你只能拍脑袋。有了压测报告你就可以说单实例最高支撑2000 QPS超过这个值需要加机器。验证系统在过载时的表现最好的情况是系统优雅降级最差的情况是进程崩溃、数据丢失。压力测试能帮你验证熔断、限流、降级策略是否真的生效。为稳定性提供信心尤其是银行、支付、电商这类对稳定性要求极高的行业上线前压测是硬性流程。银行软件测试的逻辑更是如此宁可提前测出问题也不能让线上出问题。1.3 压力测试的目标设定动手压测之前先要明确目标。不同阶段、不同系统目标完全不一样验证型目标系统声称能支撑5000 TPS那压测就是验证在5000 TPS下响应时间是否在可接受范围内错误率是否低于阈值。这类目标在功能上线前最常见。探索型目标不知道系统的上限在哪里那就逐步加压从100并发开始逐级升到200、400、800直到系统性能出现明显拐点。这类目标常用于容量评估和技术选型对比。稳定性目标在某个固定压力下持续跑1小时、4小时甚至更久观察系统是否会出现内存增长、性能衰减等长期运行问题。目标设定决定了你的压测方案怎么设计这是整个压力测试工作的第一步也是很多人容易跳过的一步。没有明确目标就开压测工具最后跑出来的数据往往只能看看热闹。2. 核心指标看不懂这些数据等于白测压力测试结束以后会得到一堆数据。这些数据不是拿来看的是用来做判断的。但前提是你要懂每个指标的含义以及它们之间的关系。2.1 TPS 和 QPS系统吞吐能力的度量衡TPSTransactions Per Second指每秒处理的事务数QPSQueries Per Second指每秒处理的查询数。在接口测试场景中很多人把这两个混用因为一个接口请求可以看作一个事务也可以看作一个查询。严格来说一个事务可能包含多个查询但实际工作中绝大多数情况可以画等号。计算方式很简单TPS 总请求数 / 总耗时秒。比如压测10分钟一共完成120万个请求那么TPS就是1200000 / 600 2000。这里有个容易被忽视的细节TPS是压测工具的统计口径它统计的是客户端视角的完成情况并不完全等于服务端的真实处理能力。如果客户端已经出现超时或连接异常统计到的TPS会比服务端实际处理的低。所以做压测时服务端也要同时监控两边数据对照看才有意义。2.2 响应时间和百分位数平均值的陷阱响应时间是最直观的指标但也是被误解最多的指标。很多测试报告只写平均响应时间50ms这是骗人骗己的写法。为什么因为平均值会被极端值拉高同时也会被大量快请求稀释。假设一个接口在压测期间99%的请求都是10ms返回但有1%的请求卡了10秒平均值是110ms左右看着还行但实际上那1%的用户已经卡到怀疑人生。正确做法是看百分位数即 TP50、TP90、TP95、TP99TP5050%的请求响应时间不超过该值代表大多数用户的体验TP9090%的请求响应时间不超过该值TP9999%的请求响应时间不超过该值代表最差一批用户的体验TP99999.9%的请求响应时间不超过该值常用于核心链路场景JMeter的聚合报告Aggregate Report里会直接给出这些数据不用自己算。分析的时候重点关注 TP99如果 TP99 和 TP50 差距过大说明系统存在明显的长尾延迟这往往是某个资源竞争或者垃圾回收导致的。2.3 并发用户数、并发请求数和资源利用率这里有个概念必须先掰清楚并发用户数不等于并发请求数也不等于TPS。1000个在线用户同一时刻真正在发请求的可能只有100个而服务器每秒钟能处理的请求可能是5000个。这三者之间的换算关系取决于用户的操作频率和思考时间。资源利用率是压测时必须实时监控的指标包括CPU使用率单核还是多核被打满用户态和内核态的比例是否正常内存使用率是否有持续增长趋势是否存在内存泄漏磁盘I/O读写延迟、队列长度、吞吐量网络I/O带宽占用、连接数、重传率线程池/连接池使用率活跃线程数、等待队列长度、连接获取等待时间判断系统是否达到瓶颈不能只看某一个指标要综合看。比如CPU没打满但TPS上不去那瓶颈就不在CPU上可能在数据库锁、网络带宽或者代码本身的串行逻辑上。2.4 错误率和性能拐点错误率是压测报告里最敏感的数据。理想情况下压测全程错误率为0但实际操作中几乎不可能。关键是看错误出现在什么阶段、什么类型。连接超时说明后端处理不过来请求堆积在等待队列请求超时说明单个请求处理时间超过了客户端设定的超时阈值连接被重置可能是服务端主动断连也可能是负载均衡层做了拦截5xx状态码说明服务端已经进入异常状态性能拐点是压测过程中需要重点观察的现象。典型的场景是并发从100升到200时TPS线性增长从200升到300时TPS增长变缓从300升到400时TPS不升反降错误率开始飙升。这个不升反降的点就是性能拐点它意味着系统已经过载继续加压只会让情况更糟。我个人习惯在压测过程中画一条TPS随并发变化的趋势曲线拐点出现的位置就是系统真实承载能力的上限。后续做容量规划、限流阈值设定都以这个数据为依据。3. 工具选型别一上来就只认JMeter压力测试工具太多了每个都有自己适合的场景。选工具的标准不是哪个最流行而是哪个最适合当前项目的技术栈和测试目标。3.1 接口和协议压测工具JMeter开源、免费、生态成熟支持HTTP、HTTPS、WebService、JDBC、JMS等几乎所有主流协议。图形化操作界面上手门槛低而且有完整的报告体系。是目前国内使用率最高的压测工具面试被问到的概率也最大。wrk / wrk2基于C语言的高性能HTTP压测工具单机就能压出很高的并发。适合快速对某个接口做冒烟式压测但不支持复杂的业务脚本和参数化。Linux下用起来很顺手。Apache abApache自带的压测工具轻量简单适合临时验证接口性能。但功能非常有限不支持场景编排也不适合复杂压测。Locust基于Python的开源压测工具用代码定义用户行为支持分布式压测。适合写复杂业务场景但对Python水平有一定要求。k6基于Go语言的压测工具脚本用JavaScript编写性能好支持云原生部署。近年很火适合对性能要求高、有DevOps基础的团队。LoadRunner商业工具中的老大哥功能强大支持协议极多适合大企业复杂系统。但价格高昂学习曲线陡峭现在的互联网公司用得越来越少了。做技术选型的时候我的建议是大多数Web项目首选JMeter理由有三点一是免费二是资料多三是公司内外协作方便。即使个人电脑上没装Linux环境Windows/macOS都能跑起来。3.2 硬件资源压测工具压力测试不只是测接口很多时候还要测服务器本身的硬件稳定性。这也是热搜词里cpu压力测试怎么开gpu压力测试(gpu-burn)工具r23压力测试软件这些词的来源场景。CPU压力测试Linux上最常用的是stress-ng可以指定压力类型CPU计算、内存分配、I/O读写等和压力时长。Windows上可以用 AIDA64 的系统稳定性测试或者直接跑 Cinebench R23 这种专业渲染工具来拉满CPU负载。GPU压力测试最知名的是gpu-burn专门在Linux下对NVIDIA显卡做高负载运算测试用来验证GPU在满载情况下的稳定性和散热能力。Windows端常用 3DMark 的 Time Spy 压力测试或 FurMark通过持续渲染高负载场景来测试显卡稳定性。内存压力测试Linux下可以用memtester和stress-ng的--vm参数Windows下用 MemTest86 这类工具。这在存储压力测试场景中很常见比如你怀疑内存条有问题或者要验证应用内存占用是否泄漏跑一轮就能发现。磁盘压力测试用fio工具做IOPS、吞吐量和延迟测试可以模拟随机读写、顺序读写等多种负载模式。这里多说一句硬件压测和应用压测往往是配合使用的。比如你压测一个视频转码服务CPU必须拉满这时候就要先确认CPU在持续高负载下的稳定性否则应用压测过程中CPU降频或者死机你就分不清是应用的问题还是硬件的问题。3.3 压测工具选型的实操建议选型没有什么标准答案但有几个经验原则可以参考协议匹配优先先确认被测系统的协议类型。如果是纯HTTP接口JMeter、wrk、k6随便选如果是数据库JMeter的JDBC插件或者专门的数据库压测工具有更合适的。脚本复杂度决定选择只是简单压一个GET接口用wrk就够了要模拟用户登录、浏览、下单、支付这种多步骤场景还是JMeter更合适。团队技术栈要考虑团队都是Python背景Locust的学习成本低很多团队有Go基础k6是不错的选择。工具是给人用的团队成员用得顺手才是硬道理。分布式压测是后期的必经之路单机压测到一定规模就上不去了因为压测工具本身也消耗系统资源。JMeter支持 Master-Slave 分布式压测k6、Locust本身也支持分布式部署选型时把这个因素考虑进去。4. 压力测试实操从0到1跑完一轮完整压测工具选好了接下来就是实战。我以最常用的 JMeter 为例完整梳理一遍压测的流程和关键动作。这套流程不管用什么工具思路都是通用的。4.1 需求分析和场景设计压测不是直接打开工具就开始发请求先要回答几个问题压什么接口是登录接口、下单接口还是查询接口还是整个业务流程压多少并发这个数据怎么来可以基于现有线上流量统计也可以基于业务预期。比如业务方说未来三个月注册用户要到100万日活10万那核心接口的并发就可以按日活/忙碌小时/3600粗算一个基础值再乘一个峰值系数。压多长时间普通验证跑10-15分钟足够稳定性测试至少1小时起步。成功标准是什么TPS目标值、TP99响应时间上限、错误率上限这些要在压测前就定好不然压完没法评估结果。场景设计时我的建议是核心链路优先。不要试图一次性把所有接口都覆盖到先把最关键、最影响用户体验的接口挑出来单独压测然后做组合场景压测。组合场景要参考真实的用户操作比例比如登录和查询的比例可能是1:10那就按这个比例分配压测流量。4.2 脚本准备和参数化JMeter脚本准备过程中有几个关键点容易踩坑线程组设置。线程数Number of Threads代表并发用户数Ramp-Up Period代表多长时间内启动所有线程。如果设置了100个线程、Ramp-Up为10秒那么每秒增加10个线程。这里有个常见误区Ramp-Up设为0不代表没有效果而是代表立即启动所有线程会瞬间产生非常大的冲击。压测初期我通常设置一个递增的Ramp-Up比如60秒让系统逐步承受压力这样能更清晰地观察到不同负载阶段的表现。循环次数和持续时间。更推荐用Duration持续时间控制压测时长比如固定压5分钟而不是固定循环100次。因为固定次数的压测总耗时受系统响应速度影响系统变慢时压测时间会被拉长数据可比性就差。参数化。这是压测实录中最重要也最容易忽略的环节。如果压测请求里的数据都是写死的同一个值那就等于在测缓存测出来的TPS可能虚高。比如压测用户查询接口所有请求都查同一个userId第一次查询后数据进了缓存后面的请求全部命中缓存这个数据完全不能反映真实性能。常规做法是使用JMeter的CSV Data Set Config准备一批测试数据存到CSV文件里每个请求取一行循环使用。不同场景对数据的要求不一样查询类接口准备一批真实存在的ID注意不要只用一个登录接口准备多个测试账号密码避免账号被锁定影响压测写操作接口注意数据清理压测会产生海量脏数据压测完要清掉4.3 测试执行和实时监控脚本准备好后正式执行压测。这一步最忌讳的是脚本一跑就等着出结果。压测过程中必须实时监控因为很多问题只在特定负载阶段出现错过了就不好复现了。我个人的执行习惯是分阶段进行预热阶段1-2分钟用小并发比如10-20线程跑起来确认脚本没问题、参数化正确、被压测环境没有报错。阶梯加压阶段逐步提高并发观察TPS和响应时间的变化趋势。每提升一档等系统稳定1-2分钟再继续加。持续压测阶段达到目标并发后保持压力持续运行一段时间观察系统是否有性能衰减、内存增长等问题。释放阶段压测结束后不要立即关闭脚本观察系统恢复到正常状态需要多长时间这也能反映系统的自愈能力。监控方面至少要做到以下几条通过网络监控工具看服务端的CPU、内存、磁盘I/O、网络I/O用top、free、df -h、iostat、sar这些Linux基础命令做系统层监控查看应用日志关注错误日志和慢请求日志监控中间件状态数据库连接数、Redis命中率、消息队列堆积量这个过程中如果发现TPS急剧下降、错误率飙升、CPU持续100%就要及时判断是继续加压还是停止排查。不要为了追求一个好看的结果而硬撑着跑完压测的目的是发现问题不是交差。4.4 结果分析和瓶颈定位压测跑完到了最考验功力的环节数据分析。除了直接看JMeter聚合报告里的TPS、响应时间、错误率更重要的是把服务端的监控数据和压测工具的统计数据对照起来看。以最常见的TPS上不去问题为例排查思路大致是先看服务端CPU如果CPU已经满负荷说明计算密集重点排查应用代码效率、GC频率再看数据库如果CPU没打满但数据库的CPU高、慢查询多瓶颈在存储层检查连接池和线程池看线程池是否打满请求是否在排队。线程池打满的典型特征是TPS上不去、响应时间线性增长检查外部依赖被测系统依赖的第三方接口、下游服务是否成了瓶颈可能导致同步阻塞检查网络和负载均衡带宽是否打满、负载均衡的转发能力是否受限这里有一个我踩过很多次的坑压测结果不好第一反应不要怀疑系统代码先检查压测工具本身。因为JMeter单机压测能力有限线程数开得过大JMeter自身的CPU和内存会成为瓶颈导致发压能力不足。曾经有一次压测TPS始终上不去排查了很久服务端最后发现是JMeter所在机器只有4核CPU压测线程开到了500JMeter进程CPU已经100%根本发不出更多请求。压测机的性能必须远高于被测系统否则测出来的不是系统瓶颈是压测工具瓶颈。5. 常见问题与排查技巧实录压测做得多了遇到的问题也就那么多。我把高频问题整理成速查表每个都对应到具体的排查方向和实操建议。现象可能原因排查方向TPS上不去CPU打满代码计算密集、GC频繁用JProfiler/Arthas分析CPU热点优化代码逻辑TPS上不去CPU没打满锁竞争、线程池配置过小、数据库慢查询查看线程Dump、SQL慢日志调整连接池和线程池参数错误率飙升连接池耗尽、请求超时、服务端处理不过来检查连接池配置、超时设置配合日志定位异常类型响应时间周期性飙高GC停顿、定时任务抢占资源检查GC日志观察定时任务执行时间窗口压测一段时间后TPS逐渐下降内存泄漏、缓存失效、连接未释放观察内存和FD文件描述符变化做堆内存分析数据库CPU高但应用CPU低SQL执行慢、缺少索引、缓存命中率低开启慢查询日志分析执行计划补充索引接口返回数据不一致参数化数据冲突、并发修改同一数据检查测试数据是否唯一确认业务逻辑是否幂等5.1 内存泄漏的经典排查过程内存泄漏是稳定性压测中最典型的长期问题。简单描述一下排查套路压测开始阶段TPS正常跑了2小时后TPS开始缓慢下降响应时间逐渐增加。用top查看进程内存发现JVM内存占用持续增长GC日志显示Full GC频率越来越高。下一步用jmap -dump:formatb,fileheap.hprof pid导出堆内存快照然后用 MATMemory Analyzer Tool分析重点看哪些对象占用了最多内存是否有对象实例数量异常庞大是否有对象无法被垃圾回收器回收找到疑似问题对象后回到代码里定位创建该对象的逻辑通常就会发现某个静态集合类只加不删、或者连接没有关闭导致的对象引用链无法释放。修复后再压测一轮确认内存曲线变成平稳状态问题才算真正解决。5.2 数据库连接池被耗尽这个问题的典型表现是压测初期一切正常并发升高后突然大量报错错误信息类似Connection pool exhausted或者Cannot get a connection, pool exhausted。排查思路是确认当前连接池的最大连接数配置HikariCP默认是10Druid默认是8这个数量在高并发下非常容易被打满查看每个请求获取连接的持续时间如果每次请求持连接时间过长说明SQL执行太慢或者事务范围过大检查数据库侧的最大连接数限制MySQL的max_connections默认为151如果应用实例开得很多连接数很容易超限排查连接泄漏是否有代码获取连接后没有finally释放或者异常路径漏了关闭连接调整方向通常是先优化SQL减少每条请求持锁/持连接的时间再评估是否要增大连接池和数据库最大连接数同时给连接设置合理的空闲回收和最大生命周期。5.3 压测机上发现资源不足前面说过压测机本身可能成为瓶颈。这里再补充一个典型场景压测过程中发现JMeter的TPS出现周期性下跌而且错误率升高但在服务端完全看不到任何异常。用top看了下压测机发现CPU使用率100%而且是JMeter进程占满。再往下看JMeter是纯Java应用内存开得太小导致频繁GCGC停顿期间发压能力骤降。解决办法给JMeter加大堆内存修改jmeter.bat或jmeter.sh里的HEAP-Xms2g -Xmx2g具体大小根据压测机配置来减少不必要的内容关掉View Results Tree这类监听器因为保存全部响应结果会非常消耗内存改用非GUI模式运行jmeter -n -t test.jmx -l result.jtl -e -o report_dirGUI模式本身也会消耗不少资源正式压测一定要用命令行模式这条经验几乎每次给团队培训都会讲正式压测必须用命令行模式GUI只适合调试脚本阶段。命令行模式跑出来的结果更稳定也更容易集成到CI/CD流水线里。5.4 定位性能瓶颈的完整方法如果压测结果不达标但上面的速查表没有完全命中可以走一套完整的定位流程。我的核心思路是分层排查逐层剥离压测工具层先确认压测机资源充足脚本没有明显不合理的地方网络层检查压测机到服务端的网络延迟、带宽、丢包率。方法很简单压测期间在压测机和服务端分别执行ping、sar -n DEV 1看流量接入层检查负载均衡、网关的转发能力和配置。Nginx的worker_processes、worker_connections是否足够是否开启keepalive应用层看应用实例的CPU、内存、线程Dump、GC日志用APM工具如Arthas、SkyWalking分析热点方法数据层看数据库的慢查询、连接数、锁等待情况检查缓存命中率每排查完一层没有发现问题就往下继续。正常来说80%的瓶颈要么在数据库要么在应用层的线程池/连接池配置上这两处优先排查。6. 压测报告怎么写才有说服力压测数据出来了问题也定位了最后还要落到一份报告上。很多人不重视报告觉得数据摆上去就行了。实际工作中报告写得好不好直接影响领导/客户/开发团队对系统质量的判断。一份完整的压测报告至少要包含以下内容测试概述测试时间、测试环境机器配置、网络环境、操作系统、测试工具、被测系统版本测试场景压了哪些接口、并发多大、持续时间多长、测试数据怎么构造的关键指标结果TPS、响应时间TP50/TP90/TP99、错误率、资源利用率用表格对比目标值问题清单压测过程中发现了哪些问题、严重程度、影响范围性能结论系统是否达到预期目标当前承载能力是多少瓶颈在哪里优化建议针对每个问题给出可落地的优化方向按优先级排序写报告有一个原则我始终强调数据波动要解释原因。比如TPS在压测中期有一个明显的下跌报告里不能只写TPS下跌30%要说明是因为数据库出现了慢查询还是因为GC频率升高。没有原因解释的数据对决策者来说只是一串数字对开发排查问题也帮助有限。报告里还有一个细节要区分测试环境压测结果和线上环境压测结果。同一个系统测试环境和线上环境的机器配置、网络环境、数据量完全不一样压测数据不能直接画等号。如果是在测试环境做的压测报告要注明并给出换算到生产环境的估算逻辑。7. 给新人的几条实在建议如果看完这篇内容你正准备开始接触压力测试我再多啰嗦几句实操层面的经验第一先学会看懂系统资源监控。很多测试新人一上来就学JMeter工具用得很溜但问起服务端CPU、内存、磁盘I/O都说不清楚。压测的核心是分析不是发请求。建议先在Linux上把top、free、iostat、sar、vmstat这些基础命令用熟这是做性能分析的基本功。第二自己搭一套简单的压测环境练手。在自己电脑上装一个Spring Boot应用写两个接口一个查询数据库一个做计算密集任务然后用JMeter分别压测观察不同负载下TPS和CPU的表现。这个过程不需要真实业务但能帮你把压测的完整流程跑通。第三学会看GC日志和线程Dump。这是Java应用性能排查的核心工具也是面试中经常被考察的加分项。不会分析GC日志遇到内存问题时就会抓瞎不会看线程Dump遇到死锁、线程池打满就只能靠猜。第四多多关注真实的压测案例和开源压测工具文档。现在网上有很多免费的开源课程和社区文章比纯看理论书有效得多。像JMeter官方文档里的示例、GitHub上的k6案例、各类技术社区的性能优化实战文章都是很值得反复研究的内容。另外像全国大学生软件测试大赛这类专业赛事也值得关注里面的题目往往会超出日常工作的视野对提升测试设计思维帮助很大。压测这条路上踩过的坑很多但每一项经验沉淀下来都会变成你自己的判断力。对一个系统性能的判断从我觉得应该没问题变成我压过了数据证明没问题这中间的差别正是压力测试这个岗位不可替代的价值所在。
返回列表