美文网首页开发技巧大后端
Arthas排查命令实时操作程序代码的总结分享

Arthas排查命令实时操作程序代码的总结分享

作者: 凯凯雄雄 | 来源:发表于2021-06-15 20:57 被阅读0次

    日常开发中,总会遇到一些莫名其妙的问题,这些问题在服务器上出现的概率可能很低,本地环境难以复现,这个时候阿里开源的Arthas就派上用场了,可以基于实时运行的应用进行排查,不必每次打日志,重启等掉头发的操作;

    以下是一些个人觉得比较常用的场景及命令分享给大家。

    @[toc]

    1. 调用静态方法

    比如调用Hutool的SpringUtil的getActiveProfile方法来查看当前环境配置

    ognl -x 3 @cn.hutool.extra.spring.SpringUtil@getActiveProfile()
    

    如果出现类找不到等等异常的,请按照以下步骤:

    查找类的唯一标记HASH码

    # 先查看类是否已经加载完毕
    sc -d cn.hutool.extra.spring.SpringUtil
    # 然后找到  classLoaderHash   1be6f5c3  这个值
    ognl -c 1be6f5c3  @cn.hutool.extra.spring.SpringUtil@getActiveProfile()
    # 得到结果 : @String[dev]
    

    2. 获取Spring中IOC容器,并且为所欲为

    我想知道SpringBoot中的yml中的spring.profiles.active属性配置

    # 查找到对应的类的唯一标记HASH码
    ognl -c 1be6f5c3 '#springContext=@cn.hutool.extra.spring.SpringUtil@applicationContext,#springContext.getEnvironment().getProperty("spring.profiles.active")'
    

    #springContext=@cn.hutool.extra.spring.SpringUtil@applicationContext,#springContext.getEnvironment().getProperty("spring.profiles.active")
    名词释义
    cn.hutool.extra.spring.SpringUtil: 类的全路径,将工厂构建成一个静态工具类。
    applicationContext: 表示类的属性
    springContext : 表示定义的新变量,在这里面的意义表示Spring的工厂的变量
    springContext.getEnvironment().getProperty("spring.profiles.active") : 表示调用了Spring工厂中的getEnvironment方法;

    如果你对ognl命令不熟悉,那么可以安装一个IDEA插件Arthas Idea Plugin,通过这个插件可以选择方法然后生成特定的命令直接在命令行中运行

    3. 服务加载包不一致的情况

    由于现在的服务都是需要依赖一些第三方的jar包,但是第三方的jar会带来一些其他的依赖,特定的版本号不一致都会导致出现问题。

    之前还遇到过window开发运行是好的,但是放到linux服务器上启动就不行。

    这个时候我们希望查看服务器的某个类到底是出自哪个版本的jar包,
    这个时候sc命令就非常好的解决了这个问题

    [arthas@1794]$ sc -d com.dianping.cat.message.io.DefaultMessageQueue
     class-info        com.dianping.cat.message.io.DefaultMessageQueue                                                                                                                                               
     code-source       /data/tomcat/tomcat-cat/webapps/cat/WEB-INF/lib/cat-client-3.0.0.jar                                                                                                                          
     name              com.dianping.cat.message.io.DefaultMessageQueue                                                                                                                                               
     isInterface       false                                                                                                                                                                                         
     isAnnotation      false                                                                                                                                                                                         
     isEnum            false                                                                                                                                                                                         
     isAnonymousClass  false                                                                                                                                                                                         
     isArray           false                                                                                                                                                                                         
     isLocalClass      false                                                                                                                                                                                         
     isMemberClass     false                                                                                                                                                                                         
     isPrimitive       false                                                                                                                                                                                         
     isSynthetic       false                                                                                                                                                                                         
     simple-name       DefaultMessageQueue                                                                                                                                                                           
     modifier          public                                                                                                                                                                                        
     annotation                                                                                                                                                                                                      
     interfaces        com.dianping.cat.message.spi.MessageQueue                                                                                                                                                     
     super-class       +-java.lang.Object                                                                                                                                                                            
     class-loader      +-ParallelWebappClassLoader                                                                                                                                                                   
                           context: cat                                                                                                                                                                              
                           delegate: false                                                                                                                                                                           
                         ----------> Parent Classloader:                                                                                                                                                             
                         java.net.URLClassLoader@63961c42                                                                                                                                                            
                                                                                                                                                                                                                     
                         +-java.net.URLClassLoader@63961c42                                                                                                                                                          
                           +-sun.misc.Launcher$AppClassLoader@5c647e05                                                                                                                                               
                             +-sun.misc.Launcher$ExtClassLoader@3a03464                                                                                                                                              
     classLoaderHash   26d4a70e                                                                                                                                                                                      
    
    Affect(row-cnt:1) cost in 60 ms.
    

    参考

    4. 反编译服务器上的代码

    你是否有遇到过服务器发版,可能在集群情况下,一个服务要经过很多台服务器重启,然后某台服务可能没发好的情况,又没有足够的证据是发版引起的?

    这个时候可以通过jad命令去查看当前应用进程中的特定代码:

    jad 你想查看的类

    [arthas@12870]$ jad com.xxx.xxx.xxx.xxx.AuthCacheUtil 
    
    ClassLoader:                                                                                                                                                                                                     
    +-org.springframework.boot.loader.LaunchedURLClassLoader@5674cd4d                                                                                                                                                
      +-sun.misc.Launcher$AppClassLoader@70dea4e                                                                                                                                                                     
        +-sun.misc.Launcher$ExtClassLoader@7516e4e5                                                                                                                                                                  
    
    Location:                                                                                                                                                                                                        
    file:/elab/spring-boot/elab-marketing-analyse-1.0.0.jar!/BOOT-INF/classes!/                    
                                                                                                                      
           package com.elab.marketing.analyse.cache;
           
           @Component
           @Order(value=1)
           public class AuthCacheUtil
           implements CommandLineRunner {
               private static final Logger log = LoggerFactory.getLogger(AuthCacheUtil.class);
               private static CacheUtil authCache;
           
               public static void putValue(String key, Object value) {
    /*37*/         authCache.putValue(key, value);
               }
           
               public void run(String ... strings) throws Exception {
    /*28*/         log.info("================== AuthCache is ready! ==================");
                   authCache = new CacheUtil((long)UserAuthCache.USER_AUTH_INFO_SIZE.intValue(), (long)UserAuthCache.USER_AUTH_INFO_TIME.intValue());
               }
           
               public static Object getValue(String key, Callable callable) throws Exception {
    /*33*/         return authCache.getValue(key, callable);
               }
           }
    
    Affect(row-cnt:1) cost in 987 ms.
    

    5. 排查特定日志的打印链路栈

    比如随着系统越来越大,某些日志老是打印一些乱七八糟的值,而且打印的非常频繁,和预期的日志内容不一致,需要排查上游是如何产生的?

    比如我们可以在测试环境,修改特定的类,比如logback的实现类,如果你不清楚的话,重写JDK的StringBuilder的toString()方法也行,因为java中的字符串拼接都是通过StringBuilder来完成的;
    比如修改成:

        @Override
        public String toString() {
            // Create a copy, don't share the array
            String result = new String(value, 0, count);
            if(result.contains("No credential found")) {
                System.err.println(result);
                 // 如果你有链路日志系统的话,这里可以考虑打印日志编号,
                 // 可以让参数看的更详细
                new Throwable().printStackTrace();
            }
            return result;
        }
    

    然后重新编译修改过的StringBuilder

    javac StringBuilder.java
    

    启动应用后,在奇怪日志输出之前,先使用arthas attach应用,再redefine StringBuilder:

    $ redefine  /tmp/StringBuilder.class
    redefine success, size: 1
    

    然后默默的等待报错查看日志即可看到执行的线程栈;

    建议还是在测试环境或者其他环境执行即可,生产环境慎重;

    6. 谁调用了特定的方法?

    比如线上发生了大量Full GC ,造成的原因可能是触发了System.gc()这个时候你可能不清楚到底是哪里调用过这个玩意?

    第一步,由于java.lang.System是JDK自带的类,Arthas默认关闭了对JDK类的自带类的增强,需要通过options命令打开。

    $ options unsafe true
     NAME    BEFORE-VALUE  AFTER-VALUE
    -----------------------------------
     unsafe  false         true
    

    第二步,使用stack命令,观察谁调用了java.lang.System#gc

    $ stack java.lang.System gc
    Press Ctrl+C to abort.
    Affect(class-cnt:1 , method-cnt:1) cost in 81 ms.
    stack java.lang.System gc
    // 等待结果反馈即可
    

    具体参考

    7. 某个方法时快时慢?

    相信你可能遇到过这样的问题,某个方法在本地执行的时候特别快,但是一到服务器上,有时候快,有时候慢的很,导致的原因可能有很多:入参,出参,特定的逻辑等等。你想看看慢的方法执行的方法栈是什么样子。

    trace --skipJDKMethod false demo.MathGame run
    Press Q or Ctrl+C to abort.
    Affect(class-cnt:1 , method-cnt:1) cost in 60 ms.
    `---ts=2019-12-04 00:44:41;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@3d4eac69
        `---[1.357742ms] demo.MathGame:run()
            +---[0.028624ms] java.util.Random:nextInt() #23
            +---[0.045534ms] demo.MathGame:primeFactors() #24 [throws Exception]
            +---[0.005372ms] java.lang.StringBuilder:<init>() #28
            +---[0.012257ms] java.lang.Integer:valueOf() #28
            +---[0.234537ms] java.lang.String:format() #28
            +---[min=0.004539ms,max=0.005778ms,total=0.010317ms,count=2] java.lang.StringBuilder:append() #28
            +---[0.013777ms] java.lang.Exception:getMessage() #28
            +---[0.004935ms] java.lang.StringBuilder:toString() #28
            `---[0.06941ms] java.io.PrintStream:println() #28
    

    --skipJDKMethod false 代表展示JDK层面的方法栈

    具体参考

    8. 刚上线某个方法,它的具体调用情况是怎么样的?

    比如刚上线一个秒杀活动,你不知道这一时刻到底调用的线程有多少?能不能抗住?线程池够用吗?
    monitor 命令可以很好的监控,实时情况下的方法调用情况.

    $ monitor -c 5 demo.MathGame primeFactors
    Press Ctrl+C to abort.
    Affect(class-cnt:1 , method-cnt:1) cost in 94 ms.
     timestamp            class          method        total  success  fail  avg-rt(ms)  fail-rate
    -----------------------------------------------------------------------------------------------
     2018-12-03 19:06:38  demo.MathGame  primeFactors  5      1        4     1.15        80.00%
     
     timestamp            class          method        total  success  fail  avg-rt(ms)  fail-rate
    -----------------------------------------------------------------------------------------------
     2018-12-03 19:06:43  demo.MathGame  primeFactors  5      3        2     42.29       40.00%
     
     timestamp            class          method        total  success  fail  avg-rt(ms)  fail-rate
    -----------------------------------------------------------------------------------------------
     2018-12-03 19:06:48  demo.MathGame  primeFactors  5      3        2     67.92       40.00%
     
     timestamp            class          method        total  success  fail  avg-rt(ms)  fail-rate
    -----------------------------------------------------------------------------------------------
     2018-12-03 19:06:53  demo.MathGame  primeFactors  5      2        3     0.25        60.00%
     
     timestamp            class          method        total  success  fail  avg-rt(ms)  fail-rate
    -----------------------------------------------------------------------------------------------
     2018-12-03 19:06:58  demo.MathGame  primeFactors  1      1        0     0.45        0.00%
     
     timestamp            class          method        total  success  fail  avg-rt(ms)  fail-rate
    -----------------------------------------------------------------------------------------------
     2018-12-03 19:07:03  demo.MathGame  primeFactors  2      2        0     3182.72     0.00%
    

    具体参考

    相关文章

      网友评论

        本文标题:Arthas排查命令实时操作程序代码的总结分享

        本文链接:https://www.haomeiwen.com/subject/ooktyltx.html