资讯详情

资讯详情

压力测试实战指南:加压方法、瓶颈定位与避坑要点

干软件测试这些年被问得最多的问题之一就是“这系统上线以后能扛多少人同时用”每次听到这种问题我就知道压力测试又该上场了。说实话压力测试是软件测试里最能让系统“现出原形”的一种方式它会通过不断加压把系统的极限、瓶颈、隐患全部逼出来。这篇文章我想完整聊聊压力测试这件事它到底在压什么、怎么做才靠谱、压出来的数据怎么解读以及我这个老测试踩过的那些坑。内容主要面向刚入行想系统了解压力测试的测试工程师也适合正在准备软件测试面试、或者项目上线前手忙脚乱的同路人。1. 压力测试到底在测什么为什么上线前必须做1.1 压力测试的定义以及它和负载测试的区别压力测试英文叫 Stress Testing核心思路其实很简单在系统超过预期负载的情况下持续给它施加压力看它什么时候扛不住、怎么扛不住、扛不住之后能不能恢复。很多人容易把压力测试和负载测试混在一起说这可以理解因为两者确实经常在同一轮测试里完成。我自己习惯这样区分负载测试讲究“慢慢加看到达预期指标时系统表现怎么样”压力测试讲究“继续加加到你认为系统该崩溃了为止”。前者回答“系统够不够用”后者回答“系统极限在哪、崩溃后是什么状态、恢复能力怎么样”。对比维度负载测试压力测试目标验证预期负载下性能是否达标找到系统极限、崩溃点和恢复能力加压方式逐步增加至预期负载持续加压超出预期负载并逼近上限关注点响应时间、TPS、稳定性系统何时出错、是否雪崩、能否自愈典型产出性能基线与调优依据容量上限、弹性边界、风险预警我不太建议大家把时间花在抠名词区别上因为实际项目里很多团队会把两件事混在一起做。重要的是你自己心里清楚这次压测你要的是“验证够用”还是“摸清上限”。这两种目标下场景设计和判断标准完全不同。1.2 为什么压力测试是上线前最关键的一环我强调一下压力测试绝不只是“看看系统顶不顶得住”这么简单它最核心的价值有三块。第一暴露低负载下根本发现不了的问题。比如内存泄漏正常用可能一个礼拜都发现不了但压测持续跑几个小时内存曲线会一路往上走。再比如连接池耗尽、线程死锁、数据库慢查询拖垮整体这些问题的触发条件都是“并发量足够大”。没有压力测试这些问题大概率会在用户量冲上来之后才暴露到那时候就是线上事故处理成本完全不一样。第二给容量规划提供数据依据。运维问你“要不要加机器、加几台”的时候靠的不是拍脑袋而是压测结果。我之前做过一个电商项目压测后发现当前集群最多支撑每秒300个订单而大促预估峰值是每秒800那就要提前扩容。具体扩到几台按压测数据推至少留出三倍余量。没有数据就只能拼运气。第三验证系统在异常情况下的恢复能力。压到系统快要崩溃时停止加压观察它能不能自己恢复。熔断、限流、降级这些机制有没有真正生效用压力测试一压就看得清清楚楚。所以我常说压力测试不只是测“上限”它更像是给系统做一次全身体检。再补充一点很多人问“小程序上线前需要做压力测试吗”我的回答是需要。小程序前端本身对服务器压力不大真正被压的是后端接口。只要小程序有业务接口、有数据库读写、有用户增长的可能上线前的压力测试就不能省。当然除了压力测试上线前还应该做功能回归、冒烟测试、兼容性测试、安全测试这些它们和压力测试是互补关系不是替代关系。2. 压力测试完整流程从需求到报告2.1 测试目标与业务模型确认第一步不是打开JMeter而是先坐下来搞清楚三个问题测什么系统、覆盖什么业务场景、达到什么标准算合格。系统层面的目标比较好理解是新上线做容量摸底还是老系统升级后做回归对比还是线上出了事故做排查验证。目标不同后续的报告结论和关注指标完全不一样。比如容量摸底关心的是上限回归对比关心的是“这次改动有没有把性能改差”。业务模型是很多人容易忽略的点。一个系统可能有几十个接口但压力测试不可能每个接口都压也没必要。正确做法是挑出核心链路。拿一个典型的电商下单场景举例核心链路大概是用户登录、商品查询、加入购物车、提交订单、支付回调。压测脚本里这几个接口就按真实业务比例混合施压而不是只压最慢的那一个。这样压出来的数据才接近真实。另外要提前和业务方、产品经理对齐预期值。比如“大促峰值并发大概多少”“平时高峰在线人数多少”这些业务数据是场景设计的输入。没有业务预期压测很容易变成“随便压一压看个曲线”跑完之后谁都不知道结果算好算坏。2.2 脚本编写、参数化与断言脚本编写这块我用JMeter举例它是目前最通用的工具但思路对Gatling、Locust同样适用。脚本来源有两种一是录制真实操作生成脚本适合快速出包二是手工编写HTTP请求脚本更可控、更准确。我个人更推荐手工编写尤其是核心链路因为录制会把大量静态资源请求一起录进去干扰结果判断。参数化是脚本编写中最重要的一步。举个例子如果所有虚拟用户同时用同一个账号访问登录接口那服务器其实只对同一个用户做了登录大量并发会落在内存里同一个会话上结果完全失真。更极端的例子是查询类接口如果所有请求都查同一个商品ID数据库缓存命中率会异常偏高压测结果会给出一个“看起来很美”的数字。所以参数化要做的是让每个虚拟用户使用不同的账号、不同的商品ID、不同的订单编号去请求。断言同样不能省。我会在每个请求后面加一个响应断言判断HTTP状态码是200同时再校验响应体里包含某个关键字段。否则当系统已经返回错误页或者空数据时压测工具统计里可能仍然把它当成成功最后的错误率数据就废了。还有一个争议点要不要在脚本里加“思考时间”。思考时间就是模拟真实用户“看完这页再点下个按钮”的停顿。我的态度是如果压测目的是验证系统容量可以不加让请求以最快速度轰击系统压出上限如果是想尽量模拟真实场景就要加否则压出来的访问频率会远高于真实用户。两种做法没有绝对对错关键是报告里写明你加还是没加看报告的人才能正确理解结果。2.3 场景策略怎么加压才靠谱压测最常见的错误是一上来就按目标并发直接压。这种做法有几个问题一是系统存在瓶颈时瞬间大并发可能导致线程池直接打满系统假死二是数据不好看你不知道瓶颈出现在哪个阶段。正确做法是梯度加压。我常用的策略是先在脚本里把并发数设成10跑3分钟看基线然后提到30跑3分钟再提到50、100、200每一档都观察TPS、响应时间和错误率的变化。这样你能看到一个清晰的拐点——比如并发到150的时候TPS不再上涨但响应时间还在涨那大概率就是系统瓶颈所在。持续时长也是一个关键决策。做稳定性相关的压力测试时我会让系统在目标并发下跑至少30分钟到1小时用来观察内存泄漏、连接池回收这类慢性问题。短时间压测往往只能验证“瞬时抗压能力”验证不了“持续运行能力”而这两种能力生产环境都缺一不可。3. 线程组怎么选JMeter核心配置实操3.1 三类常用线程组对比关于“压力测试选择什么线程组”这是新手最容易懵的地方。JMeter自带的Thread Group是基础线程组但真实项目里我很少只用它更多是用下面几种组合。线程组类型工作原理适用场景Thread Group基础线程组固定线程数、固定循环次数单场景快速压测、简单验证Stepping Thread Group按预设步长逐步增加线程数梯度加压、定位系统拐点Ultimate Thread Group线程数、启动时间、运行时长、释放时间均可配置复杂场景建模模拟波浪式真实流量我用得最多的是Ultimate Thread Group原因是它足够灵活能把一个完整的场景时间轴配置出来前5分钟从0爬到50并发中间10分钟稳定在50并发最后5分钟再爬到100并发然后慢慢释放。这种波浪式的压力模型很接近真实互联网流量的形状。如果你的测试目标是模拟一场“先升温、再持续、再升温”的大促流量它是我第一个推荐的线程组。Stepping Thread Group适合快速找拐点它更偏“线性爬坡”配置也简单适合用来出报告里的“拐点图”。而基础Thread Group适合一些小项目快速验证比如一个内部管理系统的接口预估在线人数就几十个人直接用Thread Group设个固定并发跑一轮简单直接。3.2 关键参数详解线程数、Ramp-Up、Duration配置线程组时三个参数最容易出错线程数、Ramp-Up Period、Loop Count。线程数代表虚拟用户数注意它不等于请求数。一个线程在循环里可以发出几十个请求所以“100个线程”可能意味着每秒几百次请求。线程数的设置依据是业务预估并发量不要拍脑袋写个5000没有业务场景支撑的数字没有实际意义。Ramp-Up Period是线程的启动时间。假设线程数100、Ramp-Up设成10秒意思是每秒启动10个线程。这个参数的作用是让压力不是一瞬间全部砸上去。如果设成0测试一开始就把100个线程全部创建并发出请求这对系统是一个非常不友好的冲击也很容易让压测结果从第一秒起就失真。我一般建议普通场景下Ramp-Up时间不要少于线程数除以10到20的值也就是说100个线程至少用5到10秒去慢慢爬。除非你刻意想测系统瞬时崩溃点那可以特殊处理。Loop Count是循环次数。压测时我通常设成无限循环再用Duration来控制测试长度。原因是固定循环次数时不同请求的响应时间不同会导致所有请求结束的时间点不一致很难精确控制压测时长。用Duration控制能保证每一档压力都跑够预定时间不同档位的结果对比起来才公平。3.3 分布式压测与资源清理当单台JMeter机器的CPU打到80%以上时它自己就成了测试瓶颈。这时候压出来的数据不是系统的真实能力而是压测机器的上限。解决办法是做分布式压测一台主控机负责调度多台施压机同时发起请求主控机汇总结果。分布式压测有两个很实际的坑。第一施压机和被压系统之间的网络要单独考虑。如果施压机在办公网被压系统在云上那压出来的瓶颈很可能就变成了办公网带宽而不是系统本身。第二主控机尽量不要参与实际施压它只负责下发脚本和收集结果否则主控机的状态会影响整个压测链路结果波动会很大。压测结束后还有一件容易被忽略的事清理测试数据。压测会在数据库里插入大量订单、用户记录上线前不清理就会造成数据污染。我见过有人压测完忘了删测试账号结果上线后发现生产环境多了一堆“test用户”。这个动作虽然简单但真没几个人每次都记得。4. 压测结果怎么分析指标解读与瓶颈定位4.1 核心指标速查压测报告里的英文缩写很多真正核心的指标其实就那么几个。指标含义什么情况算有问题TPS / QPS每秒完成的事务数 / 请求数随并发增长不再上升可能到了瓶颈响应时间Avg / P90 / P99平均响应时间、90%和99%请求的响应时间P99远高于Avg说明存在长尾慢请求错误率失败请求占总请求的比例超过0.1%-1%就要警惕具体看业务容忍度CPU / 内存 / 磁盘 / 网络系统资源利用率CPU持续90%以上或内存持续攀升不回落这里我想重点说说P99。很多人只看平均响应时间这不够。平均响应时间500ms看起来挺好但实际可能是100个请求里99个都是200ms只有1个是30秒平均值被拉起来了。而P99能告诉你最慢的那1%请求到底慢到什么程度。线上用户体验里最慢的那1%往往才是用户投诉的起点。所以我看报告时习惯先看P99再回头看平均。4.2 一次真实瓶颈定位实录拿我之前压测一个订单系统来举例。脚本就绪后我按梯度把并发从10提到50TPS一直在涨表现正常。再提到100问题来了TPS不再上涨响应时间却明显涨错误率也开始出现零星超时。遇到这种情况第一步不是看数据库而是先看应用服务器的CPU和内存。如果CPU已经到95%以上说明瓶颈在应用层可能是业务代码复杂或者GC太频繁。我当时看到应用服务器CPU只有40%内存也正常于是把视线转向数据库。数据库CPU也不高但连接数指标很异常——已经打到了配置上限。查配置后发现这个服务的数据库连接池最大值被设成了10。并发一上来10个连接全部被占满新请求只能排队等连接释放响应时间自然越来越长。把连接池最大值调到50后TPS直接翻了一倍。这个案例很小但它说明了一个方法论定位瓶颈时要按“应用层→数据库→中间件→网络”这条链路逐层排查别一上来就怀疑数据库。先把资源利用率整体扫一遍再往深处走。大部分情况下瓶颈都藏在配置项里比如连接池、线程池、超时时间而不是藏在那些多复杂的代码逻辑里。5. 常见问题与避坑速查5.1 为什么你的压测结果不可信经常有人问“我压出来TPS有5000怎么上线之后连2000都扛不住”这种问题九成出在压测方案本身而不是系统问题。我整理了最常见的几个结果失真原因大家可以对照自查。常见问题原因解决方案压测机本身成瓶颈单机JMeter线程数开太大CPU耗尽使用分布式压测多台施压机分摊网络带宽打满压测机与被压系统跨网络保证压测在同一内网或同一区域云环境数据未参数化所有请求命中同一缓存使用不同账号、ID等参数化数据断言配置错误把错误响应当成成功检查断言逻辑增加响应体校验脚本包含静态资源录制脚本把CSS/JS等请求录进去手工编写脚本过滤非核心请求没有加思考时间请求频率远高于真实用户根据场景决定是否添加并在报告注明其中“数据未参数化”和“断言配置错误”这两个问题造成的失真最多也是新手最容易踩的。压测结果一旦失真整个报告就没有参考价值所以每次压测开始前花几分钟检查参数化和断言是值得的。5.2 实操中踩过的三个坑第一个坑是JMeter自身的JVM内存不够。默认配置下JMeter的堆内存很小压测到一半就会报OutOfMemoryError整个测试直接中断。我踩过一次之后养成了习惯压测开始前先改jmeter.sh或jmeter.bat里的JVM参数把堆内存调到2G到4G给压测场景留足空间。第二个坑是压测到一半才发现断言写错。有一回我压一个支付回调接口响应码是200但响应体里其实是个错误信息我的断言只写了“HTTP 200”结果整轮压测的错误率统计是0报告完全没法用。从那以后我写断言都会加上响应体关键字段的判断比如“code0”或“successtrue”。第三个坑是压测完忘了检查系统连接状态。长时间压测后系统里会残留大量TIME_WAIT状态连接影响后续测试。在Linux上压测前我会先确认被压服务端口和连接限制配置压测结束后再看一眼连接状态。如果你不想折腾内核参数至少压测前确认服务端的连接数限制比测试并发数大不少。6. 零基础学习和面试高频题6.1 零基础学习压力测试的建议路径经常有人问“软件测试零基础压力测试怎么学”。说实话压力测试的门槛不在工具上而在基础知识是否扎实。我的建议路径是四步走。第一步先把HTTP协议基础搞明白。压力测试压来压去压的就是HTTP请求你至少要知道GET和POST的区别、请求头请求体大概是什么意思、常见状态码代表什么。不一定背得多深但看到502、504、429的时候要能反应过来是网络问题、超时问题还是被限流了。第二步掌握一个工具首选JMeter。它开源、资料多、社区活跃遇到问题基本搜得到答案。初学阶段不用把每个组件都学会先把线程组、HTTP请求、参数化、断言、监听器这几个核心组件吃透就够了。工具是“术”多试几次就能上手不必在这一步纠结太久。第三步学会看系统资源。在实际项目里压力测试往往和Linux性能监控配套出现。至少要会看CPU、内存、磁盘I/O和网络流量会使用top、vmstat、free、iostat这些命令。这一步决定了你能不能从“会跑压测”升级到“会定位问题”也是区分熟练工和新手的关键。第四步找开源项目练手。GitHub上找个简单的个人博客或商城项目本地跑起来按前面说的流程完整做一遍定场景、写脚本、梯度加压、分析报告。练完这一轮你对压力测试的理解会超过大部分面试候选人。嵌入式软件测试也可以用类似思路只是环境更受限、工具链不同但“通过加压找出系统边界”的思想是完全一致的。6.2 面试官常问的压力测试问题怎么答最近很多朋友在准备软件测试面试随手一搜就是“软件测试面试题”或“软件测试面试八股文”。我把面试里最可能问到的压力测试相关问题整理一下直接给答题框架。第一个是“压力测试和负载测试的区别”。这个问题几乎必问。答题框架就是用前面说的负载测的是预期负载下的表现压力测的是超过预期后系统的极限和恢复能力。答的时候如果能举一个自己做过的例子说明效果会好很多。第二个是“一个接口的并发用户数怎么确定”。别扯复杂公式直接说思路用业务预估的日活和峰值在线人数做初始估算再结合历史流量数据校准最后用梯度加压实测确认。面试官想听的是“你有业务视角”而不是只会套公式。第三个是“压测报告怎么看怎么定位瓶颈”。答案分两层先看整体指标TPS、错误率、响应时间再按“应用→数据库→中间件→网络”逐层排查。能把连接池打满那个例子讲出来绝对是加分项。第四个是“小程序上线前除了压力测试还要做什么”。除了压力测试还需要功能测试、兼容性测试不同机型屏幕适配、网络异常测试弱网、断网场景、安全测试接口防刷。这个问题考的是知识面广度每类测试用一两句话说清就行。还有一个隐藏考点是“你为什么选这个线程组”。面试官有时会顺着你用的工具深入问这时候把自己实际用过Stepping Thread Group或Ultimate Thread Group的理由讲清楚比背概念有用得多。最后说点我个人体会。我刚开始做压力测试的时候总喜欢把并发数往死里调大觉得压得越猛越有成就感。后来才慢慢想明白压测的本质不是为了把系统压垮而是为了知道系统的边界在哪以及越过边界之后会发生什么。成熟的团队每次上线前都会认真跑一遍压测把结果存档下一次压测和这次对比看性能是变好了还是变差了。如果你准备在自己的项目里开始第一次压力测试我的建议是先不要追求复杂挑出一个核心接口按前面说的梯度加压跑一轮把报告存下来。有了第一份基线报告之后的每一次压测都会变得更有参考价值。踩坑很正常关键是每次踩完坑都把它记录下来——这个习惯能让你的测试经验以肉眼可见的速度增长。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →