牛逼的不停服定位线上问题-arthas

news2024/9/24 3:29:53


Hello,大家好我是你们可爱的小花。

前言

你是不是为了生产环境问题,无法定位、无法中断、无法解决
项目无故异常,日志无报错、报错不够明确
测试环境无法复现、生产环境问题偶发
但重启项目后问题消失,无法给领导一个答复而苦恼~

why?

别急别急
小花花在线帮你疑问解答

because:

生产环境情况复杂,程序多一,占用线程无法直观看到、内存无法直观定位、缓存无法直接查看、gc无法确定正常,出参入参无法断点调试,业务问题在不启动远程debug的场景下无法轻松找到
重启项目后,一切回到起点,占用内存、缓存、cpu、线程通通清空,重新计算
这就是为什么生产出现问题,一建重启便可解决绝大多数问题
重启可解决一时问题,没有从根本解决
所谓之:跑得了和尚、跑不了庙
当当当当当,废话太多,废话太多,进入主题
我我我我我我我我我我我发现了一款绝佳的线上诊断产品------arthas
(当然当然当然,大牛就别来笑话我了,初生小牛犊,小见解、小眼光(狗头保命))

Now!!!!!!
---------------------分割线---------------------------分割线-------------------------分割线--------------------------
我要一本正经了,大家耳朵竖起来了啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊

Arthas能解决什么问题?

Arthas 是一款线上监控诊断产品,通过全局视角实时查看应用 load、内存、gc、线程的状态信息,并能在不修改应用代码的情况下,对业务问题进行诊断,包括查看方法调用的出入参、异常,监测方法执行耗时,类加载信息等,大大提升线上问题排查效率。
Arthas 支持 JDK 6+,支持 Linux/Mac/Windows,采用命令行交互模式,同时提供丰富的 Tab 自动补全功能,进一步方便进行问题的定位和诊断。

怎样使用呢?

1、下载arthas

找一个你喜欢的文件夹输入以下命令下载arthas
curl -O https://arthas.aliyun.com/arthas-boot.jar
下载成功后会出现一个arthas-boot.jar的包
如果下载太慢,可更换为aliyun的镜像:java -jar arthas-boot.jar --repo-mirror aliyun --use-http
注意注意:执行该程序的用户需要和目标进程具有相同的权限。比如以myy用户来执行:sudo su myy && java -jar arthas-boot.jar 或 sudo -u myy -EH java -jar arthas-boot.jar
这里我使用网上的用例给大家来精确举例
下载一个小项目math-game
curl -O https://arthas.aliyun.com/math-game.jar
在这里插入图片描述

启用
java -jar math-game.jar

2、启动arthas进程

找一个舒服的姿势来执行以下命令,跟正常启动jar包命令一致
java -jar arthas-boot.jar

3、选择java程序进行监控

arthas启动成功后,会将所有正在运行的java进程罗列出来,只需要输入你想要监控线程前面的数字
我选择刚刚安装的数字游戏进程4
回车之后,出现arthas的图标之后,说明你的女神与你对接成功,女神为你爆灯
在这里插入图片描述

4、来吧来吧,接下来就看用那些骚操作,可更快读懂女神的心灵,为女神排忧解难

注注注,以下所有操作,都需要回车/enter确认之后查看结果,要不然你小声哔哔,女神怎能听的见

(1)dashboard

在这里插入图片描述

this is 查看控制面板的操作,改命令可查询到当前进程的信息,了解足够时可按ctrl+c中断该了解
可看到第一个框中显示正在运行的线程id、名称、组。。。。的信息
第二个框显示内存使用情况
第三个框显示运行环境
每5秒刷新一次面板
比如内存泄露:如果内存使用率在不断上升,而且gc后也不下降,后面还发现gc越来越频繁,很可能就是内存泄漏了。
这个时候我们可以直接用heapdump命令:heapdump --live /root/jvm.hprof 把内存快照dump出来,作用和jmap工具一样(jmap -dump:live):
下载下来,再使用内存dump分析工具,比如:MAT( Eclipse Memory Analyzer),分析可能泄露的内存原因

(2)thread 线程id

当发现某个线程cpu过高时,可通过thread 线程id命令开输出该线程的栈信息
通过 thread 线程id命令来获取到math-game进程的名称
thread -n 3 查看CPU使用率top n线程的栈
比如我们输入 thread 1 回车
搜索thread 1 | grep main
可看到类名
thread -b 可查看是否有线程阻塞:找出当前阻塞其他线程的线程。有时候我们发现应用卡住了, 通常是由于某个线程拿住了某个锁, 并且其他线程都在等待这把锁造成的

