前言:本文将简单介绍一下如何实现数据库的性能剖析,以及介绍一下剖析工具的基本使用方法
一,为什么要性能剖析?
你在执行一条SQL语句时,发现服务器响应很慢,执行效率很低。通过EXPLAIN执行语句发现了问题。哦,这是一条慢查询!那么你接下来开始想办法对这条SQL语句进行优化,接下来如何着手?
数据库的优化是在一定的负载下尽可能降低服务器的响应时间
优化的前提条件是测量
优化的难点不在于改,而是以测量的结果作为依据,和需求的数据进行对比。从而发现病灶
确认查询开销是花费在等待上还是执行上
如果一条服务器处理一条请求95%的时间都在等待IO完成,但是执行sql的时间仅占5%,这时候优化sql语句的执行效率就是无意义的。
平均结果无法反映一条sql语句的具体效率
执行慢查询,从服务器整体运行开销来分析问题所在这是不合理的。要对慢查询进行测量而不是只测量服务器整体。
完成一项任务所需的时间可以分为等待时间+执行时间
执行时间受到应用层的影响,比如使用了暴搜或者索引失效
等待时间则会与其他线程之间竞争资源有关
不能执着于单条sql语句的查询
当一个用户进行交互时,其操作往往涉及到多个查询语句,这时候仅关注一条sql的执行效率,就无法把用户交互行为涉及到的查询关联起来,也就是管中窥豹,后续在性能剖析中会介绍如何实现聚合性能分析
二,对应用程序进行剖析
这里介绍一下如何使用Arthas来进行应用层性能剖析
1. 下载Arthas
在 Windows 中打开 PowerShell,进入你想要存放工具的目录(比如 D:\tools),执行以下命令:
PowerShell
curl -O https://arthas.aliyun.com/arthas-boot.jar
- 注意: 如果你的电脑没装 curl,直接通过浏览器访问 Arthas 官网 下载这个
.jar文件即可。
2. 启动,挂载服务器
启动Arthas之前我们需要先启一个服务,这里以我之前写的TCP回显服务器为例
程序启动之后使用arthas检测对应进程,在控制台输入:
java -jar arthas-boot.jar

输入我们想要监测的序号,注意不要输入PID

执行到这一步,再继续对终端进行输入会发现出现输入和粘贴数据缺失的现象发生,这是因为我们在控制台的交互行为会因为网络波动导致输入的字符流丢失。这里我们切换为Web 控制台完成后续流程
打开浏览器,输入 http://127.0.0.1:8563/
进入 Web 控制台后,按顺序执行以下三个核心诊断操作,观察 TCP 代码如何运行:
A. 整体扫描:dashboard
输入 dashboard。
-
目的: 看看你的
newCachedThreadPool是否在疯狂创建线程,或者内存是否有异常。 -
退出: 按
Ctrl + C。
B. 追踪交互链路:trace
这是你之前最想要的。直接粘贴这行命令:
Bash
trace netWork.tcpEchoServer processConnection
-
操作: 回到你的
tcpEchoClient发送一条消息。 -
观察点: 网页上会立刻弹出一棵树。你会看到
processConnection内部如何分步执行:从获取流到调用process,每一步的耗时(微秒级)清晰可见。
在TCP客户端上输入一条信息,观察控制台响应结果

C. 多次输入
在客户端控制台多次输入,观察结果:

D. 制造延迟
由于 process 方法太快了(7 微秒),快到让性能分析失去了挑战性。你想试试**"定位生产环境瓶颈"**的模拟吗?
-
修改服务器代码 :在
process方法里随机制造一点延迟。Java
public String process(String request) { if ("slow".equals(request)) { try { Thread.sleep(200); } catch (InterruptedException e) {} } return request; }
热更新代码(不重启服务器)
如果你刚才是在 IDE 里改了代码并重新编译成了 .class 文件,你可以利用 Arthas 的 retransform 命令让新逻辑直接在运行中的服务器生效:
-
加载新类:
Bash
retransform "C:\你的路径\netWork\tcpEchoServer.class" -
验证 :看到
retransform success后,你的服务器逻辑就已经原地升级了。

利用 tt 发起"时光倒流"测试
tt 的核心理念是:"记录一次,无限重放"。你不需要反复去客户端敲字,只要抓到一次"样本",就可以在服务端无限次模拟这次请求,验证你的代码逻辑和性能。
共划分为 4 步标准操作:
第一步:开启记录仪(布下陷阱)
首先,告诉 Arthas 你要监控 process 方法。
Bash
tt -t netWork.tcpEchoServer process
- 状态 :此时控制台会显示
Press Q or Ctrl+C to abort.,说明它正在后台静静等待请求到来。
第二步:制造"样本"请求(关键!)
因为 tt 只能重放 已经发生过的请求,所以你需要先去客户端发送一次符合你测试目标的请求。
-
操作 :去
tcpEchoClient的黑窗口,输入slow并回车。 -
目的 :因为你的新代码逻辑是
if ("slow".equals(request))才会触发延迟。如果你只发送hello,重放一万次也测不出那 200ms 的延迟。 -
Arthas 的反应 :你会看到控制台立刻弹出一行记录,记下那个 INDEX (比如
1002)。

第三步:发起重放测试(时光倒流)
现在你可以把客户端关了,甚至拔掉网线,我们直接在服务端"重放"刚才那条请求。
刚才记录到的索引是 1001,输入:
Bash
tt -i 1001 -p
-
-i 1001:指定要重放的那条记录的索引。 -
-p:Play(重放)。这是最神奇的一步,Arthas 会主动调用一次process("slow")。
第四步:验收结果(看真相)
执行完命令后,你会看到类似下面的输出,请重点看这两个指标:
-
COST (耗时):
-
预期 :应该在 200ms 左右。
-
分析 :如果之前的请求是 0.0x ms,而这次重放变成了 200ms,恭喜你!热更新成功了,代码逻辑已生效。
-
-
result (返回值):
- 预期 :显示
@String[slow]。

- 预期 :显示
⚔️ 进阶:压力测试(疯狂重放)
如果你想看看这 200ms 的延迟会不会把你的线程池拖垮,可以让 Arthas 疯狂重放这个请求:
Bash
# 每隔 100ms 重放一次,总共重放 50 次,也就是持续 5 秒的压力测试
tt -i 1001 -p --replay-times 50 --replay-interval 100

对比先后的时间开销,得出process方法是影响性能的主要罪魁祸首
修改process代码逻辑即可修正。
以上只是对于服务器的串行测试,如果想要正在给服务器施压,可以使用jmeter压测工具