性能压测及分析调优实践 !

【关键导读】

文中结合一次重保活动的性能压测需求,详解了整体的性能测试策略及性能分析思路,并在实施过程中有效利用了NPT性能测试平台完成了压测场景设计、执行、业务指标监控、性能指标分析,结合监控找出了性能瓶颈并给出了相应的性能优化解决方案

0.背景说明

A业务有大促活动,对B业务有依赖,要求B业务对于X场景能够持续稳定支撑1.4w TPS 5min, 如此要对B业务进行性能压测,完成对应的性能需求。

1.性能测试策略

如下所示,接下来按照这个思路去分析下整个性能测试实践的流程。

典型性能测试策略及流程

1.1 性能需求指标

容量指标:X场景支撑1.4W TPS 持续5min

1.2 性能模型建立

【业务模型】

涉及的场景包含A-》B-》C-》D共4个接口,按照真实业务分析流量比例为3:1:1:1
【监控模型】
监控对象
– 测试活动中的所有服务器,测试机、应用服务器、数据库服务器、缓存服务器、依赖服务等资源监控
– 所有被测的应用服务监控,Nginx、tomcat、MySQL等。


监控内容
业务指标:吞吐量、响应时间、失败率
资源监控:CPU、内存、磁盘、网络、IO
日志信息:错误、异常、关键业务日志
进程监控:CPU、内存、进程状态、线程状态
一个典型的linux 性能监控工具图:

1.3 性能方案设计

测试环境:线上真实业务集群

测试数据:场景是从客户端APP发起调用接口,考虑到线上数据样本不涉及隐私及敏感数据且可以复用,不会对用户造成数据污染。故从线上捞取了100万用户数据样本。

压力策略:
1)先摸高,按照一定的线程递增策略,根据预期目标是否有性能瓶颈
2)峰值容量持续压测,观察系统的承受及处理能力

2.性能测试执行及分析

利用NPT性能压测平台完成整个性能压测活动

易测NPT_性能压测_一站式测试解决方案-网易数帆​www.163yun.com/product/npt​编辑

2.1 容量场景:TPS摸高

性能压测模型及场景设计

经过压测在NPT平台中压测后的TPS-RT曲线如下

容量场景:TPS-RT曲线


接下来按照性能分析的典型思路给大家逐一介绍下:

性能分析思路


【瓶颈的精准判断】
很多情况下,在分析系统性能瓶颈的时候,我们总是想找到性能瓶颈的那个“拐点”,但是实际上大部分系统其实是没有明确的拐点的。在实际操作中需要按照固定递增幅度增加并发线程数,进而对于TPS 的增加控制得更为精准,实际业务中TPS的增加是有一个有清晰的弧度,而不是有一个非常清晰的拐点。
从上图业务真实TPS-RT曲线中可以做出以下判断:在线程逐步递增的过程中,TPS按照固定比例上升与线程数呈现线性增长,达到一定的压力的情况下,TPS的增长幅度在衰减,最后逐步趋于平稳。以此可以判断出业务在一定的压力情形下出现了性能瓶颈。为了更加清晰判断性能瓶颈,接下来分析下性能衰减的过程。
【性能衰减的过程】
所谓的性能衰减可以通过每线程每秒请求数在逐渐变少来反应,即使TPS仍在增加,如下针对压测业务采用3个点,计算每线程每秒请求数


采样点1:每线程每秒请求数=9547/270=35.3


采样点2:每线程每秒请求数=13461/450=29.9


采样点3:每线程每秒请求数=13773/495=27.8
由此可以得到如下结论
只要每线程每秒的请求数开始变少,就意味着性能瓶颈已经出现了。但是瓶颈出现之后,并不是说服务器的处理能力(这里我们用 TPS 来描述)会下降,应该说 TPS 仍然会上升,在性能不断衰减的过程中,TPS 就会达到上限。
在这个场景的测试过程中,在性能瓶颈出现后,继续保持递增的压力,让瓶颈更为明显,可以看如下TPS-RT的曲线,我们会更加清晰的看到压力还在逐步增加,但TPS已经趋于平稳,而平均RT却在不断上升


【响应时间的拆分】
基于性能瓶颈的出现,接下来就需要分析在性能瓶颈出现时,哪个链路耗时增加明显导致请求RT变长。那么首先需要做的是画出请求的整个业务链路。这里的策略是:先粗后细,先从较粗的粒度划分,确认耗时较长的链路节点,然后再细分粒度可能到某个方法。我们先来看一个典型的响应时间RT的分布链路


响应时间 = (N1+N2+N3+N4)+(A1+A2+A3),一般我们优先关注的是A1、A2、A3,对于网络传输处理,在这里优先默认它表现良好
基于业务场景的链路:


第三方依赖服务采用了hystrix降级熔断组件实现了独立线程池隔离调用。
1)首先要排除发压端是否有瓶颈,查看发压端服务器监控,CPU利用率和负载都还不到10%

压测机指标


2)分析下调用第三方依赖服务的平均RT,对比如下
单应用实例 20并发 平均rt 19.25
单应用实例 50并发 平均rt 38.25
由此看来在并发用户数一直往上增时,调用第三方依赖服务RT上涨明显,进而初步需要排查的是第三方依赖服务在大并发用户数下的处理能力,并发用户数增加,处理能力下降,导致RT边长
这里优先说下在第一轮性能压测时发现的问题并调整,同样是TPS摸高,从下图可以看出TPS还未达到性能瓶颈时,已经出现失败请求


经过分析调用第三方的线程池被打满抛异常,采用的hystrix实现的业务降级熔断,配置了独立的线程池,线程池配置为核心和最大线程数为20,队列为0

异常日志:
Task java.util.concurrent.FutureTask@66339c68 rejected from java.util.concurrent.ThreadPoolExecutor@303bf923[Running, pool size = 20, active threads = 20, queued tasks = 0, completed tasks = 2071934]
代码实现配置如下,进而优化调整线程池,核心线程数和最大线程数都调整为50



【构建决策分析树】


从压力工具中,只需要知道 TPS、响应时间和错误率三条曲线,就可以明确判断瓶颈是否存在。再通过分段分层策略,结合监控平台、日志平台,或者其他的实时分析平台,知道架构中的哪个环节有问题,然后再根据更细化的架构图一个一个拆解下去。因为这里业务很明显找到了影响RT变长的原因,在此没有进一步分析下去。


2.2 峰值稳定性压测

性能压测模型及场景设计


【性能分析】
针对precheck压测恒定压力1.4W 持续3min后,中间突然TPS陡增初步分析是因为服务器端口耗尽了,看了下TCP连接状态,大量Time_wait,调用第三方依赖服务接口监控中可以看到对应时间点开始抛异常

峰值稳定性场景:TPS-RT曲线

TCP状态监控

错误次数监控

连接异常堆栈信息


看了下服务器的相关配置,对于端口的回收、复用、超时都未进行优化配置


性能优化解决方案:
1)调整应用服务器对于端口的回收、复用、超时进行优化配置
2)将B业务作为客户端调用第三方依赖服务的连接改为长连接,避免短连接每次请求都会占用一个端口

扩展延伸
几种典型的异常波动:
• tps持续下降
• tps频繁波动
• tps陡升陡降
• tps剧烈下降

在此感谢下一位性能测试专家-高楼的一些关于性能测试方向的总结思考,实践过程中有借鉴

【关键总结】

性能测试是针对系统的性能指标,建立性能测试模型,制定性能测试方案,制定监控策略,在场景条件之下执行性能场景,分析判断性能瓶颈并调优,最终得出性能结果来评估系统的性能指标是否满足既定值。

最后感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走! 

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