(3)jad 类名

通过jad 类名来反编译代码
回车后代码就反编译成功,

ClassLoader:
+-sun.misc.Launcher$AppClassLoader@3d4eac69
  +-sun.misc.Launcher$ExtClassLoader@66350f69

Location:
/tmp/math-game.jar

/*
 * Decompiled with CFR 0_132.
 */
package demo;

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

public class MathGame {
    private static Random random = new Random();
    private int illegalArgumentCount = 0;

    public static void main(String[] args) throws InterruptedException {
        MathGame game = new MathGame();
        do {
            game.run();
            TimeUnit.SECONDS.sleep(1L);
        } while (true);
    }

    public void run() throws InterruptedException {
        try {
            int number = random.nextInt();
            List<Integer> primeFactors = this.primeFactors(number);
            MathGame.print(number, primeFactors);
        }
        catch (Exception e) {
            System.out.println(String.format("illegalArgumentCount:%3d, ", this.illegalArgumentCount) + e.getMessage());
        }
    }

    public static void print(int number, List<Integer> primeFactors) {
        StringBuffer sb = new StringBuffer("" + number + "=");
        Iterator<Integer> iterator = primeFactors.iterator();
        while (iterator.hasNext()) {
            int factor = iterator.next();
            sb.append(factor).append('*');
        }
        if (sb.charAt(sb.length() - 1) == '*') {
            sb.deleteCharAt(sb.length() - 1);
        }
        System.out.println(sb);
    }

    public List<Integer> primeFactors(int number) {
        if (number < 2) {
            ++this.illegalArgumentCount;
            throw new IllegalArgumentException("number is: " + number + ", need >= 2");
        }
        ArrayList<Integer> result = new ArrayList<Integer>();
        int i = 2;
        while (i <= number) {
            if (number % i == 0) {
                result.add(i);
                number /= i;
                i = 2;
                continue;
            }
            ++i;
        }
        return result;
    }
}

Affect(row-cnt:1) cost in 970 ms.

有兴趣的小朋友可以编译好代码看看是否正确

可单独查看方法
jad demo.MathGame print

(4)watch

watch+类名+方法名+returnObj
可看到函数的返回值

watch demo.MathGame primeFactors returnObj

返回数据

Affect(class-cnt:1 , method-cnt:1) cost in 107 ms.
ts=2018-11-28 19:22:30; [cost=1.715367ms] result=null
ts=2018-11-28 19:22:31; [cost=0.185203ms] result=null
ts=2018-11-28 19:22:32; [cost=19.012416ms] result=@ArrayList[
    @Integer[5],
    @Integer[47],
    @Integer[2675531],
]
ts=2018-11-28 19:22:33; [cost=0.311395ms] result=@ArrayList[
    @Integer[2],
    @Integer[5],
    @Integer[317],
    @Integer[503],
    @Integer[887],
]
ts=2018-11-28 19:22:34; [cost=10.136007ms] result=@ArrayList[
    @Integer[2],
    @Integer[2],
    @Integer[3],
    @Integer[3],
    @Integer[31],
    @Integer[717593],
]
ts=2018-11-28 19:22:35; [cost=29.969732ms] result=@ArrayList[
    @Integer[5],
    @Integer[29],
    @Integer[7651739],
]
watch 类名 方法名 "{params,returnObj}" -x 3 -b -s 
可查看入参和返回值
-x 3是指定输出结果的属性遍历深度,默认为 1
-b方法调用前观察,用于返回方法入参
-s方法调用后观察,用于返回方法返回值

(5)monitor监控

 monitor -c 10 demo.MathGame primeFactors  

每10秒监控方法的执行情况
包括:成功次数、失败次数、平均响应时间、失败率

  • 监控primeFactors这个方法的执行情况
  • -c 10 指定统计周期为10秒统计一次,默认是120秒统计一次

(6)tt命令: TimeTunnel 记录下方法执行数据的时空隧道

tt -t demo.MathGame primeFactors

INDEX: 时间片段记录编号,每一个编号代表着一次调用,后续tt还有很多命令都是基于此编号指定记录操作,非常重要。
TIMESTAMP: 方法执行的本机时间,记录了这个时间片段所发生的本机时间
COST(ms): 方法执行的耗时
IS-RET: 方法是否以正常返回的形式结束
IS-EXP: 方法是否以抛异常的形式结束
OBJECT: 执行对象的hashCode(),注意,曾经有人误认为是对象在JVM中的内存地址,但很遗憾他不是。但他能帮助你简单的标记当前执行方法的类实体
CLASS: 执行的类名
METHOD: 执行的方法名

