arthas使用分析

一 简介

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

arthas详细官网介绍说明文档:简介 | arthas

Arthas实现的原理:

  • 利用Instrumentation实现Java字节码的动态修改和增强,以实现方法拦截等功能。(Instrumentation是JDK1.5后新增的一个特性,它允许在程序运行时动态地修改或者增强Java类的行为,而不需要修改原始的字节码文件。Java Instrumentation API允许开发者通过编写一个代理程序(Agent)来监控和修改Java程序的运行状态)。

  • 利用Java Debug接口实现线程的调试和监控,包括线程的挂起、恢复和修改等操作。

  • 利用Java Attach机制或者Java Debug Wire Protocol(JDWP)协议实现对远程Java进程的连接和调试。 具体来说,Arthas的实现原理分为三个部分: Agent:Arthas作为Java Agent,通过代理方式加载到目标Java进程中,与目标进程建立通信管道,通过该管道向目标进程发送指令,并接收目标进程的响应数据。 Transformer:通过Instrumentation API,Arthas可以修改目标Java进程中的字节码,实现方法拦截和增强等功能。

a

背景

通常,本地开发环境无法访问生产环境。如果在生产环境中遇到问题,则无法使用 IDE 远程调试。更糟糕的是,在生产环境中调试是不可接受的,因为它会暂停所有线程,导致服务暂停。

开发人员可以尝试在测试环境或者预发环境中复现生产环境中的问题。但是,某些问题无法在不同的环境中轻松复现,甚至在重新启动后就消失了。

如果您正在考虑在代码中添加一些日志以帮助解决问题,您将必须经历以下阶段:测试、预发,然后生产。这种方法效率低下,更糟糕的是,该问题可能无法解决,因为一旦 JVM 重新启动,它可能无法复现,如上文所述。

Arthas 旨在解决这些问题。开发人员可以在线解决生产问题。无需 JVM 重启,无需代码更改。 Arthas 作为观察者永远不会暂停正在运行的线程。

1.Arthas(阿尔萨斯)能为你做什么?

Arthas 是 Alibaba 开源的 Java 诊断工具,深受开发者喜爱。

当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决:

  1. 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?

  2. 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?

  3. 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?

  4. 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!

  5. 是否有一个全局视角来查看系统的运行状况?

  6. 有什么办法可以监控到 JVM 的实时运行状态?

  7. 怎么快速定位应用的热点,生成火焰图?

  8. 怎样直接从 JVM 内查找某个类的实例?

Arthas 支持 JDK 6+,支持 Linux/Mac/Windows,采用命令行交互模式,同时提供丰富的 Tab 自动补全功能,进一步方便进行问题的定位和诊断。

2. 启动 arthas

默认在公司的容器平台k8s中,arthas访问目录:/tmp/arthas-boot.jar

公司对于arthas使用说明:https://wiki.mokahr.com/pages/viewpage.action?pageId=116730746

示例:https://k8s.mokahr.com/kubernetes/Staging/console/staging-1/ai-search-platform-76f7775cfd-tr4j4?container=ai-search-platform&k8sToken&shell=bash

在命令行下面执行(使用和目标进程一致的用户启动,否则可能 attach 失败,):

curl -O https://arthas.aliyun.com/arthas-boot.jar(下载arthas)
java -jar arthas-boot.jar
  • 执行该程序的用户需要和目标进程具有相同的权限。比如以admin用户来执行:sudo su admin && java -jar arthas-boot.jarsudo -u admin -EH java -jar arthas-boot.jar

  • 如果 attach 不上目标进程,可以查看~/logs/arthas/ 目录下的日志。

  • 如果下载速度比较慢,可以使用 aliyun 的镜像:java -jar arthas-boot.jar --repo-mirror aliyun --use-http

  • java -jar arthas-boot.jar -h 打印更多参数信息。

选择应用 java 进程:

$ $ java -jar arthas-boot.jar
* [1]: 35542
  [2]: 71560 math-game.jar

