文章浏览阅读628次,点赞14次,收藏14次,不靠谱。。

哎呀,写这个文章真的是头大。大家知道我平时写代码很随意的, 今天要写这个关于Arthas的东西,我也是查了好多资料,感觉脑子都要炸了。反正就是想跟大家聊聊, 如果线上那个Java程序突然就挂了或者CPU直接飙到100%了我们这些打工人该怎么办。是不是很慌?反正我是慌的。然后我就听说有个叫Arthas的东西,说是阿里巴巴开源的,能帮我们解决很多麻烦。我就去学了一下 现在来写写我的体会,写的不好大家别喷啊,反正我也没上过什么学,就是瞎写的,希望能帮到那些跟我一样笨的人吧。
:为什么我们要学Arthas?
说真的,做程序员最怕什么?最怕的就是线上出问题。对吧?我们在自己电脑上写代码,写个Hello World都能跑得飞快,一到线上那个环境,嘿,就各种报错。不是缺这个就是少那个, 准确地说... 反正就是一顿乱报。而且最烦的是线上环境是不能随便重启的,一重启可能就影响用户体验了老板还要骂人。这时候,我们该怎么办呢?难道只能干瞪眼看着CPU一直飙?
以前我们都是用JDK自带的那些工具,比如jstat、jmap、jstack什么的。但是说实话,那些命令真的很难记啊!而且用起来也不方便。有时候我想看个方法的参数是什么还得写一堆代码,还得重新编译部署。哎,想想都觉得累。然后那个Arthas就出来了据说是个神器。什么是神器呢?就是说它不用改代码,也不用重启程序,就能知道程序里到底发生了什么。听起来是不是很神奇?我觉得就是魔法。
那个所谓的“痛点”到底是什么?
我之前遇到过一个情况,真的是想哭。当时我们线上有个接口,响应速度特别慢,慢到用户都要骂娘了。我想查原因,但是又不知道怎么查。用浏览器看日志?日志太多了根本看不过来。用JDK工具?我又不会用。我就觉得特别无助。后来同事告诉我,你可以试试Arthas。我就试了一下好家伙,真的有用!一下子就看到是哪个方法在耗时间。所以说学这个Arthas真的是为了保命,为了不被老板骂,为了能早点下班去吃火锅,人间清醒。。
Arthas是个啥?怎么安装?
好了废话不多说我们来讲讲怎么安装这个Arthas。其实安装过程还挺简单的,就是有点繁琐。先说说你得有一个Java进程在跑,不然Arthas attach不上去。就像你想跟一个人说话,但他根本没在听,那也没用嘛,掉链子。。
下载那个jar包
官方推荐的方式是下载一个boot jar包。我就在命令行里敲了这么一行命令:,拖进度。
curl -O https://arthas.aliyun.com/arthas-boot.jar
然后呢?然后施行:
java -jar arthas-boot.jar
哎,这里我就出问题了。一开始我运行的时候,它说找不到Java命令。我就想,我明明装了JDK啊,怎么就找不到呢?后来我才知道,得把JDK的bin目录加到环境变量里。这个环境变量真的太坑了每次都要配置,烦死了。配置好了之后 再运行java -jar arthas-boot.jar,它就会自动帮你找正在运行的Java进程。它会列出一堆进程出来然后你输入数字,选择你要attach的那个进程。比如说输入1,就attach到第一个进程上。attach上去之后它就会显示一个命令行界面你就可以在里面输入命令了。那个界面看起来有点像Linux的终端,但是又不太一样,反正就是那个意思,闹乌龙。。
CPU飙高了怎么办?我的正则表达式惹的祸
哎,对! CPU飙高是线上问题里最常见的一种。CPU一飙高,整个服务器就卡住了。我想大家都有过这种经历吧?屏幕转圈圈,鼠标点不动,那种感觉真的绝望。这时候我们要用Arthas来定位是哪个线程把CPU吃掉了。
用thread命令看看谁在跑
最常用的命令就是`thread`。你直接在Arthas的命令行里输入`thread`,然后回车。它会显示所有正在运行的线程。你会看到一长串的线程ID、线程名称、优先级,还有线程的状态,来日方长。。
我之前就遇到过一次CPU飙高。我用`thread`命令一看,好家伙,有好多线程都是RUNNABLE状态。其中有一个线程叫“cpu demo thread”,占用CPU特别高。然后我一看它调用的栈,发现它在一个while循环里一直在做字符串处理。我看了一下代码,好家伙,是一个正则表达式的问题。
那个正则表达式到底写错了啥?
我当时的代码大概是这样的:
String str = .toString.replaceAll;
你看, 这个代码看起来没啥毛病啊,就是把连字符替换成空字符串。但是!问题就出在`replaceAll`这个方法上。如果这个字符串特别长,或者里面有很多连字符, 绝了... 它就会把CPU吃光。特别是如果你不小心写成了贪婪匹配,那CPU绝对会飙高。我当时就是不知道这个坑,写完部署上去,没过几分钟CPU就满了。
这家伙... 发现了问题之后我用Arthas的`watch`命令去看了那个方法的输入输出。哇, 输入是“aaaaaaaaaaaaaaaa”,输出还是“aaaaaaaaaaaaaaaa”,主要原因是它一直在匹配,一直不结束。后来我把代码改了把那个贪婪的匹配去掉,或者加了点限制,CPU就降下来了。所以说写正则表达式真的要小心,一不小心就坑了自己。
死锁了?Arthas也能看出来?
这玩意儿... 除了CPU飙高,还有一种情况也很麻烦,那就是死锁。死锁就是两个线程互相等着对方释放锁,谁也不让谁,后来啊就是两个线程都卡住了程序就跑不动了。这种问题有时候很难发现,主要原因是你得等到两个线程一边运行到那个锁的地方才能触发。
ThreadController那个例子
网上有个例子,讲的是两个线程互相等待锁。代码大概是这样的:
Thread 1: synchronized { synchronized { ... } }
Thread 2: synchronized { synchronized { ... } }
这就说得通了。 你看, Thread 1锁了obj1,想去锁obj2;Thread 2锁了obj2,想去锁obj1。这就死锁了。用Arthas的话,怎么查呢?
可能.…. 你输入`thread -b`命令。这个命令的意思是“查找可以阻塞其他线程的线程”。它会扫描所有的锁,看看有没有线程正在等待某个锁,而这个锁又被别的线程锁住了。如果找到了它就会告诉你死锁的详情。
盘它。 我试了一下这个命令,真的能查出来!它直接告诉我是哪个线程拿到了锁,哪个线程在等锁。然后我就可以根据这个信息去调整代码,把锁的顺序改一下或者加个超时机制。这样死锁就解开了。Arthas真的挺厉害的,把这种逻辑上的错误都能找出来。
内存泄漏?内存溢出?Dashboard来帮忙
有时候, 程序跑得挺正常的,但是内存占用越来越大,再说说导致OOM。这种情况通常是内存泄漏, 累并充实着。 就是有一些对象被创建了但是没有被回收,一直占着内存。这种情况怎么查呢?
Dashboard看一眼大图
Arthas有一个`dashboard`命令,这个命令很有用。你输入`dashboard`,它就会显示一个表格。这个表格里有什么呢?有JVM的内存使用情况、CPU使用率、线程数量、加载的类数量等等。
试试水。 我之前遇到过一个内存泄漏的问题,内存一直在涨,但是GC也没怎么跑。我用`dashboard`看了一眼,发现Old Generation的内存已经接近满了。然后我就想,是不是有什么大对象一直没被回收?
Heapdump导出来慢慢看
功力不足。 Arthas还可以导出heapdump文件。你输入`heapdump`命令,然后指定一个文件名,它就会把当前的内存快照保存下来。然后你可以用MAT或者其他工具打开这个文件,分析里面到底有哪些对象,哪些对象占用了最多的内存。有时候你会发现,其实不是内存泄漏,只是你开了太多的连接,或者缓存了太多的数据。
补救一下。 我觉得Arthas的heapdump功能还是挺方便的,省去了我手动用jmap命令去dump文件的麻烦。直接在Arthas里操作,一键导出,然后拿去分析,效率高多了。
IDEA插件?懒人的福音
其实Arthas的命令还是挺多的, 有些命令的参数特别多,比如那个`watch`命令,我就记不住那些参数。 本质上... 每次都要去查文档,查了半天也记不住写个命令还要报错。这让我很头疼。
哈基米! 后来我发现有个Arthas的IDEA插件。这个插件真的太棒了。你安装好插件之后在IDEA里写代码的时候,可以直接点击右键,选择“Arthas”菜单。里面会列出所有可用的命令。你点击一个命令,它会自动生成命令的模板。你只需要把参数填一下就能直接施行了。这个插件还能把命令复制到剪贴板,然后你就可以去Arthas的命令行里粘贴施行了。
有了这个插件,我就再也不用死记硬背那些命令了。虽然它不能直接在IDEA里查看Arthas的输出后来啊,但是它能把命令生成出来省去了我打字的功夫。对于我这种懒人简直是救命稻草。我觉得以后肯定会越来越流行这种插件,毕竟谁愿意去记那么多命令呢?
学不会也得学, 为了生活
说了这么多,其实Arthas就是一个Java诊断工具。它不是万能的,也不能解决所有问题。但是它确实能帮我们解决很多常见的线上问题,比如CPU飙高、死锁、内存泄漏等等。它通过字节码增强的技术,在不修改代码的情况下让我们能看到程序的内部运行情况。这真的很难得。
提到这个... 虽然我写的这篇文章很烂, 语法也不通顺,逻辑也不清晰,但是我希望它真的能帮到那些跟我一样在一线挣扎的Java开发者。线上问题分秒必争,每一秒都很珍贵。如果我们能快速定位问题,快速解决问题,就能减少很多加班的时间,就能早点回家睡觉。
所以大家还是去学一下Arthas吧。别像我一样,遇到问题手忙脚乱。下载下来试试,用那个`thread`命令看看你的CPU到底被谁吃掉了。用那个`watch`命令看看你的方法的参数到底传了什么。用那个`tt`命令回放一下你的调用历史。你会发现,其实也没那么难,真的,最后说一句。。
我倾向于... 再说说希望我的这篇文章能有点阅读量,有点点赞,有点收藏。这样我就有动力继续写更多这种“烂”文章了。拜拜了您内。