如果看到IS-RET中有false,可记住index
用以下快速重新重新调用一次

tt -i 1002 -p

表示重做Index为1002的那次调用

(7)stack命令:监控方法的被执行的路径

很多时候我们都知道一个方法被执行,但不知道被谁在调用
stack 命令, 主要用于监控方法被谁调用了:
stack 类名 方法名

(8)sm命令:能搜索出所有已经加载了 Class 信息的方法信息

sm -d 类名

(9)logger

动态更新日志级别
使用sc命令查看需要改变的类信息,classLoaderHash为类加载的hash值
使用hash值和类名
查看类的日志级别

logger -c hash值 --name 类名

更改日志级别:

logger -c hash值 --name 类名 --level 级别(debug\info\error)

好了好了,到这里就结束了,如果还有啥不理解的可以评论或简单粗暴看官网啊~

总结:

arthas是一个可以不停服进行java项目诊断的产品,操作简单,都是命令,忘记命令的可直接上网搜索

我是小花,一个专注于Java后端研发的小姑娘,觉得文章有帮助到你的,关注、再看、点赞,三连哦~

最后,欢迎大家关注Java程序人生公众号,每日分享互联网行业故事、经验技术技术
在这里插入图片描述

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

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

相关文章

ChatGPT冷观察:没有大模型的土壤,开不出ChatBot的花

文|智能相对论作者|叶远风谁在跟风&#xff0c;谁又有真本事能做出中国版的对标产品来&#xff1f;这恐怕是ChatGPT这股热潮以来&#xff0c;关心中国AI发展的业界人士最想问的问题。或者说&#xff0c;在中国人工智能不落后于全世界的当下&#xff0c;业界也在普遍渴望一个真正…

AWS Directory Service

Hello大家好&#xff0c;我们接下来讨论AWS Directory Service&#xff0c;AWS目录服务的内容。 什么是微软活动目录&#xff08;AD&#xff09; 在认证考试中有很多的考点是关于微软AD部分的&#xff0c;也就是微软活动目录以及AWS活动目录服务—AWS Directory Service的内容…

PowerShell Install Mysql 8

MySQL介绍 MySQL 是最流行的关系型数据库管理系统,在 WEB 应用方面 MySQL 是最好的 RDBMS(Relational Database Management System:关系数据库管理系统)应用软件之一。 mysql download Mysql Serverdownload创建一键安装Mysql 8自动化脚本 Expand-Archive #解压文件Start-P…

【我有一个梦想:帮你实现你的梦想】

很多人都曾有过这样的经历&#xff0c;某天突然对某个东西产生了兴趣&#xff0c;于是兴致勃勃的开始在网上各种搜&#xff0c;各种查&#xff0c;去各大论坛到处看到处问&#xff0c;在网上搜集很多免费的电子书&#xff0c;看了很多视频&#xff0c;最后忙活了一阵子&#xf…

若依框架如何新增自定义主题风格

若依框架新增主题风格1.实现结果2.实现步骤2.1Settings目录下2.2 variables.scss2.3 sidebar.scss2.4 Logo.vue2.5 Siderbar目录下的index.vue1.实现结果 2.实现步骤 需要改动的文件目录&#xff1a; 2.1Settings目录下 <div class"setting-drawer-block-checbox-it…

DBeaver:开源、跨平台、强大的数据库管理工具

文章目录一、简介1.DBeaver 是什么2.DBeaver 的功能3.DBeaver 的优点二、安装与配置1.系统要求2.下载与安装3.连接数据库三、总结一、简介 1.DBeaver 是什么 DBeaver 是一个流行的开源数据库客户端&#xff0c;它可以用于连接和管理多种不同类型的数据库系统&#xff0c;包括…

什么是STAR原则?

文章目录&#x1f4cb;前言&#x1f525;省流版&#x1f3af;什么是STAR原则&#x1f3af;进行过程&#x1f4cb;前言 对于大部分还在学习阶段的学生们来说&#xff0c;可能并不了解这个原则的含义&#xff0c;这里的star并不是指英文单词星星。这个原则我也是前段时间才认识到…

CS224W课程学习笔记(二):网络图的特征说明和指标实战

引言 在第二三节课中&#xff0c;主要研究的是四个关键网络属性以表征图形&#xff1a;度分布&#xff0c;路径长度&#xff0c;聚类系数和连接组件 。 这些定义主要是针对无向图的&#xff0c;而由于上一节中已经介绍了度分布&#xff0c;以及相应公式和例题&#xff0c;关于…

刚性电路板的特点及与柔性电路板的区别

打开市场上的任何一个电子产品&#xff0c;会发现里面都有一块或多块电路板。电路板是电子产品运行的核心&#xff0c;之前沐渥小编已经给大家介绍了柔性电路板&#xff0c;下面给大家介绍刚性电路板的基础知识。 刚性电路板俗称硬板&#xff0c;是由不容易变形的刚性基材制成的…

MASA Stack 1.0 发布会 —— 社区问题解答

MASA Stack 1.0 圆桌讨论 Q1&#xff1a; 全职开源的团队&#xff0c;你们的收入是什么&#xff1f; 1.首先感谢我们的金主朗诗德公司&#xff0c;朗诗德是一家大型的净水器研发、生产、销售的公司&#xff0c;我们的产品也在朗诗德公司进行了大量的落地验证&#xff0c;再次…

Kotlin新手教程二(Kotlin基本数据类型及基础语法)

一、基本数据类型 1.数字 由于Kotlin支持类型推断&#xff0c;所以在使用时若超出Int的范围则会被认定为其它类型&#xff1b;若需要显式指定Long型值&#xff0c;则需要在值后添加L后缀。 2.浮点数 3.比较两个数&#xff08; 和 &#xff09; Kotlin 中没有基础数据类型&a…

C语言(输出scanf()函数)

一.概念带入 scanf()把输入的字符串转换成整数&#xff0c;浮点数&#xff0c;字符或字符串。而printf()正好与其相反&#xff0c;把整数&#xff0c;浮点数&#xff0c;字符和字符串转换成显示在屏幕上的文本。所以scanf&#xff08;&#xff09;在使用上面会和printf有很多一…

实验十四、共源放大电路的频率响应

一、题目 利用 Multisim 从下列两个方面研究图1所示电路的频率响应。图1共源放大电路图1\,\,共源放大电路图1共源放大电路&#xff08;1&#xff09;为改善低频特性&#xff0c;应增大三个耦合电容中的哪一个最有效。 &#xff08;2&#xff09;场效应管的漏极静态电流对上限频…

审批流、工作流、业务流

是业务流、工作流、审批流 业务流&#xff1a;即业务流程&#xff0c;指为了完成某项业务而进行的各种工作的有序组合 工作流&#xff1a;即工作流程&#xff0c;指为了完成某项工作而进行的各种动作的有序组合 审批流&#xff1a;即审批流程&#xff0c;是对某项工作的审批活动…

记录一次服务器被攻击的经历

突然收到阿里云发过来的异常登陆的信息&#xff1a; 于是&#xff0c;急忙打开电脑查看对应的ECS服务器的记录&#xff1a; 发现服务器的cpu占用率异常飙升&#xff0c;所以可以大概断定服务器已经被非法入侵了。 通过自己的账号登陆后&#xff0c;发现sshd服务有异常的链接存…

TensorRT的命令行程序

TensorRT的命令行程序 文章目录TensorRT的命令行程序A.3.1. trtexecA.3.1.1. Benchmarking NetworkA.3.1.2. Serialized Engine GenerationA.3.1.3. trtexecA.3.1.4. 常用的命令行标志点击此处加入NVIDIA开发者计划 A.3.1. trtexec 示例目录中包含一个名为trtexec的命令行包装…

关于表的操作+1 数据库(4)

素材&#xff1a; 学生表&#xff1a;Student (Sno, Sname, Ssex , Sage, Sdept) 学号&#xff0c;姓名&#xff0c;性别&#xff0c;年龄&#xff0c;所在系 Sno为主键 课程表&#xff1a;Course (Cno, Cname) 课程号&#xff0c;课程名 Cno为主键 学生选课表&#xff1a;SC (…

常见的5大软件项目风险,如何进行规避?

1、客户没有或很少参与项目 日常项目开发中&#xff0c;容易出现这样的风险&#xff1a;客户在最开始的时候提交了一份文档&#xff0c;在项目启动、计划和执行阶段&#xff0c;客户没有参与&#xff0c;只是在项目收尾时进行验收&#xff0c;客户一旦发现开发结果与预期需求相…

第42天|LeetCode121. 买卖股票的最佳时机、LeetCode122. 买卖股票的最佳时机 II

1.题目链接&#xff1a;121. 买卖股票的最佳时机 题目描述&#xff1a; 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法…

C++类基础(十六)

类的继承——继承与特殊成员函数 ● 派生类合成的…… – 缺省构造函数会隐式调用基类的缺省构造函数 – 拷贝构造函数将隐式调用基类的拷贝构造函数 – 赋值函数将隐式调用基类的赋值函数 struct Base {Base(){std::cout << "Base()\n";}Base(const Base&…