使用Arthas排查性能问题

      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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

unity学习笔记10

一、生命周期函数 1.Awake() 调用时间&#xff1a;对象被激活或创建时。 用途&#xff1a;通常用于初始化对象的状态&#xff0c;获取组件引用或执行其他在脚本生命周期早期需要完成的任务。 2.OnEnable(): 调用时间&#xff1a;对象激活时&#xff0c;包括对象被创建和Se…

每天五分钟计算机视觉:经典架构的力量与启示

在深度学习和计算机视觉领域,卷积神经网络(Convolutional Neural Networks,简称CNN)无疑是最为经典的架构之一。近年来,随着研究的不断深入和新架构的不断涌现,许多初学者可能会忽视这些经典架构的重要性。然而,理解并学习这些经典架构,对于我们深入理解卷积神经网络的…

操作系统 选择题 期末试题 考研真题 + 参考答案

1.&#xff08;考研真题&#xff0c;单项选择题&#xff09;单道批处理系统的主要缺点是&#xff08; &#xff09;。 A. CPU利用率不高 B.失去了交互性 C.不具备并行性 D.以上都不是 【参考答案】A 【解析】单道批处理系统的内存中只有一道程序&#xff0c;当该程序…

苍穹外卖项目笔记(5)——Redis

1 入门 1.1 Redis 简介 Redis 是一个基于内存的 key-value 结构数据库&#xff0c;官网链接&#xff08;中文&#xff09;&#xff1a;https://www.redis.net.cn 特点&#xff1a; 基于内存存储&#xff0c;读写性能高适合存储热点数据&#xff08;热点商品、资讯、新闻&am…

vue3(二)-基础入门之列表循环、数组变动检测、filter模糊查询、事件修饰符

一、列表循环 of 和 in 都是一样的效果 html代码&#xff1a; <div id"app"><ul><li v-for"item of datalist">{{ item }}</li></ul><ul><li v-for"item in dataobj">{{ item }}</li></u…

3D点云目标检测:CT3D解读(未完)

CT3D 一、RPN for 3D Proposal Generation二、Proposal-to-point Encoding Module2.1、Proposal-to-point Embedding2.2、Self-attention Encoding 三、Channel-wise Decoding Module3.1、Standard Decoding3.2、Channel-wise Re-weighting3.3、Channel-wise Decoding Module 四…

数据库之索引的底层数据逻辑及应用

索引&#xff08;index&#xff09;是帮助数据库高效获取数据的数据结构。 索引的数据结构 堆存储 使用二叉树存储 极端情况下的单链形式 大数据量下&#xff0c;层级越深&#xff0c;查询效率越低。 平衡二叉树 多路平衡查找树 B树的结构 所有的数据都存储在叶结点中…

redis Redis::geoAdd 无效,phpstudy 如何升级redis版本

redis 查看当前版本命令 INFO SERVERwindows 版redis 进入下载 geoadd 功能在3.2之后才有的&#xff0c;但是phpstudy提供的最新的版本也是在3.0&#xff0c;所以需要升级下 所以想出一个 挂狗头&#xff0c;卖羊肉的方法&#xff0c;下载windows 的程序&#xff0c;直接替…

Cache学习(3):Cache地址映射(直接映射缓存组相连缓存全相连缓存)

1 Cache的与存储地址的映射 以一个Cache Size 为 128 Bytes 并且Cache Line是 16 Bytes的Cache为例。首先把这个Cache想象成一个数组&#xff0c;数组总共8个元素&#xff0c;每个元素大小是 16 Bytes&#xff0c;如下图&#xff1a; 现在考虑一个问题&#xff0c;CPU从0x0654…

Vue3 + Scss 实现主题切换效果

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

3D数字孪生场景编辑器

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 数字孪生的强大功能来自于将真实世界的资产与真实世界的数据联系起来&#xff0c;因此您可以…

95.STL-遍历算法 for_each

算法概述: 算法主要是由头文件 <algorithm> <functional> <numeric> 组成。 <algorithm> 是所有STL头文件中最大的一个&#xff0c;范围涉及到比较、 交换、查找、遍历操作、复制、修改等等 <numeric> 体积很小&#xff0c;只包括几个在序列上面…

激光线提取

在做单线激光三维重建&#xff0c;和多线激光三维重建的时候都会设计到激光线提取算法的实现&#xff0c;如何保持高速和高精度是关键 &#xff0c;最近优化了steger中心线提取算法&#xff0c;通过并行化实现在cpu版本可以做到2m,GPU版本可以做到0.6ms左右&#xff0c;完全可…

华为智能手表独立导航,一呼即应轻松畅行

PetalMaps 手表独立导航&#xff0c;一声令下唤醒导航&#xff0c;打造了智慧的语音交互唤醒体验功能。导航时&#xff0c;语音播报、变道震动提醒功能&#xff0c;让您尽情体验腕上导航乐趣&#xff0c;同时又能安全抵达目的地。

pinpoint链路跟踪运用及日志logback配置

本文将讲述pinpoint的安装&#xff0c;使用及与java logback 日志的集成。 介绍 是什么 是一款 APM监控工具(Application Performance Management/应用性能管理)基于java编写用于 大规模分布式系统 的监控&#xff0c;是 分析 大规模分布式系统 的平台基于google Dapper开发&…

路径规划之A*算法

系列文章目录 路径规划之Dijkstra算法 路径规划之Best-First Search算法 路径规划之A*算法 路径规划之A*算法 系列文章目录前言一、前期准备1.1 算法对比1.2 数学式方法1.3 启发式方法 二、A*算法2.1 起源2.2 思想2.3 启发式函数2.4 过程2.5 案例查看 前言 之前提过Dijkstra算…

vue3中readonly和shallowReadonly

readonly: 深度只读数据 获取一个对象 (响应式或纯对象) 或 ref 并返回原始代理的只读代理。 只读代理是深层的&#xff1a;访问的任何嵌套 property 也是只读的。 shallowReadonly 浅只读数据 创建一个代理&#xff0c;使其自身的 property 为只读&#xff0c;但不执行…

文件权限中 chmod、u+x、u、r、w、x分别代表什么

Linux系统中的每个文件和目录都有访问许可权限&#xff0c;如下面所示&#xff1a; 要说清楚问题&#xff0c;我们截取一些内容&#xff1a; ypyubuntu:~$ ls -l drwxr-xr-- 2 ypy ypy 4096 Nov 30 18:33 Desktop/ drwxr-xr-- 2 ypy ypy 4096 Nov 30 18:33 Documen…

视频没有字幕怎么办,怎么给视频增加字幕

文章目录 视频没有字幕怎么办&#xff0c;怎么给视频增加字幕前言软件准备制作字幕1. 导入视频2. 将视频拖拽到轨道3. 生成字幕4. 导出字幕 字幕实时翻译1. 播放视频2. 显示字幕设置3. 双语字幕显示 总结 视频没有字幕怎么办&#xff0c;怎么给视频增加字幕 前言 有时候下载的…

第二节HarmonyOS DevEco Studio创建项目以及界面认识

一、创建项目 如果你是首次打开DevEco Studio&#xff0c;那么首先会进入欢迎页。 在欢迎页中单击Create Project&#xff0c;进入项目创建页面。 选择‘Application’&#xff0c;然后选择‘Empty Ability’&#xff0c;单击‘Next’进入工程配置页。 配置页中&#xff0c;详…