math-game进程是第 2 个,则输入 2,再输入回车/enter。Arthas 会 attach 到目标进程上,并输出日志:

[INFO] Try to attach process 71560
[INFO] Attach process 71560 success.
[INFO] arthas-client connect 127.0.0.1 3658
  ,---.  ,------. ,--------.,--.  ,--.  ,---.   ,---.
 /  O  \ |  .--. ''--.  .--'|  '--'  | /  O  \ '   .-'
|  .-.  ||  '--'.'   |  |   |  .--.  ||  .-.  |`.  `-.
|  | |  ||  |\  \    |  |   |  |  |  ||  | |  |.-'    |
`--' `--'`--' '--'   `--'   `--'  `--'`--' `--'`-----'
​
​
wiki: https://arthas.aliyun.com/doc
version: 3.0.5.20181127201536
pid: 71560
time: 2018-11-28 19:16:24
​
$

3.查看dashboard

如果你不知道arthas所支持的命令和功能,输入help可以看到所有的命令以及命令的详细说明

arthas@7]$ help
 NAME         DESCRIPTION                                                                                                                                                                                     
 help         Display Arthas Help                                                                                                                                                                             
 auth         Authenticates the current session                                                                                                                                                               
 keymap       Display all the available keymap for the specified connection.                                                                                                                                  
 sc           Search all the classes loaded by JVM                                                                                                                                                            
 sm           Search the method of classes loaded by JVM                                                                                                                                                      
 classloader  Show classloader info                                                                                                                                                                           
 jad          Decompile class                                                                                                                                                                                 
 getstatic    Show the static field of a class                                                                                                                                                                
 monitor      Monitor method execution statistics, e.g. total/success/failure count, average rt, fail rate, etc.                                                                                              
 stack        Display the stack trace for the specified class and method                                                                                                                                      
 thread       Display thread info, thread stack                                                                                                                                                               
 trace        Trace the execution time of specified method invocation.                                                                                                                                        
 watch        Display the input/output parameter, return object, and thrown exception of specified method invocation                                                                                          
 tt           Time Tunnel                                                                                                                                                                                     
 jvm          Display the target JVM information                                                                                                                                                              
 memory       Display jvm memory info.                                                                                                                                                                        
 perfcounter  Display the perf counter information.                                                                                                                                                           
 ognl         Execute ognl expression.                                                                                                                                                                        
 mc           Memory compiler, compiles java files into bytecode and class files in memory.                                                                                                                   
 redefine     Redefine classes. @see Instrumentation#redefineClasses(ClassDefinition...)                                                                                                                      
 retransform  Retransform classes. @see Instrumentation#retransformClasses(Class...)                                                                                                                          
 dashboard    Overview of target jvm's thread, memory, gc, vm, tomcat info.                                                                                                                                   
 dump         Dump class byte array from JVM                                                                                                                                                                  
 heapdump     Heap dump                                                                                                                                                                                       
 options      View and change various Arthas options                                                                                                                                                          
 cls          Clear the screen                                                                                                                                                                                
 reset        Reset all the enhanced classes                                                                                                                                                                  
 version      Display Arthas version                                                                                                                                                                          
 session      Display current session information                                                                                                                                                             
 sysprop      Display and change the system properties.                                                                                                                                                       
 sysenv       Display the system env.                                           

输入dashboard,按回车/enter,会展示当前进程的信息,按ctrl+c可以中断执行。

