开发者学堂课程【线上问题排查利器 Alibaba Arthas(下):Arthas 实践案例】学习笔记,与课程紧密连接,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/747/detail/13210
Arthas 实践案例
内容介绍:
一. 需求
二. 准备场景
三. 步骤
四. 实现步骤
五. 结论
一.需求
需求有两个:第一,运行在服务器上面的web程序当中是由哪一个控制器来处理所有请求的?或者说现在在执行的复制器是哪一个?它的方法名是什么?
可以快速定位一个请求是被哪些Filter拦截的,或者请求最终是由哪些Servlet处理的。但有时想知道一 个请求是被哪个Spring MVC Controller处理的。如果翻代码,会比较难找,并且不一定准确。通过Arthas可以精确定位是哪个Controller处理请求。
第二个内容,就是找到想得到的每一个请求的调用参数和它的返回值。现在这个里面有两个需求,但是现在并不知道这个方法的名字是什么?还有它的返回值是什么?所以要一层一层去找。
二.准备场景
当在做这个案例时,先要准备一个应用场景。找到一个项目,这个项目可以提前打包好,将它打包成一个war包,比如:ssm_student_war 再放在资料里面。
也可以从资料里面直接把它部署到tomcat服务器里面去。
例如将ssm_student_war项目部署到Linus的tomcat服务器下,并且是可以正常访问的。
启动之后,访问服务器的ip地址,访问:http://192.168.254.199.8080/ssm_student,再把这个 IP 地址直接部署上去。
以下例子是安装在User下面的local,这里面有一个 web apps。
在这里面有一个war包,它实际上就是一个简单的ssm框架做出来的一个简单的登录和查询,当然它也是访问数据库的。
现在可以开始运行浏览器了,看一下如下图效果。首先输入前面的地址,按回车,这时它就会进入登录的页面,这是很简单的一个页面。如下图所示:
数据库里面有一些数据在里面,在linux里面进行登录,可以看见里面有一个表
如下图:
里面有两张表,一个是用户表,这个用户表里面有两条记录
可以看到用户名密码,但这只是一个简单的密码,并没有加密。
另一个表展示了所有的学生的信息。
需求是这样的:用户以表上名字登录,进来以后就可以查到所有的学生信息,做这么一个基本的操作,但是是用 ssm 框架做出来的。
假设输入一个用户名输入一个密码进行登录。
登录进来以后就可以查到以下这个表,就是一个很简单的操作。
三. 步骤
如果想用arthas进行追踪,并且要想知道,它是调用的控制器里面哪两个方法?这两个方法的输入参数和输出参数是多少?那应该怎么去做?
首先也是要启动,输入 Java-jar arthas-boot.jar 按回车,选择要监视的java进程,选1。如下图所示:
要注意,万一出现这个端口已经被别人使用了,让你选择用另外一种方式的提示,那也是有做法的。
在 Linus 里面有一个 netstat 可以输入这个命令,进行查看
比如 arthas 是默认3658这个端口,2161/Java 这是它的进程 id。如果这个端口被占用了,可以直接把这个进程给清除掉。
如下图所示:
现在不用清除,因为两者没有冲突。
四. 实现步骤
进来以后在浏览器上先做第一步操作,现在可能不知道是用的哪个方法。
ssm 当中所有的请求都是经过一个 servlet,这个 servlet 的名字叫Dispatcherservlet,所有的这个请求都是由 spring 框架的 servlet 来进行控制的,它是一个核心控制器,首先就追踪这个操作。
如果不记得这个包,也是没关系的,它这里会有提示。可以按一下 tab 键,就可以找到。如下图所示:
在servlet里面有命令DispatcherServlet。如果不知道在过滤器里面执行了哪个方法,就写一个星号,这就相当于追踪所有的方法。
如果不记得方法怎么办?不记得方法可以写个星号,那么追踪的内核方法就多了,但是效率上面会低很多。所以还是要有一些开发的常识。如下图:
现在开始追踪,按回车,回车以后发现它现在是没有反应的。
如下图:
需要再访问一次,它才会追踪,就相当于重新刷新。刷新它实际上是
做了两件事情,因为它会有一个警告说重新提交表单,并且再查询这个数据,所以实际上它做了两个操作。
点继续让它重新提交一次。重新提交一次以后可以看到它最终的数据,但是数据是非常多的。
如下图所示的白色区域:
先从这里开始
这里可以选择视图,选择全屏模式或者紧凑模式,这样看起来内容更多一点,字体也调小一点。如下图:
这里就出现一个问题,现在这么多内容,应该怎么去看。可以从这个地方开始,如下图:
这里有一个经验,就是看哪个耗时最多。
比如说如下图,一个是33 ,一个是34。
到这里基本上就能追踪出来,它是运用哪个方法。
在如上图33下面{33.738972ms}是耗时是最长的33毫秒,也就是说它实际上做的是doDipatch这个方法。它执行这个方法是比较耗时的。
如果再往下看还有没有最长耗时的,其实都有一些耗时久的,但是最终这个doDipatch方法就可以。
现在就开始追踪doDipatch,其实它不需要追踪,直接到了如下图这一层,就能够看到这个方法就说明这个方法在处理了。
这样就可以对这个方法进行反编译,这是要做的第二步操作。将doDipatch进行反编译的操作。
注意看一下如上这个代码,因为它比较耗时,所以这里就要用到反编译的命令,先从这个页面退出来,输入Jad这是反编译的。
如果只想显示源码,就敲source only。找org.springframework.Web servlet.下面的Dispatcherservlet 反编译的Dodispatch 这个方法,
再按回车,就完成了。反编译的这个方法只是反映编译的这一个方法:Dodispatch而且只显示源码。这样就可以看到spring里面的一些源码,它最终返回的是modeAnd view。
这个是它模型和视图的一个封装对象,就是它要返回的一个对象mv,那就看哪个方法是返回mv的。
找到哪个地方是给mv进行赋值的之类的东西。往下找有个ha,它是适配器。
假设一行一行代码的去看不太现实,于是这里可以调用getHandler
以上这句话它返回了一个ha对象,获得了一个ha。
下面大概就是获得请求的方法
如果是get的方法就显示如上图所示的【equals method】。
这里大概是记录日志,也就是说下面这块的代码是一些无关紧要的代码。
在这块区域就再跟踪这个方法,并且无论跟踪哪个方法都要进行多次的尝试。
假设现在跟踪的是这个核心的处理代码的方法。这个方法它的返回值或者它返回的对象是一个什么样的内容?ha到底是个什么命令?Ha实际上就叫处理器,适配器。
这也是spring当中三大组件之一,还叫处理器适配器。跟踪一下这个方法gateHandlerAdapter。接下来,找到watch org .springframework.web.servlet getHandler
看一下这里面的get handler这个方法。
Gate handler这个方法要想知道它的返回值就输入 return obj再按回车,如果他没有动说明没有调用,这时要再刷新一次,刷新一次以后可以显示它执行的结果也可以看到gethandler他返回的对象。如下图:
这个 handler 对象里面的所有的成员属性,其中就有一个handler属性中间就标出来了两个处理器,一个是 Usercontroller login,它带了两个参数,一个user对象。一个 session。还有一个是 student controller。
找到这两个方法以后,基本上就已经找到了具体的处理器是哪一个了。
接下来第四步怎么做?
再来追踪这两个方法,它的输入参数和返回值。那这时先退出再输入 watch com.itheima.controller.*.*,
要追踪的是什么呢?
后面要写条件表达式{params returnobj}。
需要知道它的参数是什么,以及它的返回值是什么?
如果不带参数,就先按回车,再去刷新一次,就可以看到追踪的这个方法,如下图代码所示:
第一个是登录的方法,登录的方法它最终返回的是一个forward://student/list这个地址,在这个学生信息上面看是不到这个地址的,它看到的是logi,它最终跳到student/list这个地址上了。
Result=@Array list这个是上面的com.itheima.controller.usercontroller.login登录的方法。
如下图是登录的方法:
会发现它的返回值返回了一个students,返回一个students集合里面封装的每一个元素。这样就可以知道它的值。
如果看不到密码或者这个方法的其他的一些信息怎么办?可以把这个方法追踪,设置它的级别,把它最终的深度设置为两级watch,监视的深度为两级。
再刷新一下来看结果,这个时候就更加清楚了。
这个是登录的方法。登录里面的用户名和密码,这里面还有绘画,之前那个登录是有两个参数的。Student/list这个是它的返回值。
同样findall是查找所有的参数,来查找所有的学生信息。反而执行modleandview,它会执行这个view。这个方法就能够看到里面的模型的值。
那再加到三级能不能再看得到里面的内容呢?
再刷新一次,按回车,然后再刷新,如果三级还看不到就到四级,再刷新一次。
四级就能看到里面的内容。如下图所示:
这样就可以具体追踪到每一个方法,因为已经知道它方法的名称了。以上就是具体的应用的一个案例。
五. 结论
最终主要使用的是这三条命令:一个是 trace,一个是 jad 的,一个是 watch。
trace 是用来追踪最耗时的部分。jad是反编译的,watch是用的比较多的,它用来监视每个方法的参数和返回值以及它的所耗时长。
这个就相当于一个简单的实战,在实际的应用当中,可以发挥自己的想象,并且需要大量的实战的操作和积累相应的经验。