01 | 如何制定性能调优标准?

我有一个朋友,有一次他跟我说,他们公司的系统从来没有经过性能调优,功能测试完成后

就上线了,线上也没有出现过什么性能问题呀,那为什么很多系统都要去做性能调优呢?
当时我就回答了他一句,如果你们公司做的是 12306 网站,不做系统性能优化就上线,试
试看会是什么情况。
如果是你,你会怎么回答呢?今天,我们就从这个话题聊起,希望能跟你一起弄明白这几个
问题:我们为什么要做性能调优?什么时候开始做?做性能调优是不是有标准可参考?
为什么要做性能调优?一款线上产品如果没有经过性能测试,那它就好比是一颗定时炸弹,你不知道它什么时候会
出现问题,你也不清楚它能承受的极限在哪儿。
有些性能问题是时间累积慢慢产生的,到了一定时间自然就爆炸了;而更多的性能问题是由
访问量的波动导致的,例如,活动或者公司产品用户量上升;当然也有可能是一款产品上线
后就半死不活,一直没有大访问量,所以还没有引发这颗定时炸弹。
现在假设你的系统要做一次活动,产品经理或者老板告诉你预计有几十万的用户访问量,询
问系统能否承受得住这次活动的压力。如果你不清楚自己系统的性能情况,也只能战战兢兢
地回答老板,有可能大概没问题吧。
所以,要不要做性能调优,这个问题其实很好回答。所有的系统在开发完之后,多多少少都
会有性能问题,我们首先要做的就是想办法把问题暴露出来,例如进行压力测试、模拟可能
的操作场景等等,再通过性能调优去解决这些问题。
比如,当你在用某一款 App 查询某一条信息时,需要等待十几秒钟;在抢购活动中,无法
进入活动页面等等。你看,系统响应就是体现系统性能最直接的一个参考因素。
那如果系统在线上没有出现响应问题,我们是不是就不用去做性能优化了呢?再给你讲一个
故事吧。
曾经我的前前东家系统研发部门来了一位大神,为什么叫他大神,因为在他来公司的一年时
间里,他只做了一件事情,就是把服务器的数量缩减到了原来的一半,系统的性能指标,反
而还提升了。
好的系统性能调优不仅仅可以提高系统的性能,还能为公司节省资源。这也是我们做性能调
优的最直接的目的。
什么时候开始介入调优?
解决了为什么要做性能优化的问题,那么新的问题就来了:如果需要对系统做一次全面的性
能监测和优化,我们从什么时候开始介入性能调优呢?是不是越早介入越好?
其实,在项目开发的初期,我们没有必要过于在意性能优化,这样反而会让我们疲于性能优
化,不仅不会给系统性能带来提升,还会影响到开发进度,甚至获得相反的效果,给系统带
来新的问题。我们只需要在代码层面保证有效的编码,比如,减少磁盘 I/O 操作、降低竞争锁的使用以
及使用高效的算法等等。遇到比较复杂的业务,我们可以充分利用设计模式来优化业务代
码。例如,设计商品价格的时候,往往会有很多折扣活动、红包活动,我们可以用装饰模式
去设计这个业务。
在系统编码完成之后,我们就可以对系统进行性能测试了。这时候,产品经理一般会提供线
上预期数据,我们在提供的参考平台上进行压测,通过性能分析、统计工具来统计各项性能
指标,看是否在预期范围之内。
在项目成功上线后,我们还需要根据线上的实际情况,依照日志监控以及性能统计日志,来
观测系统性能问题,一旦发现问题,就要对日志进行分析并及时修复问题。
有哪些参考因素可以体现系统的性能?
上面我们讲到了在项目研发的各个阶段性能调优是如何介入的,其中多次讲到了性能指标,
那么性能指标到底有哪些呢?
在我们了解性能指标之前,我们先来了解下哪些计算机资源会成为系统的性能瓶颈。
CPU:有的应用需要大量计算,他们会长时间、不间断地占用 CPU 资源,导致其他资源无
法争夺到 CPU 而响应缓慢,从而带来系统性能问题。例如,代码递归导致的无限循环,正
则表达式引起的回溯,JVM 频繁的 FULL GC,以及多线程编程造成的大量上下文切换等,
这些都有可能导致 CPU 资源繁忙。
内存:Java 程序一般通过 JVM 对内存进行分配管理,主要是用 JVM 中的堆内存来存储
Java 创建的对象。系统堆内存的读写速度非常快,所以基本不存在读写性能瓶颈。但是由
于内存成本要比磁盘高,相比磁盘,内存的存储空间又非常有限。所以当内存空间被占满,
对象无法回收时,就会导致内存溢出、内存泄露等问题。
磁盘 I/O:磁盘相比内存来说,存储空间要大很多,但磁盘 I/O 读写的速度要比内存慢,
虽然目前引入的 SSD 固态硬盘已经有所优化,但仍然无法与内存的读写速度相提并论。
网络:网络对于系统性能来说,也起着至关重要的作用。如果你购买过云服务,一定经历
过,选择网络带宽大小这一环节。带宽过低的话,对于传输数据比较大,或者是并发量比较
大的系统,网络就很容易成为性能瓶颈。异常:Java 应用中,抛出异常需要构建异常栈,对异常进行捕获和处理,这个过程非常消
耗系统性能。如果在高并发的情况下引发异常,持续地进行异常处理,那么系统的性能就会
明显地受到影响。
数据库:大部分系统都会用到数据库,而数据库的操作往往是涉及到磁盘 I/O 的读写。大
量的数据库读写操作,会导致磁盘 I/O 性能瓶颈,进而导致数据库操作的延迟性。对于有
大量数据库读写操作的系统来说,数据库的性能优化是整个系统的核心。
锁竞争:在并发编程中,我们经常会需要多个线程,共享读写操作同一个资源,这个时候为
了保持数据的原子性(即保证这个共享资源在一个线程写的时候,不被另一个线程修改),
我们就会用到锁。锁的使用可能会带来上下文切换,从而给系统带来性能开销。JDK1.6 之
后,Java 为了降低锁竞争带来的上下文切换,对 JVM 内部锁已经做了多次优化,例如,新
增了偏向锁、自旋锁、轻量级锁、锁粗化、锁消除等。而如何合理地使用锁资源,优化锁资
源,就需要你了解更多的操作系统知识、Java 多线程编程基础,积累项目经验,并结合实
际场景去处理相关问题。
了解了上面这些基本内容,我们可以得到下面几个指标,来衡量一般系统的性能。
响应时间
响应时间是衡量系统性能的重要指标之一,响应时间越短,性能越好,一般一个接口的响应
时间是在毫秒级。在系统中,我们可以把响应时间自下而上细分为以下几种:
Version:0.9 StartHTML:0000000105 EndHTML:0000010507 StartFragment:0000000141 EndFragment:0000010467
数据库响应时间:数据库操作所消耗的时间,往往是整个请求链中最耗时的;服务端响应时间:服务端包括 Nginx 分发的请求所消耗的时间以及服务端程序执行所消
耗的时间;
网络响应时间:这是网络传输时,网络硬件需要对传输的请求进行解析等操作所消耗的时
间;
客户端响应时间:对于普通的 Web、App 客户端来说,消耗时间是可以忽略不计的,但
如果你的客户端嵌入了大量的逻辑处理,消耗的时间就有可能变长,从而成为系统的瓶
颈。
吞吐量
在测试中,我们往往会比较注重系统接口的 TPS(每秒事务处理量),因为 TPS 体现了接
口的性能,TPS 越大,性能越好。在系统中,我们也可以把吞吐量自下而上地分为两种:
磁盘吞吐量和网络吞吐量。
我们先来看磁盘吞吐量,磁盘性能有两个关键衡量指标。
一种是 IOPS(Input/Output Per Second),即每秒的输入输出量(或读写次数),这种
是指单位时间内系统能处理的 I/O 请求数量,I/O 请求通常为读或写数据操作请求,关注的
是随机读写性能。适应于随机读写频繁的应用,如小文件存储(图片)、OLTP 数据库、邮
件服务器。
另一种是数据吞吐量,这种是指单位时间内可以成功传输的数据量。对于大量顺序读写频繁
的应用,传输大量连续数据,例如,电视台的视频编辑、视频点播 VOD(Video On
Demand),数据吞吐量则是关键衡量指标。
接下来看网络吞吐量,这个是指网络传输时没有帧丢失的情况下,设备能够接受的最大数据
速率。网络吞吐量不仅仅跟带宽有关系,还跟 CPU 的处理能力、网卡、防火墙、外部接口
以及 I/O 等紧密关联。而吞吐量的大小主要由网卡的处理能力、内部程序算法以及带宽大
小决定。
计算机资源分配使用率
通常由 CPU 占用率、内存使用率、磁盘 I/O、网络 I/O 来表示资源使用率。这几个参数好
比一个木桶,如果其中任何一块木板出现短板,任何一项分配不合理,对整个系统性能的影
响都是毁灭性的。负载承受能力
当系统压力上升时,你可以观察,系统响应时间的上升曲线是否平缓。这项指标能直观地反
馈给你,系统所能承受的负载压力极限。例如,当你对系统进行压测时,系统的响应时间会
随着系统并发数的增加而延长,直到系统无法处理这么多请求,抛出大量错误时,就到了极
限。
总结
通过今天的学习,我们知道性能调优可以使系统稳定,用户体验更佳,甚至在比较大的系统
中,还能帮公司节约资源。
但是在项目的开始阶段,我们没有必要过早地介入性能优化,只需在编码的时候保证其优
秀、高效,以及良好的程序设计。
在完成项目后,我们就可以进行系统测试了,我们可以将以下性能指标,作为性能调优的标
准,响应时间、吞吐量、计算机资源分配使用率、负载承受能力。
回顾我自己的项目经验,有电商系统、支付系统以及游戏充值计费系统,用户级都是千万级
别,且要承受各种大型抢购活动,所以我对系统的性能要求非常苛刻。除了通过观察以上指
标来确定系统性能的好坏,还需要在更新迭代中,充分保障系统的稳定性。
这里,给你延伸一个方法,就是将迭代之前版本的系统性能指标作为参考标准,通过自动化
性能测试,校验迭代发版之后的系统性能是否出现异常,这里就不仅仅是比较吞吐量、响应
时间、负载能力等直接指标了,还需要比较系统资源的 CPU 占用率、内存使用率、磁盘
I/O、网络 I/O 等几项间接指标的变化。

 

性能测试分析是通过**量化指标对比、瓶颈定位、根因分析、验证**的闭环流程,结合工具监控与业务场景,系统性地提升系统性能的过程。其核心目标是**找到性能瓶颈,针对性化,并通过数据验证化效果**。以下是详细分析步骤和关键方法: --- ### **一、性能测试分析的完整流程** #### **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)。 | | **可衡量性** | 前后需通过相同测试场景验证效果。 | | **可持续性** | 确保化后的系统在长期运行中性能稳定。 | ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值