性能测试分析是通过**量化指标对比、瓶颈定位、根因分析验证**的闭环流程,结合工具监控与业务场景,系统性地提升系统性能的过程。其核心目标是**找到性能瓶颈,针对性化,并通过数据验证化效果**。以下是详细分析步骤和关键方法: --- ### **一、性能测试分析的完整流程** #### **1. 明确试目标与场景** - **目标**:确定方向(如提升吞吐量、降低响应时间、减少资源占用)。 - **场景**:设计覆盖核心业务路径的试用例(如订单提交、支付、查询)。 - **示例**: - 电商系统:模拟高并发下单场景(1000用户并发,持续1小时)。 - 数据库:试复杂SQL查询的响应时间(如多表关联、聚合计算)。 #### **2. 执行基准试** - **作用**:获取化前的性能基线数据(如TPS、响应时间、资源使用率)。 - **工具**: - **工具**:JMeter、Gatling、Locust(模拟用户请求)。 - **监控工具**:Prometheus + Grafana(实时监控JVM、系统资源)。 - **日志工具**:GC日志、线程转储(分析GC和线程阻塞)。 #### **3. 收集性能数据** - **关键指标**: | **指标类型** | **具体指标** | |--------------------|-----------------------------------------------------------------------------| | **业务指标** | TPS、响应时间(P50/P90/P99)、错误率、超时率 | | **资源指标** | CPU使用率、内存占用、磁盘IO、网络带宽 | | **JVM指标** | GC频率、GC停顿时间、堆内存使用率、Metaspace使用率 | | **应用指标** | 线程池活跃线程数、数据库连接池使用率、缓存命中率 | #### **4. 定位性能瓶颈** - **方法**: - **自上而下分析**:从业务指标(如TPS下降)逐步定位到资源或代码问题。 - **自下而上分析**:从资源指标(如CPU 100%)反向推断业务影响。 - **工具辅助**: - **Arthas**:动态跟踪方法耗时、线程阻塞。 - **Async Profiler**:火焰图分析CPU热点。 - **VisualVM**:内存分析、线程转储。 - **常见瓶颈场景**: - **CPU瓶颈**: - 现象:CPU使用率持续>80%,响应时间随并发增加线性上升。 - 工具:`top -H`(Linux)、Async Profiler火焰图。 - 原因:代码热点(如循环计算)、锁竞争、GC频繁。 - **内存瓶颈**: - 现象:频繁Full GC、堆内存使用率>90%、OOM错误。 - 工具:GC日志、MAT(内存转储分析)。 - 原因:内存泄漏、大对象分配、缓存未清理。 - **IO瓶颈**: - 现象:磁盘IO等待高、数据库查询慢、网络延迟大。 - 工具:`iostat`、`iotop`(磁盘)、Wireshark(网络)。 - 原因:磁盘满、SQL未化、网络带宽不足。 #### **5. 根因分析方案** - **根因定位**: - **示例1:CPU瓶颈** - 现象:时CPU 100%,TPS停滞。 - 分析:火焰图显示`String.substring()`方法耗时占比30%。 - 根因:字符串操作频繁且未复用,导致CPU计算浪费。 - **示例2:内存瓶颈** - 现象:Full GC频率从每小时1次增至10次,响应时间波动大。 - 分析:GC日志显示`Promotion Failed`,老年代空间不足。 - 根因:新生代对象晋升失败,因Survivor区过小。 - **方案**: | **瓶颈类型** | **化措施** | |--------------|-----------------------------------------------------------------------------| | **CPU** | 化热点代码(如减少循环、使用更高效算法)、减少锁竞争(如并发数据结构)。 | | **内存** | 整GC参数(如增大新生代)、修复内存泄漏、化对象分配(如对象池)。 | | **IO** | 化SQL(加索引、减少全表扫描)、使用异步IO、增加磁盘带宽(如SSD)。 | | **网络** | 缩响应数据、启用HTTP/2、增加CDN缓存。 | #### **6. 实施并验证** - **步骤**: 1. **小范围试**:在试环境验证效果(避免直接上线风险)。 2. **回归试**:使用相同试场景和负载,对比化前后的量化指标。 3. **监控长期效果**:模拟生产环境持续运行(如24小时),观察性能是否稳定。 - **验证标准**: - **核心指标达标**:如TPS提升20%、P99响应时间<500ms。 - **无副作用**:吞吐量未下降、错误率未上升、资源使用率合理。 #### **7. 迭代化** - **场景**:首次未完全解决问题,需进一步分析。 - **示例**: - 化后TPS从500提升至700,但P99响应时间仍>1s。 - 进一步分析:发现数据库锁等待时间长,需化事务隔离级别。 --- ### **二、关键分析方法与工具** #### **1. 火焰图分析CPU热点** - **工具**:Async Profiler、Perf。 - **作用**:可视化方法用栈,定位耗时占比高的代码路径。 - **示例**: ```bash # 使用Async Profiler生成火焰图 ./profiler.sh -d 30 -f flamegraph.html <PID> ``` - **解读**:火焰图顶部宽度越宽,表示该方法耗时占比越高。 #### **2. GC日志分析内存问题** - **工具**:GCeasy、GCE Viewer。 - **关键指标**: - Full GC频率、单次停顿时间、晋升失败次数。 - 老年代使用率趋势(是否持续增长)。 - **示例**: - 发现`Promotion Failed`日志 → 整Survivor区大小: ```ini -XX:SurvivorRatio=6 # Eden:Survivor=6:1:1 ``` #### **3. 线程转储分析阻塞** - **工具**:jstack、Arthas。 - **作用**:捕获线程状态,定位死锁、锁竞争、等待资源等问题。 - **示例**: ```bash # 使用jstack生成线程转储 jstack <PID> > thread_dump.log ``` - **解读**:搜索`BLOCKED`状态的线程,分析其等待的锁对象。 #### **4. 分布式链路追踪** - **工具**:SkyWalking、Zipkin。 - **作用**:在微服务架构中,跟踪请求跨服务的耗时分布。 - **示例**: - 发现订单服务用支付服务耗时占比40% → 化支付服务接口。 --- ### **三、案例分析:电商系统性能** #### **场景**: - **问题**:时TPS卡在800,P99响应时间>2s,CPU使用率100%。 - **试环境**:4核8G虚拟机,JVM参数:`-Xms4G -Xmx4G -XX:+UseParallelGC`。 #### **分析步骤**: 1. **收集数据**: - 业务指标:TPS=800,P99=2.1s,错误率=0.1%。 - 资源指标:CPU 100%,内存使用率70%,网络带宽未饱和。 - JVM指标:Young GC频率=10次/秒,单次停顿=50ms;Full GC频率=0(未触发)。 2. **定位瓶颈**: - **CPU 100%**:火焰图显示`OrderService.calculateDiscount()`方法耗时占比35%。 - **代码分析**:该方法对每个商品循环计算折扣,且未缓存结果。 3. **根因**: - 算法低效:重复计算相同商品的折扣。 - 锁竞争:`DiscountCache`使用同步锁,高并发下线程阻塞。 4. **方案**: - **代码化**: - 引入本地缓存(Guava Cache)存储商品折扣。 - 使用`ConcurrentHashMap`替代同步锁。 - **JVM**: - 切换到G1 GC(减少Young GC频率): ```ini -XX:+UseG1GC -XX:MaxGCPauseMillis=100 ``` 5. **验证效果**: | **指标** | **化前** | **化后** | **变化** | |------------------|------------|------------|----------------| | TPS | 800 | 1200 | +50% | | P99响应时间 | 2.1s | 0.8s | -61.9% | | CPU使用率 | 100% | 75% | -25% | | Young GC频率 | 10次/秒 | 3次/秒 | -70% | 6. **迭代化**: - 发现数据库查询耗时占比仍较高(P99=500ms)。 - 进一步化:为商品表添加索引,使用批量查询替代单条查询。 --- ### **四、最佳实践** 1. **从小范围开始**:先在试环境验证效果,避免影响生产。 2. **一次只改一个变量**:如同时整JVM参数和代码,难以定位效果来源。 3. **结合业务场景**:不同业务对性能的敏感度不同(如金融系统更关注稳定性)。 4. **自动化监控**:通过Prometheus + Grafana实时展示关键指标,快速发现问题。 5. **记录过程**:保留每次的配置、数据和结论,便于复盘和知识共享。 --- ### **五、总结:性能的核心原则** | **原则** | **具体表现** | |------------------------|-----------------------------------------------------------------------------| | **数据驱动** | 依赖量化指标(如TPS、响应时间)而非主观感受。 | | **分层分析** | 从业务到资源、从整体到局部,逐步定位瓶颈。 | | **根因先** | 先解决根本问题(如内存泄漏),而非症状(如频繁GC)。 | | **可衡量性** | 前后需通过相同试场景验证效果。 | | **可持续性** | 确保化后的系统在长期运行中性能稳定。 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值