$ dashboard
ID     NAME                   GROUP          PRIORI STATE  %CPU    TIME   INTERRU DAEMON
17     pool-2-thread-1        system         5      WAITIN 67      0:0    false   false
27     Timer-for-arthas-dashb system         10     RUNNAB 32      0:0    false   true
11     AsyncAppender-Worker-a system         9      WAITIN 0       0:0    false   true
9      Attach Listener        system         9      RUNNAB 0       0:0    false   true
3      Finalizer              system         8      WAITIN 0       0:0    false   true
2      Reference Handler      system         10     WAITIN 0       0:0    false   true
4      Signal Dispatcher      system         9      RUNNAB 0       0:0    false   true
26     as-command-execute-dae system         10     TIMED_ 0       0:0    false   true
13     job-timeout            system         9      TIMED_ 0       0:0    false   true
1      main                   main           5      TIMED_ 0       0:0    false   false
14     nioEventLoopGroup-2-1  system         10     RUNNAB 0       0:0    false   false
18     nioEventLoopGroup-2-2  system         10     RUNNAB 0       0:0    false   false
23     nioEventLoopGroup-2-3  system         10     RUNNAB 0       0:0    false   false
15     nioEventLoopGroup-3-1  system         10     RUNNAB 0       0:0    false   false
Memory             used   total max    usage GC
heap               32M    155M  1820M  1.77% gc.ps_scavenge.count  4
ps_eden_space      14M    65M   672M   2.21% gc.ps_scavenge.time(m 166
ps_survivor_space  4M     5M    5M           s)
ps_old_gen         12M    85M   1365M  0.91% gc.ps_marksweep.count 0
nonheap            20M    23M   -1           gc.ps_marksweep.time( 0
code_cache         3M     5M    240M   1.32% ms)
Runtime
os.name                Mac OS X
os.version             10.13.4
java.version           1.8.0_162
java.home              /Library/Java/JavaVir
                       tualMachines/jdk1.8.0
                       _162.jdk/Contents/Hom
                       e/jre

#4. 通过 thread 命令来获取到math-game进程的 Main Class

thread 1会打印线程 ID 1 的栈,通常是 main 函数的线程。

$ thread 1 | grep 'main('
    at demo.MathGame.main(MathGame.java:17)

#5. 通过 jad 来反编译 Main Class

$ jad demo.MathGame
​
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 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 primeFactors) {
        StringBuffer sb = new StringBuffer("" + number + "=");
        Iterator 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 primeFactors(int number) {
        if (number < 2) {
            ++this.illegalArgumentCount;
            throw new IllegalArgumentException("number is: " + number + ", need >= 2");
        }
        ArrayList result = new ArrayList();
        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.

#6. watch

通过watch命令来查看demo.MathGame#primeFactors函数的返回值:

# ai-search-platform使用示例
# 
$ watch demo.MathGame primeFactors returnObj
Press Ctrl+C to abort.
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],
]

更多的功能可以查看进阶使用。

#7. 退出 arthas

如果只是退出当前的连接,可以用quit或者exit命令。Attach 到目标进程上的 arthas 还会继续运行,端口会保持开放,下次连接时可以直接连接上。

如果想完全退出 arthas,可以执行stop命令。

二.安装与卸载

可以直接通过rpm的方式进行安装:

sudo rpm -i arthas*.rpm

卸载通过直接删除文件的方式

  • 在 Linux/Unix/Mac 平台

    删除下面文件:

    rm -rf ~/.arthas/
    rm -rf ~/logs/arthas
  • Windows 平台直接删除 user home 下面的.arthaslogs/arthas目录

三 进阶使用

通过web console来直接访问(默认端口8563),由于k8s容器中对外暴露端口被严格限制,只能在本机进行访问。如果你的服务部署在ecs服务器上,则可以直接通过web浏览器的方式来进行访问

1. 使用&在后台执行任务

比如希望执行后台执行 trace 命令,那么调用下面命令

trace Test t &

这时命令在后台执行,可以在 console 中继续执行其他命令。

2. 通过 jobs 查看任务

如果希望查看当前有哪些 arthas 任务在执行,可以执行 jobs 命令,执行结果如下

$ jobs
[10]*
       Stopped           watch com.taobao.container.Test test "params[0].{? #this.name == null }" -x 2
       execution count : 19
       start time      : Fri Sep 22 09:59:55 CST 2017
       timeout date    : Sat Sep 23 09:59:55 CST 2017
       session         : 3648e874-5e69-473f-9eed-7f89660b079b (current)

可以看到目前有一个后台任务在执行。

  • job id 是 10, * 表示此 job 是当前 session 创建

  • 状态是 Stopped

  • execution count 是执行次数,从启动开始已经执行了 19 次

  • timeout date 是超时的时间,到这个时间,任务将会自动超时退出

3. 任务暂停和取消

当任务正在前台执行,比如直接调用命令trace Test t或者调用后台执行命令trace Test t &后又通过fg命令将任务转到前台。这时 console 中无法继续执行命令,但是可以接收并处理以下事件:

  • ‘ctrl + z’:将任务暂停。通过jbos查看任务状态将会变为 Stopped,通过bg 或者fg 可让任务重新开始执行

  • ‘ctrl + c’:停止任务

  • ‘ctrl + d’:按照 linux 语义应当是退出终端,目前 arthas 中是空实现,不处理

4. 任务输出重定向

可通过>或者>>将任务输出结果输出到指定的文件中,可以和&一起使用,实现 arthas 命令的后台异步任务。比如:

$ trace Test t >> test.out &

这时 trace 命令会在后台执行,并且把结果输出到应用工作目录下面的test.out文件。可继续执行其他命令。并可查看文件中的命令执行结果。可以执行pwd命令查看当前应用的工作目录

$ cat test.out

四 命令使用详解

1.查看类的静态属性值:

getstatic class_name field_name

示例

[arthas@7]$ getstatic com.moka.search.api.core.utils.Constants TYPE_DELETE
field: TYPE_DELETE
@String[1]
Affect(row-cnt:1) cost in 13 ms.
[arthas@7]$ 

示例对应的java代码

public class Constants {
​
​
    public static final String TYPE_DELETE = "1";
    public static final String TYPE_SAVE_OR_UPDATE = "0";
    }

2.查看类的类加载器

查看指定类的加载器

sc -d 对应类 

Eg:

[arthas@7]$ sc -d  com.moka.search.api.core.utils.Constants
 class-info        com.moka.search.api.core.utils.Constants                                                                                                                                                   
 code-source       file:/java_app.jar!/BOOT-INF/classes!/                                                                                                                                                     
 name              com.moka.search.api.core.utils.Constants                                                                                                                                                   
 isInterface       false                                                                                                                                                                                      
 isAnnotation      false                                                                                                                                                                                      
 isEnum            false                                                                                                                                                                                      
 isAnonymousClass  false                                                                                                                                                                                      
 isArray           false                                                                                                                                                                                      
 isLocalClass      false                                                                                                                                                                                      
 isMemberClass     false                                                                                                                                                                                      
 isPrimitive       false                                                                                                                                                                                      
 isSynthetic       false                                                                                                                                                                                      
 simple-name       Constants                                                                                                                                                                                  
 modifier          public                                                                                                                                                                                     
 annotation                                                                                                                                                                                                   
 interfaces                                                                                                                                                                                                   
 super-class       +-java.lang.Object                                                                                                                                                                         
 class-loader      +-org.springframework.boot.loader.LaunchedURLClassLoader@1d56ce6a                                                                                                                          
                     +-sun.misc.Launcher$AppClassLoader@33909752                                                                                                                                              
                       +-sun.misc.Launcher$ExtClassLoader@762c01c1      

复习一下类加载器:

什么是类加载器,类加载器有哪些?
​
实现通过类的全限定名获取该类的二进制字节流的代码块叫做类加载器。
​
主要有一下四种类加载器:
​
1.  启动类加载器(Bootstrap ClassLoader)用来加载java核心类库,无法被java程序直接引用。
2.  扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
3.  系统类加载器(system class loader,也称为 AppClassLoader):它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader()来获取它。
4.  用户自定义类加载器,通过继承 java.lang.ClassLoader类的方式实现。
​

自定义类加载器可以动态加载来自于网络、磁盘、数据库等来源的class类二进制文件以下为一个自定义类

ublic class MyClassLoader extends ClassLoader {
    private String classPath;
    public MyClassLoader(String classPath) {
        this.classPath = classPath;
    }
    @Override
    protected Class findClass(String name) throws ClassNotFoundException {
        byte[] classData = getClassData(name);
        if (classData == null) {
            throw new ClassNotFoundException();
        } else {
            return defineClass(name, classData, 0, classData.length);
        }
    }
    private byte[] getClassData(String name) {
        // 从指定路径中读取class文件
        // ...
    }
}

自定义类加载器作用:

自定义类加载器的作用主要有以下几个方面:

  1. 实现类隔离:自定义类加载器可以实现不同的类加载器加载不同路径下的类文件,从而实现类隔离。这在一些需要动态加载插件、使用不同版本的库等场景下非常有用。

  2. 加载加密的类:自定义类加载器可以在加载类的过程中进行解密,从而保护类的安全性。

  3. 修改字节码:自定义类加载器可以在加载类的过程中对字节码进行修改,从而实现一些特殊的需求,如AOP框架等。

  4. 热部署:自定义类加载器可以支持类的热部署,即在应用程序运行过程中,通过修改类文件并重新加载,实现动态更新应用程序的功能。 总之,自定义类加载器可以实现更加灵活、安全、高效的类加载方式,同时也为一些特殊需求提供了解决方案。

3.查看指定的classloader加载了哪些jar

使用classloader -t 以树的形式展示类加载器

[arthas@7]$ classloader -t
+-BootstrapClassLoader                                                                                                                                                                                        
+-sun.misc.Launcher$ExtClassLoader@762c01c1                                                                                                                                                                   
  +-com.taobao.arthas.agent.ArthasClassloader@14a26eaf                                                                                                                                                        
  +-sun.misc.Launcher$AppClassLoader@33909752                                                                                                                                                                 
    +-org.springframework.boot.loader.LaunchedURLClassLoader@1d56ce6a                                                                                                                                         
      +-com.alibaba.fastjson2.util.DynamicClassLoader@f231925    

由于我们的ai-search-platform为spring项目,我们查看

org.springframework.boot.loader.LaunchedURLClassLoader@1d56ce6a

使用命令: classloader -c classloader对应的hash值

arthas@7]$ classloader -c 1d56ce6a
jar:file:/java_app.jar!/BOOT-INF/classes!/                                                                                                                                                                    
jar:file:/java_app.jar!/BOOT-INF/lib/ratelimiter-2.0.8-RELEASE.jar!/                                                                                                                                          
jar:file:/java_app.jar!/BOOT-INF/lib/spring-boot-starter-2.2.0.RELEASE.jar!/                                                                                                                                  
jar:file:/java_app.jar!/BOOT-INF/lib/spring-boot-2.2.0.RELEASE.jar!/                                                                                                                                          
jar:file:/java_app.jar!/BOOT-INF/lib/spring-boot-autoconfigure-2.2.0.RELEASE.jar!/                                                                                                                            
jar:file:/java_app.jar!/BOOT-INF/lib/spring-boot-starter-logging-2.2.0.RELEASE.jar!/                                                                                                                          
jar:file:/java_app.jar!/BOOT-INF/lib/logback-classic-1.2.3.jar!/                                                                                                                                              
jar:file:/java_app.jar!/BOOT-INF/lib/logback-core-1.2.3.jar!/                                                                                                                                                 
jar:file:/java_app.jar!/BOOT-INF/lib/log4j-to-slf4j-2.12.1.jar!/                                                                                                                                              
jar:file:/java_app.jar!/BOOT-INF/lib/jul-to-slf4j-1.7.28.jar!/                                                                                                                                                
jar:file:/java_app.jar!/BOOT-INF/lib/jakarta.annotation-api-1.3.5.jar!/                                                                                                                                       
jar:file:/java_app.jar!/BOOT-INF/lib/commons-pool2-2.7.0.jar!/                                                                                                                                                
jar:file:/java_app.jar!/BOOT-INF/lib/spring-boot-starter-aop-2.2.0.RELEASE.jar!/         

