-
Notifications
You must be signed in to change notification settings - Fork 7.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
通过 Arthas Trace 命令将接口性能优化十倍(User Case 投稿) #1892
Comments
cool |
1 similar comment
cool |
很有意义的分享 |
mark |
加个排序可好,看得眼有点花 |
|
java耗时分类里面
|
大佬 截图的那个是什么工具呀 |
基于 Skywalking 二开的调用链系统,前端也重写了一下。 |
莫得现成的嘛,可以直接用的?
…------------------ 原始邮件 ------------------
发件人: "alibaba/arthas" ***@***.***>;
发送时间: 2022年2月18日(星期五) 下午3:08
***@***.***>;
***@***.******@***.***>;
主题: Re: [alibaba/arthas] 通过 Arthas Trace 命令将接口性能优化十倍(User Case 投稿) (#1892)
大佬 截图的那个是什么工具呀 可否加个微信呀,感谢!!! ju_hao_666
基于 Skywalking 二开的调用链系统,前端也重写了一下。
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications on the go with GitHub Mobile for iOS or Android.
You are receiving this because you commented.Message ID: ***@***.***>
|
mark |
ngood |
mark |
Mark |
Mark |
感谢分享 |
excellent ^_^ |
您好!杨永同学已收到您的来信!
|
get下 ,如果能用本地缓存的方式或者分布式缓存 ,程序性能至少提升1.5倍 |
您好!杨永同学已收到您的来信!
|
m |
mark |
您好!杨永同学已收到您的来信!
|
总结里面为啥会说 list.size()会有性能问题呢,不是O(1)的时间复杂度吗 |
您好!杨永同学已收到您的来信!
|
是的,应该这么说,list.size() 一方面开销在于虚拟机进栈出栈的开销,一方面是 arthas 追踪方法耗时的开销。后者的占比会更大。 |
Mark |
1 similar comment
Mark |
mark |
您好!杨永同学已收到您的来信!
|
Mark |
1 similar comment
Mark |
您好!杨永同学已收到您的来信!
|
Best Practices! |
您好!杨永同学已收到您的来信!
|
mark |
背景
Helios 系统要处理的数据量比较大,尤其是查询所有服务一天的评分数据时要返回每日 1440 分钟的所有应用的评分,总计有几十万个数据点,接口有时延迟会达到数秒。本文记录如何利用 Arthas ,将接口从几百几千 ms,优化到几十 ms。
链路:
从链路上看,线上获取一整天的数据时大概 300 多 ms,而查询数据库只有 11ms,说明大部分时间都是程序组装数据时消耗的,于是动起了优化代码的念头。
优化过程
温馨提示:代码可以不用看,没有上下文的情况下很难明白函数什么意思。主要看 Arthas Trace 的结果与优化思路。
初始未优化版本
代码
Arthas Trace
分析
Arthas 显示总共花了 4 秒,但实际上在链路上看大概是 350~450ms 左右。其他多出来的时间是 Arthas 每一次执行统计的消耗,因为方法里的循环比较多。这也告诉我们,不要用 trace 去看循环很多的方法。会对性能有非常严重的影响。
可以看出整个函数有 3 个循环,第一层循环的数量为 appId 的数量约为 140,第二层是查出来的数据条数,一天的数据已经归并了所以这里应该是 1,第三层是时间区间的分钟数,一天的话就是 1440 个。
Trace 中可以看到消耗最多的是封装的一个
SimpleDateFormat.formatDate()
。第一次优化
优化方向
遍历每个时间点的思路改变,把合并过的大对象拆分成一个个小对象直接遍历,改成先合并起来,通过时间点逻辑上遍历。这样会减少创建几十万个对象。
将时间点集合
Set<String> dateSet
改为Set<Date>
,这样减少反复 formatDate() 的开销。优化字符串转数字的过程,减少
Integer.parseInt
方法调用,改为用Map<String, Integer>
提前创建出 0~100 的字符串数字字典。(后来经过 JMH 测试,还是Integer.parseInt
最快)代码
Arthas Trace
分析
这一步实际上执行时间优化了 50ms 左右。
从 Trace 中看耗时时间最长的是 Date 的 compareTo,也就是代码中的
if (splitHeliosScore.getTimeFrom().compareTo(request.getStartTime()) < 0)
而比较意外的是从对象中 get 属性居然也是有开销的。
第二次优化
优化方向
结合上一次 Arthas Trace 的结果,在以下几个方向进行优化:
Date
对象的换成long
型时间戳进行比较Date
对象反复 getTime、setTime,改为long
型时间戳+= 60_000
实现,得到结果后只 setTime 一次。Set<String> dateSet
放入数据,改为通过标识判断只放入一次。代码
Arthas Trace
分析
这一步将执行时间又优化了 80ms 左右。现在还剩是 160ms 了。
从 Trace 中看耗时时间最长的是三个方法:
getScores
。直接 get 了属性啥也没干,但是积少成多list.size()
list.get(index)
也就是说虽然这几个函数里也没干什么东西,但是函数调用、指针寻址本身也是有开销的。
第三次优化
优化方向
也就是说循环中不做任何耗时操作,不做任何指针/引用。
代码
Arthas Trace
分析
这一步又优化了 100ms 左右,现在还剩 60ms。
现在从 trace 上看耗时操作只有三个了:
第四次优化
优化方向
代码
Arthas Trace
分析
可以看到现在最大耗时的地方终于是数据库查询了。现在查询一整天的数据,也只需要 25~40ms 左右。
结果
链路:
链路上看程序代码还是要处理个十几 ms,主要是字符串转 int[] 时的开销,这一步可以再想办法继续优化。
结论
从这次优化我们可以得到一些结论:
SimpleDateFormat
的开销很大Date.compare
的开销不低list.size()
list.add
次数多了开销也很可观另外强烈推荐 动态追踪技术漫谈
The text was updated successfully, but these errors were encountered: