Arthas 实践——生产环境排查 CPU 飚高问题

原创
2020/11/30 18:06
阅读数 3K

作者 | 李昊(可以养肥)

【Arthas 官方社区正在举行征文活动,参加即有奖品拿~点击投稿

生产环境 CPU 告警:

 13:40 收到我们的生产环境服务器绿版 CUP 超负载告警通知。

1.png

此时心里只有一个想法,重启大法好,马上登录服务器,执行 top 发现进程 30247 和 28337 占用 CPU 为 200 多和100 多基本占用了 4 核的 3 核,整个过程大概用时 30 秒,维护群依然很平静,运营的电话也没打过来,这时候我断定,这次问题应该影响面很小,用户可能也暂时没有发现,好吧,还有时间做排查。

2.png

Arthas排查过程:

  • 开启 Arthas 工具找到对应的 30247 运单模块和 28337 支付模块,选择运单模块进入:
java -jar arthas-boot.jar

3.png

  • 执行 dashboard 命令,线程 35 和 12042 不正常 CUP 占用 49%:
dashboard

4.png

  • 执行 thread 35  thread 12042 定位代码行:
thread 35
thread 12042

5.png

  • 查看代码,业务需求为生成一个至少包含 2 个数字的随机字符串,我们使用的统一的工具类方法,该方法中先通过 UUID.randomUUID() 随机出一个 10 位的字符池,然后再从这个字符池中随机需要位数的字符串,如果随机出来的 10 位字符池中都是字母,则二次随机时候就会出现死循环,问题代码如下:
public static String getRandomStr(boolean numberFlag, int length) {
    String retStr = "";
    String strTable =
        numberFlag
            ? UUID.randomUUID().toString().replaceAll("-", "").substring(0, 10)
            : "1234567890abcdefghijkmnpqrstuvwxyz";
    int len = strTable.length();
    boolean bDone = true;
    do {
      retStr = "";
      int count = 0;
      for (int i = 0; i < length; i++) {
        double dblR = Math.random() * len;
        int intR = (int) Math.floor(dblR);
        char c = strTable.charAt(intR);
        if (('0' <= c) && (c <= '9')) {
          count++;
        }
        retStr += strTable.charAt(intR);
      }
      if (count >= 2) {
        bDone = false;
      }
    } while (bDone);
    return retStr;
  }
  • 线下模拟不到二万次 UUID.randomUUID() 前十位会出现一次全字母的情况。

6.png

  • 最终原因是死循环导致的 CPU 飚高,修复代码,增加是否都是字母的判断,第一次随机出来的 10 位字符池都是字母,则重新随机。

Arthas 常用命令:

安装

curl -O arthas.aliyun.com/arthas-boot…<br />java -jar arthas-boot.jar

基础命令

  • help——查看命令帮助信息
  • cat——打印文件内容,和 linux 里的 cat 命令类似
  • echo–打印参数,和 linux 里的 echo 命令类似
  • grep——匹配查找,和 linux 里的 grep 命令类似
  • tee——复制标准输入到标准输出和指定的文件,和 linux 里的 tee 命令类似
  • pwd——返回当前的工作目录,和 linux 命令类似
  • cls——清空当前屏幕区域
  • session——查看当前会话的信息
  • reset——重置增强类,将被 Arthas 增强过的类全部还原,Arthas 服务端关闭时会重置所有增强过的类
  • version——输出当前目标 Java 进程所加载的 Arthas 版本号
  • history——打印命令历史
  • quit——退出当前 Arthas 客户端,其他 Arthas 客户端不受影响
  • stop——关闭 Arthas 服务端,所有 Arthas 客户端全部退出
  • keymap——Arthas 快捷键列表及自定义快捷键

jvm相关

  • dashboard——当前系统的实时数据面板
  • thread——查看当前 JVM 的线程堆栈信息
  • jvm——查看当前 JVM 的信息
  • sysprop——查看和修改 JVM 的系统属性
  • sysenv——查看 JVM 的环境变量
  • vmoption——查看和修改 JVM 里诊断相关的 option
  • perfcounter——查看当前 JVM 的 Perf Counter 信息
  • logger——查看和修改 logger
  • getstatic——查看类的静态属性
  • ognl——执行 ognl 表达式
  • mbean——查看 Mbean 的信息
  • heapdump——dump java heap, 类似 jmap 命令的 heap dump 功能

class/classloader相关

  • sc——查看 JVM 已加载的类信息
  • sm——查看已加载类的方法信息
  • jad——反编译指定已加载类的源码
  • mc——内存编译器,内存编译 .java 文件为 .class 文件
  • redefine——加载外部的 .class 文件,redefine 到 JVM 里
  • dump——dump 已加载类的 byte code 到特定目录
  • classloader——查看 classloader 的继承树,urls,类加载信息,使用classloader 去 getResource

monitor/watch/trace相关

  • monitor 方法执行监控

monitor -c 5 demo.MathGame primeFactors

-c 5 未统计周期默认 120s

  • watch 能观察到的范围为:返回值、抛出异常、入参

watch demo.MathGame primeFactors “{params,target,returnObj}” -x 2 -b -s -n 2

-x 2 输出结果的属性遍历深度 -b 方法调用前 -s 方法返回后 -n 2 执行2次

watch demo.MathGame primeFactors “{params[0],throwExp}” -e -x 2

-e表示抛出异常时才触发

  • trace 方法内部调用路径,并输出方法路径上的每个节点上耗时

trace demo.MathGame run

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
0 评论
0 收藏
0
分享
返回顶部
顶部