使用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//省略代码 dosomethingif (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()); //内存里获取//省略代码 dosomethingif (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.mzph.cn/news/175356.shtml

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

相关文章

Open Feign 源码解析(四) --- 请求对象构造(上)

Open Feign 源码解析四 请求对象的构造&#xff08;上&#xff09; 源码前三篇文章写了这个图的过程 源码前三篇文章的内容归纳起来就是讲了这样的问题&#xff1a; 如何把接口转换为具有发送http请求能力的feign client对象以及如何整合到Spring容器中&#xff1f; 如何构造…

普通表计读数开发思路

一、普通表计类型介绍&#x1f349; 常见的普通表计有SF6&#xff0c;压力表&#xff0c;油位表&#xff08;指针类&#xff09;等。 图1&#xff1a;( 压力表) 图2&#xff1a;&#xff08;油位表-指针类&#xff09; 图3&#xff1a;&#xff08;SF6表&#xff09; 图4:&a…

linux 磁盘管理、分区管理常用命令

文章目录 基础命令挂载新硬盘/分区添加内存交换分区swaplvm分区管理模式 基础命令 查看目录文件大小 du -sh /backup du -sh /backup/* du -sh *查看磁盘挂载信息 df -lhT查看某个目录挂载在哪个分区&#xff0c;以及分区的磁盘使用情况 df [目录] #例如&#xff1a;df /ho…

(二) Windows 下 Sublime Text 3 安装离线插件 Anaconda

1 下载 Sublime Text 3 免安装版 Download - Sublime Text 2 下载 Package Control&#xff0c;放到 Sublime Text Build 3211\Data\Installed Packages 目录下。 Installation - Package Control 3 页面搜索 anaconda anaconda - Search - Package Control Anaconda - Pac…

vue3通过provide和inject实现多层级组件通信

父组件 <template><div><h1>我是父组件 {{num}}</h1><hr><child></child></div> </template><script setup> import child from ./child.vue; import { ref,provide } from vue; let num ref(520) provide(pare…

kafka的详细安装部署

简介&#xff1a; Kafka是一个分布式流处理平台&#xff0c;主要用于处理高吞吐量的实时数据流。Kafka最初由LinkedIn公司开发&#xff0c;现在由Apache Software Foundation维护和开发。 Kafka的核心是一个分布式发布-订阅消息系统&#xff0c;它可以处理大量的消息流&#…

PHP TCP服务端监听端口接收客户端RFID网络读卡器上传的读卡数据

本示例使用设备&#xff1a;WIFI/TCP/UDP/HTTP协议RFID液显网络读卡器可二次开发语音播报POE-淘宝网 (taobao.com) <?php header("content-type:text/html;charsetGBK");set_time_limit(0); $port39169; //监听端口if(($socket socket_create(AF_INET, SOCK…

共享模型之不可变

前言 该文章后续还需要进行修改&#xff01;&#xff01; 不可变的解释是对象属性不可以更改。 在多线程下&#xff0c;格式转化使用SimpleDateFormat可能会报错。这是因为线程之间互相影响导致。 public class test {public static void main(String[] args) {SimpleDateFo…

抽象类-Java

抽象类 一、父类方法的不确定性二、抽象类介绍三、抽象类细节四、练习题 一、父类方法的不确定性 引入&#xff1a;对于一个动物&#xff0c;不知道它吃什么&#xff0c;比如猫吃鱼&#xff0c;兔子吃萝卜。动物类中的 eat 方法往往由它的子类去具体实现。 class Animal {pub…

qgis添加arcgis的FeatureServer

左侧浏览器-ArcGIS要素服务器-新建连接 http://sampleserver6.arcgisonline.com/arcgis/rest/services/ 展开-双击即可

sql中group by和having的使用

group by&#xff1a;按照某个字段或者某些字段进行分组。 having&#xff1a;对分组之后的数据进行再次过滤&#xff0c;having必须和group by一起用&#xff0c;且在group by后面。 比如person表如下&#xff08;以下查询均基于此表&#xff09;&#xff1a; 1.group by 用法…

为何要隐藏IP地址?网络上哪些行为需要隐藏IP和更换IP?

网络已经成为现代人生活的重要组成部分&#xff0c;人们在网络上交流、学习、娱乐、购物等。但是&#xff0c;在享受网络带来的便利时&#xff0c;我们也需要时刻保护自己的隐私和安全。其中&#xff0c;IP地址作为网络通信中的重要标识&#xff0c;如何隐藏以及在哪些情况下需…

C语言题目强化-DAY12

题型指引 一、选择题二、编程题 ★★写在前面★★ 本题库源自互联网&#xff0c;仅作为个人学习使用&#xff0c;记录C语言题目练习的过程&#xff0c;如果对你也有帮助&#xff0c;那就点个赞吧。 一、选择题 1、请阅读以下程序&#xff0c;其运行结果是&#xff08; &#x…

CMake语法解读 | Qt6需要用到

CMake 入门CMakeLists.txtmain.cpp编译示例cmake常用参数入门 Hello CMake CMake 是一个用于配置跨平台源代码项目应该如何配置的工具建立在给定的平台上。 ├── CMakeLists.txt # 希望运行的 CMake命令 ├── main.cpp # 带有main 的源文件 ├── include # 头文件目录 …

GLM: 自回归空白填充的多任务预训练语言模型

当前&#xff0c;ChatGLM-6B 在自然语言处理领域日益流行。其卓越的技术特点和强大的语言建模能力使其成为对话语言模型中的佼佼者。让我们深入了解 ChatGLM-6B 的技术特点&#xff0c;探索它在对话模型中的创新之处。 GLM: 自回归空白填充的多任务预训练语言模型 ChatGLM-6B 技…

C++二分查找视频教程:两数之和

作者推荐 利用广度优先或模拟解决米诺骨牌 本文涉及的基础知识点 二分查找算法合集 题目 给你一个下标从 1 开始的整数数组 numbers &#xff0c;该数组已按 非递减顺序排列 &#xff0c;请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 n…

Webhook端口中的自签名身份验证

概述 有时&#xff0c;可能需要通过 Webhook 端口从交易伙伴处接收数据&#xff0c;但该交易伙伴可能需要更多的安全性&#xff0c;而不仅仅是用于验证入站 Webhook 请求的基本身份验证用户名/密码 – 或者您可能只想在入站 Webhook 消息上添加额外的安全层。 使用 Webhook 端…

使用STM32和蓝牙模块进行无线数据传输的实践

无线数据传输在现代通信领域中具有重要的地位&#xff0c;而蓝牙技术是一种常用的无线数据传输技术。本文介绍了如何使用STM32微控制器和蓝牙模块实现无线数据传输的方案&#xff0c;包括硬件设计、蓝牙模块配置、数据发送和接收等步骤&#xff0c;并给出相应的代码示例。 一、…

Codebeamer—软件全生命周期管理轻量级平台

产品概述 Codebeamer涵盖了软件研发的生命周期&#xff0c;在一个整合的平台内支持需求管理、测试管理、软件开发过程管理以及项目管理等&#xff0c;同时具有IToperations&DevOps相关的内容&#xff0c;并支持变体管理的功能。对于使用集成的应用程序生命周期管理&#xf…

13.端点、簇、属性

源码地址&#xff1a;13.端点、簇、属性 端点&#xff08;endPoint&#xff09; 一个端点就是一个应用 一个字节编号&#xff0c;数据收和发送的基本单元&#xff0c;在模块通信的时候&#xff0c;发送模块必须指定收发双方模块的网络地址和端点。端点要使用必须要和模块里的…