使用Arthas排查性能问题

news2024/12/27 10:45:22

      Arthas 是一款线上监控诊断产品,通过全局视角实时查看应用 load、内存、gc、线程的状态信息,并能在不修改应用代码的情况下,对业务问题进行诊断,包括查看方法调用的出入参、异常,监测方法执行耗时,类加载信息等,大大提升线上问题排查效率

1.问题背景

今天一到公司开发人员就因线上的性能问题寻求帮助,售后反馈系统升级后物理产品更换业务处理十分缓慢,有时卡主10几秒。

我先尝试从开发环境复现问题,发现开发环境处理并不慢。考虑到线上环境存在性能问题而开发环境没有这个问题,一般情况下是两边数据量差引起的。我们的开发环境中的数据比现场环境低几个数量级。可能某些SQL在线上执行比较慢引发了问题。我尝试打印慢SQL,发现日志中没有执行比较慢的SQL以及可疑日志。 这个问题变得十分棘手。

2.问题分析

在毫无头绪时,只能借助一些工具来协助分析。本问题主要用到了Arthas 的trace命令

trace :获取方法内部调用路径,并输出方法路径上的每个节点上耗时

参考: trace | arthas

排查过程

1.运行arthas ,并选择进程20408,20408是系统客户端使用的进程

D:\staibossCliente\arthas-bin>
D:\staibossCliente\arthas-bin>java -jar arthas-boot.jar
[INFO] arthas-boot version: 3.5.4
[INFO] Process 20408 already using port 3658
[INFO] Process 20408 already using port 8563
[INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.
* [1]: 20408 D:\staibossCliente\staribossclient\stariboss-new-client.exe
1
[INFO] arthas home: D:\staibossCliente\arthas-bin
[INFO] The target process already listen port 3658, skip attach.
[INFO] arthas-client connect 127.0.0.1 3658
  ,---.  ,------. ,--------.,--.  ,--.  ,---.   ,---.
 /  O  \ |  .--. ''--.  .--'|  '--'  | /  O  \ '   .-'
|  .-.  ||  '--'.'   |  |   |  .--.  ||  .-.  |`.  `-.
|  | |  ||  |\  \    |  |   |  |  |  ||  | |  |.-'    |
`--' `--'`--' '--'   `--'   `--'  `--'`--' `--'`-----'
 
 
wiki       https://arthas.aliyun.com/doc
tutorials  https://arthas.aliyun.com/doc/arthas-tutorials.html
version    3.5.4
main_class
pid        20408
time       2023-11-20 17:38:39
 

2. 根据业务行为查看方法内部的处理时间

[arthas@20408]$ trace -E com.star.sms.richclient.accept.view.accept.acceptEditor2.ExchangePhysicalProductEditor initOptionalPhysicalProducts
Affect(class count: 1 , method count: 0) cost in 61 ms, listenerId: 10
No class or method is affected, try:
1. Execute `sm CLASS_NAME METHOD_NAME` to make sure the method you are tracing actually exists (it might be in your parent class).
2. Execute `options unsafe true`, if you want to enhance the classes under the `java.*` package.
3. Execute `reset CLASS_NAME` and try again, your method body might be too large.
4. Check arthas log: C:\Users\95225/logs/arthas/arthas.log
5. Visit https://github.com/alibaba/arthas/issues/47 for more details.
[arthas@20408]$
[arthas@20408]$
[arthas@20408]$
[arthas@20408]$ trace -E com.star.sms.richclient.accept.view.accept.acceptEditor2.ExchangePhysicalProductEditor subscriberChanged
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 3) cost in 152 ms, listenerId: 12
`---ts=2023-11-20 17:57:00;thread_name=AWT-EventQueue-0;id=f;is_daemon=false;priority=6;TCCL=com.star.sms.launch.LaunchURLClassLoader@17a8a02
    `---[12855.2434ms] com.star.sms.richclient.accept.view.accept.acceptEditor2.ExchangePhysicalProductEditor:subscriberChanged()
        +---[0.0065ms] org.apache.commons.logging.Log:debug() #115
        +---[0.0061ms] com.star.sms.richclient.accept.view.accept.acceptEditor2.ExchangePhysicalProductEditor:getSelectedSubscriber() #116
        +---[0.0033ms] com.star.sms.richclient.accept.view.accept2.page.displayer.ExchangePhyProductDisplayer:setSubscriber() #117
        +---[min=0.0032ms,max=0.0032ms,total=0.0064ms,count=2] com.star.sms.richclient.accept.view.accept.acceptEditor2.ExchangePhysicalProductEditor:getCurrentAction() #122
        +---[0.0031ms] com.star.sms.richclient.accept.view.accept.acceptEditor2.ExchangePhysicalProductEditor:getCurrentCustomer() #122
        +---[5947.6627ms] com.star.sms.richclient.accept.view.accept.acceptEditor2.ExchangePhysicalProductEditor:getPhyProducts() #122    // getPhyProducts消耗了6S
        +---[6907.4171ms] com.star.sms.richclient.accept.view.accept2.page.displayer.ExchangePhyProductDisplayer:onSubscriberChanged() #122  // getPhyProducts消耗了7S
        +---[0.0056ms] com.star.sms.richclient.accept.view.accept.acceptEditor2.ExchangePhysicalProductEditor:getCurrentCustomer() #126
        `---[0.0048ms] com.star.sms.richclient.accept.view.accept2.page.displayer.ExchangePhyProductDisplayer:setCurrentCustomer() #126
  

3.分析日志

从日志中可见, getPhyProducts 消耗了6秒, onSubscriberChanged消耗了7S。定位2个性能慢的方法后,进一步分析

[arthas@20408]$ trace -E com.star.sms.richclient.accept.view.accept2.page.displayer.ExchangePhyProductDisplayer onSubscriberChanged|getExchangableInfos|initOptionalPhysicalProducts
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 3) cost in 132 ms, listenerId: 14
`---ts=2023-11-20 17:59:13;thread_name=AWT-EventQueue-0;id=f;is_daemon=false;priority=6;TCCL=com.star.sms.launch.LaunchURLClassLoader@17a8a02
    `---[0.4848ms] com.star.sms.richclient.accept.view.accept2.page.displayer.ExchangePhyProductDisplayer:onSubscriberChanged()
        `---[0.1634ms] com.star.sms.richclient.accept.view.accept2.page.displayer.ExchangePhyProductDisplayer:clearTable() #195
 