4.thread

thread命令可以查看当前占用cpu最多的县城,并且打印对应的堆栈信息。

参数说明

参数名称 参数说明
id 线程 id
[n:] 指定最忙的前 N 个线程并打印堆栈
[b] 找出当前阻塞其他线程的线程
[i ] 指定 cpu 使用率统计的采样间隔,单位为毫秒,默认值为 200
[--all] 显示所有匹配的线程

cpu-使用率是如何统计出来的

这里的 cpu 使用率与 linux 命令top -H -p 的线程%CPU类似,一段采样间隔时间内,当前 JVM 里各个线程的增量 cpu 时间与采样间隔时间的比例。

工作原理说明:

  • 首先第一次采样,获取所有线程的 CPU 时间(调用的是java.lang.management.ThreadMXBean#getThreadCpuTime()sun.management.HotspotThreadMBean.getInternalThreadCpuTimes()接口)

  • 然后睡眠等待一个间隔时间(默认为 200ms,可以通过-i指定间隔时间)

  • 再次第二次采样,获取所有线程的 CPU 时间,对比两次采样数据,计算出每个线程的增量 CPU 时间

  • 线程 CPU 使用率 = 线程增量 CPU 时间 / 采样间隔时间 * 100%

支持一键展示当前最忙的前 N 个线程并打印堆栈:

$ thread -n 3
"C1 CompilerThread0" [Internal] cpuUsage=1.63% deltaTime=3ms time=1170ms
​
​
"arthas-command-execute" Id=23 cpuUsage=0.11% deltaTime=0ms time=401ms RUNNABLE
    at [email protected]/sun.management.ThreadImpl.dumpThreads0(Native Method)
    at [email protected]/sun.management.ThreadImpl.getThreadInfo(ThreadImpl.java:466)
    at com.taobao.arthas.core.command.monitor200.ThreadCommand.processTopBusyThreads(ThreadCommand.java:199)
    at com.taobao.arthas.core.command.monitor200.ThreadCommand.process(ThreadCommand.java:122)
    at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.process(AnnotatedCommandImpl.java:82)
    at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.access$100(AnnotatedCommandImpl.java:18)
    at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:111)
    at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:108)
    at com.taobao.arthas.core.shell.system.impl.ProcessImpl$CommandProcessTask.run(ProcessImpl.java:385)
    at [email protected]/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
    at [email protected]/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at [email protected]/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
    at [email protected]/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at [email protected]/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at [email protected]/java.lang.Thread.run(Thread.java:834)
​
​
"VM Periodic Task Thread" [Internal] cpuUsage=0.07% deltaTime=0ms time=584ms
  • 没有线程 ID,包含[Internal]表示为 JVM 内部线程,参考dashboard命令的介绍。

  • cpuUsage为采样间隔时间内线程的 CPU 使用率,与dashboard命令的数据一致。

  • deltaTime为采样间隔时间内线程的增量 CPU 时间,小于 1ms 时被取整显示为 0ms。

  • time 线程运行总 CPU 时间。

5.heapdump

heapdump类似于java dump jvm的堆栈信息。只 dump live 对象

[arthas@58205]$ heapdump --live /tmp/dump.hprof
Dumping heap to /tmp/dump.hprof ...
Heap dump file created

6.jvm相关命令

memory命令查看各个分区对应占用的内存大小和比例

$ memory
Memory                                                                                    used                         total                         max                           usage                         
heap                                                                                      1066M                        2880M                         2880M                         37.03%                        
par_eden_space                                                                            998M                         1152M                         1152M                         86.67%                        
par_survivor_space                                                                        68M                          192M                          192M                          35.47%                        
cms_old_gen                                                                               0K                           1572864K                      1572864K                      0.00%                         
nonheap                                                                                   154M                         625M                          1016M                         15.18%                        
code_cache                                                                                46M                          512M                          512M                          9.14%                         
metaspace                                                                                 95M                          100M                          256M                          37.30%                        
compressed_class_space                                                                    11M                          13M                           248M                          4.83%                         
direct                                                                                    5M                           5M                            -                             100.00%                       
mapped                                                                                    0K                           0K                            -                             0.00%

