2、性能分析工具链:Linux性能工具集(perf、top、vmstat)、Java性能工具(JProfiler、Arthas)、数据库性能工具(慢查询日志、EXPLAIN)
性能调优这件事,说白了就是「先找到瓶颈,再解决它」。但瓶颈在哪?靠猜可不行。我见过太多团队,一上来就改代码、调参数,结果折腾半天,问题压根不在那。
所以,工具链就是你的眼睛。今天我把压箱底的三类工具串起来讲——Linux系统级、Java应用级、数据库级。你想想看,一个请求从网络进来,经过OS、JVM、最后落到数据库,每一层都可能卡住。咱们得一层层剥开。
2.1 Linux系统级工具:perf、top、vmstat
系统级工具,我习惯先看top。为什么?因为它快。一条命令下去,CPU、内存、负载全出来了。但很多人只看一眼就跑了,这不对。
核心用法:
top:按1看每个CPU核心,按P按CPU排序,按M按内存排序。我一般先看%id(空闲CPU),如果低于20%,说明CPU吃紧了。vmstat 1 5:每秒输出一次,共5次。重点关注r(运行队列)和wa(IO等待)。r如果持续大于CPU核数,说明CPU不够用;wa高了,磁盘IO是瓶颈。
有一次线上告警,top看到CPU才30%,但接口响应慢。我下意识觉得是IO问题,vmstat一看,wa飙到40%。嗯,磁盘在拖后腿。后来发现是日志写得太猛,调整了日志级别和异步刷盘,问题解决。
再说perf。这工具我建议每个后端开发都学一下。它能告诉你CPU到底在忙什么——是执行代码,还是在等内存?
常用命令:
perf top:实时显示CPU热点函数。如果看到spin_lock或__schedule频繁出现,说明锁竞争或上下文切换严重。perf record -g -p [PID]:采样并记录调用栈。之后perf report看火焰图。我个人习惯先跑30秒,数据量够用就行。
我曾经排查过一个Java服务CPU飙高的问题。perf top一看,热点全在GC线程里。说白了,就是JVM在疯狂垃圾回收。后来调大了堆内存,并改用G1收集器,CPU直接降了一半。
2.2 Java应用级工具:JProfiler、Arthas
Java应用的性能问题,很多时候是代码层面的。比如死循环、频繁创建对象、锁竞争。这时候系统级工具就看不透了,得用Java专用工具。
JProfiler:图形化工具,适合本地开发和压测环境。我最常用的是「CPU视图」和「内存视图」。
- CPU视图:看哪个方法耗时最长。我习惯先按「自耗时」排序,而不是「总耗时」。因为总耗时可能包含子调用,自耗时才是方法本身的消耗。
- 内存视图:看对象分配。如果发现某个
HashMap或ArrayList不断增长,八成是内存泄漏。
但线上环境,我更推荐Arthas。它是阿里巴巴开源的诊断工具,不用重启应用,直接attach到JVM上。
Arthas常用命令:
dashboard:实时面板,看线程、内存、GC情况。我每次上线后都会跑一下,确认一切正常。thread -n 3:显示最忙的3个线程。如果看到BLOCKED状态的线程,说明有锁竞争。trace [类名] [方法名]:追踪方法调用耗时。比如trace com.example.UserService getUser,就能看到这个方法里每一行代码的执行时间。
我记得有一次,一个接口偶尔超时。用trace一查,发现是RedisTemplate.opsForValue().get()有时会卡住2秒。后来排查是Redis连接池配置太小,高峰期连接被占满。调整了maxTotal和maxWaitMillis,问题消失。
注意:Arthas的trace命令会带来额外性能开销,线上使用建议只trace少量请求,或者配合--skipJDKMethod false过滤JDK内部方法。
2.3 数据库性能工具:慢查询日志、EXPLAIN
数据库往往是性能瓶颈的重灾区。我见过太多慢SQL拖垮整个系统的案例。所以,数据库工具链必须掌握。
慢查询日志:这是MySQL自带的,开启后会自动记录执行时间超过阈值的SQL。
配置方式:
-- 开启慢查询日志
SET GLOBAL slow_query_log = ON;
-- 设置阈值(单位:秒)
SET GLOBAL long_query_time = 1;
-- 查看日志文件路径
SHOW VARIABLES LIKE 'slow_query_log_file';
我建议阈值设成1秒。线上业务如果大部分查询都在10ms以内,超过1秒的SQL就是重点怀疑对象。拿到慢SQL后,下一步就是用EXPLAIN分析执行计划。
EXPLAIN:在SQL前面加上EXPLAIN,MySQL会告诉你它是怎么执行这条SQL的。
关键字段解读:
| 字段 | 含义 | 重点关注 |
|---|---|---|
type |
访问类型 | 从好到差:const > eq_ref > ref > range > index > ALL。看到ALL(全表扫描)就要警惕。 |
rows |
预估扫描行数 | 数值越大,性能越差。如果rows是几百万,但实际只返回几条,说明索引没用好。 |
Extra |
额外信息 | 看到Using filesort或Using temporary,说明排序或分组用了临时表,需要优化。 |
我曾经接手过一个报表系统,每天凌晨跑批要2小时。慢查询日志里抓到一条SQL,EXPLAIN一看,type是ALL,rows显示800万。说白了,就是全表扫描。后来加了个联合索引,跑批时间降到15分钟。
避坑指南:我曾经犯过一个错——只看rows,没看Extra。有一次rows只有1000,但SQL还是慢。后来发现Extra里有Using where; Using index,但Using filesort也在。原来排序字段没在索引里,导致MySQL用了文件排序。加了个覆盖索引,问题解决。
2.4 工具链的串联使用
单个工具只能看到局部。我习惯的排查路径是:
- 先看系统层:
top看CPU和内存,vmstat看IO和上下文切换。如果CPU高,用perf定位热点。 - 再看应用层:如果是Java应用,用Arthas的
thread和trace定位具体代码。 - 最后看数据库:如果怀疑是数据库问题,开慢查询日志,用
EXPLAIN分析。
你想想看,如果一上来就调JVM参数,结果瓶颈在磁盘IO,那不是白忙活吗?所以,工具链要串联起来用,一层层缩小范围。
总结一句话:性能调优不是玄学,是科学。工具链就是你的实验仪器。用好它们,问题无处遁形。