`---ts=2023-11-20 17:59:19;thread_name=AWT-EventQueue-0;id=f;is_daemon=false;priority=6;TCCL=com.star.sms.launch.LaunchURLClassLoader@17a8a02
    `---[6979.1925ms] com.star.sms.richclient.accept.view.accept2.page.displayer.ExchangePhyProductDisplayer:onSubscriberChanged()
        +---[342.3417ms] com.star.sms.richclient.accept.view.accept2.page.displayer.ExchangePhyProductDisplayer:getExchangableInfos() #198
com.star.sms.model.order.dto.ExchangeInfo:setReturnResourceState() #1082
        +---[93.7515ms] com.star.sms.richclient.accept.view.accept2.page.displayer.ExchangePhyProductDisplayer:setTableDatas() #198
        `---[6543.0383ms] com.star.sms.richclient.accept.view.accept2.page.displayer.ExchangePhyProductDisplayer:initOptionalPhysicalProducts() #200
            `---[6542.9974ms] com.star.sms.richclient.accept.view.accept2.page.displayer.ExchangePhyProductDisplayer:initOptionalPhysicalProducts()    //initOptionalPhysicalProducts 消耗时间7S
                +---[0.0147ms] org.apache.commons.logging.Log:debug() #907
                +---[min=0.0015ms,max=0.0175ms,total=0.7956ms,count=202] com.star.sms.model.product.core.catalog.PhysicalProduct:getResourceDirectory() #911
                +---[min=0.0017ms,max=0.0306ms,total=0.6809ms,count=202] com.star.sms.model.product.other.ResourceDirectory:getId() #911
                +---[min=29.9191ms,max=55.5523ms,total=6528.053ms,count=202] com.star.sms.outerInterface.resource.service.IResourceExService:getResCatalogById() #911
                +---[min=0.0017ms,max=0.0447ms,total=1.0478ms,count=202] com.star.sms.model.resource.core.resparam.ResourceCatalog:getResourceType() #913
                +---[min=0.0034ms,max=0.0327ms,total=1.4611ms,count=202] com.star.sms.richclient.accept.view.accept2.page.displayer.ExchangePhyProductDisplayer:setPhysicalProductResourceType() #914
                +---[min=0.0023ms,max=0.0376ms,total=0.9837ms,count=202] org.apache.commons.logging.Log:isDebugEnabled() #929
                `---[0.0128ms] org.apache.commons.logging.Log:debug() #934

继续查看执行时间,发现程序中initOptionalPhysicalProducts 方法用时最长,是一个程序瓶颈,此方法中使用了循环,循环中IResourceExService:getResCatalogById方法调用了202次。

查看程序代码,这是一个典型的N+1此查询性能问题。 循环中调用了N此业务查询获取ResourceCatalog信息。

  private void initOptionalPhysicalProducts() {
        logger.debug("<== Begin to initialize the optional physical product... ==>");

        for (PhysicalProduct physicalProduct : physicalProducts) {
            ResourceCatalog resourceCatalog = resourceExService.getResCatalogById(physicalProduct .getResourceDirectory().getId());   // 这里存在N+1次查询, 其中N=202
           
            //省略代码 dosomething

            if (logger.isDebugEnabled()) {
                logger.debug("<-- Get a product,name is:" + physicalProduct.getName()
                        + "; and its resource type Id is :" + resourceType.getId() + " -->");
            }
        }
        logger.debug("<~~The end of the physical product to initialize the optional~~>");
    }

3.解决方法

对于N+1此查询可以通过id集合查询+分组方式来处理,修改后的代码

    private void initOptionalPhysicalProducts() {
        logger.debug("<== Begin to initialize the optional physical product... ==>");
        
        //1.获取ID集合
		List<Long> catalogids = new ArrayList<Long>();
		for (PhysicalProduct physicalProduct : physicalProducts) {
			catalogids.add(physicalProduct.getResourceDirectory().getId());
		}

        //2.只查询1次
		List<ResourceCatalog> catalogs = resourceExService.getResCatalogByIds(catalogids);
        
        //3.分组
		Map<Long, ResourceCatalog> map = new HashMap<Long, ResourceCatalog>();
		for (ResourceCatalog resourceCatalog : catalogs) {
			map.put(resourceCatalog.getId(), resourceCatalog);
		}
        
        for (PhysicalProduct physicalProduct : physicalProducts) {
            ResourceCatalog resourceCatalog = map.get(physicalProduct.getResourceDirectory().getId()); //内存里获取
           
            //省略代码 dosomething
            
            if (logger.isDebugEnabled()) {
                logger.debug("<-- Get a product,name is:" + physicalProduct.getName()
                        + "; and its resource type Id is :" + resourceType.getId() + " -->");
            }
        }
        logger.debug("<~~The end of the physical product to initialize the optional~~>");
    }

按照此处理方式,优化处理getPhyProducts 后问题解决,修正后业务处理时间在1秒内

上一篇:Jboss启动报错Unrecognized VM option PermSize=128m

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1260836.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

小程序----使用图表显示数据--canvas

需求&#xff1a;在小程序上实现数据可视化 思路&#xff1a;本来想用的是echarts或者相关的可视化插件&#xff0c;但因为用的是vue3&#xff0c;大多数插件不支持&#xff0c;所以用了echarts&#xff0c;但最后打包的时候说包太大超过2M无法上传&#xff0c;百度了一下&…

汽车功能安全ISO26262

一、功能安全基本概念及功能安全管理 什么是功能安全 相关标准&#xff1a; 现状&#xff1a; 功能安全的目的和范围&#xff1a; 总体框架&#xff1a; 基本定义&#xff1a;

vue3中toRaw 与 markRaw

toRaw 返回由 reactive 或 readonly 方法转换成响应式代理的普通对象。 这是一个还原方法&#xff0c;可用于临时读取&#xff0c;访问不会被代理/跟踪&#xff0c;写入时也不会触发界面更新。 markRaw 标记一个对象&#xff0c;使其永远不会转换为代理。返回对象本身 应…

企业软件手机app定制开发新趋势|网站小程序搭建

企业软件手机app定制开发新趋势|网站小程序搭建 随着移动互联网的快速发展和企业数字化转型的加速&#xff0c;企业软件手机App定制开发正成为一个新的趋势。这种趋势主要是由于企业对于手机App的需求增长以及现有的通用应用不能满足企业特定需求的情况下而产生的。 首先&#…

解决:AttributeError: module ‘os’ has no attribute ‘mknod’

解决&#xff1a;AttributeError: module ‘os’ has no attribute ‘mknod’ 文章目录 解决&#xff1a;AttributeError: module os has no attribute mknod背景报错问题报错翻译报错位置代码报错原因解决方法今天的分享就到此结束了 背景 在使用之前的代码时&#xff0c;报错…

小航助学题库蓝桥杯题库stem选拔赛(21年3月)(含题库教师学生账号)

需要在线模拟训练的题库账号请点击 小航助学编程在线模拟试卷系统&#xff08;含题库答题软件账号&#xff09;_程序猿下山的博客-CSDN博客 需要在线模拟训练的题库账号请点击 小航助学编程在线模拟试卷系统&#xff08;含题库答题软件账号&#xff09;_程序猿下山的博客-CSD…

小航助学题库蓝桥杯题库stem选拔赛(22年1月)(含题库教师学生账号)

需要在线模拟训练的题库账号请点击 小航助学编程在线模拟试卷系统&#xff08;含题库答题软件账号&#xff09;_程序猿下山的博客-CSDN博客 需要在线模拟训练的题库账号请点击 小航助学编程在线模拟试卷系统&#xff08;含题库答题软件账号&#xff09;_程序猿下山的博客-CSD…

【JDK21】详解虚拟线程

目录 1.概述 2.虚拟线程是为了解决哪些问题 2.1.线程切换的巨大代价 2.2.哪些情况会造成线程的切换 2.3.线程资源是有限的 3.虚拟线程 4.适用场景 1.概述 你发任你发&#xff0c;我用JAVA8&#xff1f;JDK21可能要对这句话say no了。 现在Oracle JDK是每4个版本&#x…

Android系统源码中添加可编译运行执行程序,C,C++

文章目录 Android系统源码中添加可编译运行执行程序&#xff0c;C&#xff0c;C1. 源码product分区中添加可执行程序 Android系统源码中添加可编译运行执行程序&#xff0c;C&#xff0c;C 1. 源码product分区中添加可执行程序 新建一个文件夹&#xff0c;以及一个test.cpp文…

【设计模式】03:单例模式

单例模式 OVERVIOW 单例模式1.单例模式实现2.饿汉与懒汉&#xff08;1&#xff09;饿汉模式&#xff08;2&#xff09;懒汉模式 3.懒汉线程安全1&#xff08;1&#xff09;引入互斥锁&#xff08;2&#xff09;引入双重检查锁定&#xff08;3&#xff09;引入原子变量 4.懒汉线…

RWA+AI 叙事下的 ProsperEx,对 Web3 时代交易的重新定义

RWA&#xff08;Real World Assets&#xff09;即现实资产代币&#xff0c;其本质在于将现实世界中具有货币价值的东西转化为数字代币&#xff0c;使其可以在区块链上表现价值并进行交易。RWA 资产既可以包括有形资产&#xff0c;例如房产、珠宝、黄金等&#xff0c;也可以包无…

第一节HarmonyOS DevEcoStudio工具下载以及环境搭建

一、下载与安装DevEco Studio 在HarmonyOS应用开发学习之前&#xff0c;需要进行一些准备工作&#xff0c;首先需要完成开发工具DevEco Studio的下载与安装以及环境配置。 进入DevEco Studio 工具下载官网&#xff1a;https://developer.harmonyos.com/cn/develop/deveco-stu…

OpenCvSharp从入门到实践-(04)色彩空间

目录 1、GRAY色彩空间 2、从BGR色彩空间转换到GRAY色彩空间 2.1色彩空间转换码 2.2实例 BGR色彩空间转换到GRAY色彩空间 3、HSV色彩空间 4、从BGR色彩空间转换到HSV色彩空间 4.1色彩空间转换码 4.2实例 BGR色彩空间转换到HSV色彩空间 1、GRAY色彩空间 GRAY色彩空间通常…

上游任务和下游任务

起源多任务学习中的定义理解结合定义分析例子示例 1&#xff1a;计算机视觉示例 2&#xff1a;自然语言处理示例 3&#xff1a;语音处理示例 4&#xff1a;强化学习总结 起源 "上游任务"和"下游任务"这两个术语在深度学习领域中通常用来描述一种 多任务学…

适用于iOS 的顶级苹果数据恢复软件

数据丢失可能随时发生在任何人身上&#xff0c;这可能是一种令人沮丧的经历。丢失 iOS 设备上的重要数据可能会造成特别严重的损失&#xff0c;因为其中可能包括有价值的照片、联系人、消息和其他重要文件。幸运的是&#xff0c;有多种数据恢复工具可以帮助用户恢复丢失的数据。…

Java数据结构与算法----字符串匹配(KMP算法)

KMP算法简介 是一种线性时间复杂度的字符串匹配、查找算法。 暴力实现字符串匹配 对于字符串的匹配&#xff0c;可以使用暴力进行匹配&#xff1a; 如图进行演示:&#xff08;以a串 ABABABCAA 被b串 ABABC 匹配为例&#xff09;&#xff1a; 第一轮匹配&#xff1a;&#x…

Linux静态库,共享库,计算机基础知识

1.库文件: 1).库文件库是一组预先编译好的方法的集合;Linux系统存储库的位置一般在/lib 和 /usr/lib (64位系统/usr/lib64)库的头文件放在/usr/include 2).库的分类 静态库:libxxx.a(命名规则) 共享库:libxxx.so(命名规则) 3).准备文件: //add.c int add(int x,int y) { retu…

前端学习系列之html

目录 初识html 发展史 优势 W3C 标准 地址 格式 网页基本标签 标题标签 段落标签 换行标签 水平线标签 字体样式 注释和特殊符号 特殊符号 图像、超链接 图像 常见图像格式 格式 超链接 格式 重要属性 href&#xff1a;规定链接指向的页面的 URL target…

线上问题整理-ConcurrentModificationException异常

项目场景&#xff1a; 商品改价&#xff1a;商品改价中通过多线程批量处理经过 Lists.partition拆分的集合对象 问题描述 商品改价中通过多线程批量处理经过 Lists.partition拆分的集合对象&#xff0c;发现偶尔会报 java.util.ConcurrentModificationException: nullat jav…

Vue3 + Scss 实现主题切换效果

Vue3 Scss 实现主题切换效果 先给大家看一下主题切换的效果&#xff1a; 像这样的效果实现起来并不难&#xff0c;只是比较麻烦&#xff0c;目前我知道的有两种方式可以实现&#xff0c;分别是 CSS 变量、样式文件切换&#xff0c;下面是该效果的核心实现方法 CSS变量 给…