7.查看jvm相关参数:

jvm

MACHINE-NAME                                                7@ai-search-platform-76f7775cfd-tr4j4                                                                                                               
 JVM-START-TIME                                              2023-05-17 14:29:57                                                                                                                                 
 MANAGEMENT-SPEC-VERSION                                     1.2                                                                                                                                                 
 SPEC-NAME                                                   Java Virtual Machine Specification                                                                                                                  
 SPEC-VENDOR                                                 Oracle Corporation                                                                                                                                  
 SPEC-VERSION                                                1.8                                                                                                                                                 
 VM-NAME                                                     Java HotSpot(TM) 64-Bit Server VM                                                                                                                   
 VM-VENDOR                                                   Oracle Corporation                                                                                                                                  
 VM-VERSION                                                  25.201-b09                                                                                                                                          
 INPUT-ARGUMENTS                                             -Xmx3072m                                                                                                                                           
                                                             -Xms3072m                                                                                                                                           
                                                             -XX:-OmitStackTraceInFastThrow                                                                                                                      
                                                             -XX:+PrintGC                                                                                                                                        
                                                             -XX:+PrintGCDateStamps                                                                                                                              
                                                             -Xloggc:/data/logs/ai-search-platform/gc-%t.log                                                                                                     
                                                             -XX:HeapDumpPath=/data/logs/ai-search-platform/java.hprof                                                                                           
                                                             -XX:-UseAdaptiveSizePolicy                                                                                                                          
                                                             -XX:+PrintAdaptiveSizePolicy                                                                                                                        
                                                             -XX:+PrintGCDetails                                                                                                                                 
                                                             -XX:+PrintGCTimeStamps                                                                                                                              
                                                             -XX:+UseGCLogFileRotation                                                                                                                           
                                                             -XX:MetaspaceSize=128M                                                                                                                              
                                                             -XX:MaxMetaspaceSize=256m                                                                                                                           
                                                             -XX:NumberOfGCLogFiles=5                                                                                                                            
                                                             -XX:GCLogFileSize=128m                                                                                                                              
                                                             -XX:+HeapDumpOnOutOfMemoryError                                                                                                                     
                                                             -XX:SurvivorRatio=6                                                                                                                                 
                                                             -XX:NewRatio=1                                                                                                                                      
                                                             -XX:ReservedCodeCacheSize=512m                                                                                                                      
                                                             -XX:InitialCodeCacheSize=512m                                                                                                                       
                                                             -XX:CMSInitiatingOccupancyFraction=70                                                                                                               
                                                             -XX:+UseCMSInitiatingOccupancyOnly                                                                                                                  
                                                             -XX:+UseCMSCompactAtFullCollection                                                                                                                  
                                                             -XX:CMSFullGCsBeforeCompaction=0                                                                                                                    
                                                             -XX:+CMSParallelInitialMarkEnabled                                                                                                                  
                                                             -XX:PrintCMSStatistics=1                                                                                                                            
                                                             -XX:+CMSScavengeBeforeRemark                                                                                                                        
                                                             -XX:+UseConcMarkSweepGC                                                                                                                             
                                                             -XX:+PrintGCApplicationStoppedTime                                                                                                                  
                                                             -Dcluster=staging-1                                                                                                                                 
                                                             -Dcloud=ali        

五 线上实操案例

1.tagram项目中出现了线上导入数据太慢,要求进行性能优化。

如果不使用arthas,需要修改代码,将各个步骤的耗时通过日志打印出来,然后重新发布至线上,不仅耗时费力,而且对代码产生侵入性。而使用arthas则而使用arthas trace命令,可以在线上直接定位指定方法的各个步骤执行的耗时。从而定位问题是获取候选人标签速度过慢导致,通过优化该接口解决问题 :

2.使用arthas模拟排查堆内存溢出问题
[arthas@58205]$ heapdump --live /tmp/dump.hprof
Dumping heap to /tmp/dump.hprof ...
Heap dump file created

将堆文件dump后,可在k8s管理页面中下载:

下载完成后,可以用jprofile工具将其打开:

看到这里,大对象的类型,内容可以确定。如果仅靠类型、内容无法确认大对象的产生原因的话,我们还可以继续通过调用链路来进行分析:

右击选择selected objects

在biggest objects中选择对象,右键show grah

查看对象调用链路:

可以看到对象引用链路,从而确认对象的生成原因。一般对象太大导致内存溢出,都是由于内存没有及时释放导致:

3.使用火焰图协助排查线上es升级后,CPU负载变高问题

$profiler start
#经过一段时间后,获取已经采样的数量
$ profiler getSamples
150
$profiler stop --format svg --file /Users/leixingbang/Downloads/profile.html

将鼠标点上具体的矩形方块后,能够看到具体执行的类看,以及其对cpu的占用情况。

一般来说,一家公司对es集群只维护一个大版本,便于快速定位和排查问题(eg.6.x版本只维护6.6.2版本,7.x版本只维护7.17版本,8.x版本只维护8.5版本)。

1.对于7版本(大版本)集群希望只维护一个版本,最终选择7.17,对同大版本的7.5版本集群进行升级

2.根据官方描述,_id放到堆外性能损失非常小可以忽略,且对BKD进行了优化

3.升级完成,一段时间之后,收到用户报障

发现CPU占用率提高,并且发现查询平均延迟增大,需要定位问题产生原因。

由于已经确认是由于CPU负载升高导致,我们可以使用es中自带的命令,但是由于缺乏采样,需要持续观察,经过观察一段时间后,发现是由于时不时出现的update相关函数,导致消耗的CPU过多。

GET /_nodes/hot_threads

为了进一步定位问题,我们使用arthas进行采样,查看其火焰图:

从图中可以看到Bulk请求执行过程中的getDocID方法占有大量CPU。

集群写多读少,使用的是niofs( 是一种文件存储类型,它使用 Java NIO(New I/O)库来读写磁盘上的文件)。可知,7.5版本的FST是在堆外,但是_id字段是在堆内。升级到7.17版本后,默认FST在堆外,该字段也放到了堆外(官方版本应该是7.9就开始放到堆外了,具体为什么要放到堆外内存详细原因参考:https://www.cnblogs.com/muzhongjiang/p/13930195.html)。fst、bkd放到堆外内存的原因是,受限于寻址空间,堆内存的最大32G(一个指针占用8字节),放到堆外内存,由于堆外内存

数据放到堆外,其实也就是文件放到磁盘,读一次之后放到pagecache。

这样也就可以解释了,在upsert类请求多的时候会频繁查询docId,此时如果_id字段没有进入pageCache或者被踢出pageCache,那么就会出现响应慢,并且CPU高、IO高的情况。 将7.17版本的bkd、fst改为堆内存存储,elasticsearch中添加以下设置(详细参考:FST Off Heap 内存优化_indices.segment_memory.off_heap.enable_weixin_42414008的博客-CSDN博客):

curl -H "Content-Type:application/json" -XPUT http://localhost:9200/_cluster/settings -d '{
  "persistent" : {
    "indices.segment_memory.off_heap.enable" : false
   }
}'

因此:update、upsert、get等请求如果十分频繁,_id使用offheap将不会是个好的选择,除非给足够的堆外内存,并且保证尽可能常驻内存。.不同的业务场景下使用ES的同一版本也会有不一样的效果。对于日志场景的话,由于数据只有index请求,没有update是十分合适的,但是对于搜索的业务场景,就不建议这么设置了。

你可能感兴趣的:(java,jvm,大数据)