Javosize——下一代JAVA Profiler

达芬奇密码2018-07-03 14:31

 性能测试中经常需要定位性能问题,那么你是否想过会有一个工具不需要像BTrace或者housemd那样需要安装配置、执行脚本就可以定位性能问题呢?javosize工具就可以实现,同时它还可以告诉你哪里出了问题,为什么出了问题。Javosize的官网地址为:http://www.javosize.com/,它自诩为the missing sugar for your Java cup,那么我就带大家看看这颗糖到底甜不甜。


1.安装

Javosize的安装非常简单,去官网上面下载一个jar包,不需要安装配置,官网地址:http://www.javosize.com/index.html;

安利小贴士

1)  大家都知道,想要传输文件到云主机,可以直接在XShell上用新建文件传输,把需要的文件传到对应主机的/tmp目录下;

2)  对于需要连接不同vpn的不同租户来说,比如说萧山B的两个vpn不能同时连接,但是环境中用到了这两个租户中的一些机器,我们就可以连接其中一个vpn,将其中的某台机器开启Xagent,就可以通过ssh登录另外一个vpn的机器了:

3)  在两个云主机之间传输文件,可以采用如下方式,这样文件就从qatest@test1传到了qatest@test2上了:

qatest@test1:  python -m SimpleHTTPServer 10010

qatest @test2:  wget http://test1.server.163.org:10010/file

2.使用

在该jar包所在的目录中,运行如下命令: java -jar javosize.jar <PID>。其中<PID>就是java进程的PID,可以通过命令 ps –ef |grep java来获取。下图就表示进入了21296这个java进程:


3.功能

linux相似的界面和操作,能大大增加用户的好感。用一个简单的ls就可以查看它的目录结构,用cd就可以进入相应的目录,cd ..可以返回到上一级菜单:

help命令可以查看每个目录的功能,以及在该目录下面可以执行的命令:


Apps

显示当前应用的信息以及cpu详细指标

appthreads

显示所有活动的应用程序的线程

breakpoints

断点生成以及控制

classes

显示所有装载类的信息,可以动态修改类

custommetrics

显示自定义的指标

interceptor

添加拦截器

jmx

显示JVM提供的Mbeans的信息

memory

显示有关不同内存空间和垃圾收集的信息

perfcounter

显示JVM不同性能的计数器

problems

显示你的JVM的常见问题

repository

存储和执行方法

scheduler

调度命令

sessions

显示HTTP会话细节以及CPU消耗

sh

允许应用服务器内执行任意代码

threads

显示线程的信息

其中在性能测试中排查问题最常用的要数 threads repository这两个了
4. 常用命令解析

Threads

ls

罗列所有存在的线程以及它们的状态

cat <Thread_ID>

某个线程的详细信息

dump

输出一个完整的线程dump

kill <Thread_ID>

杀死某个线程

      

repository

FIND_SLOW_METHODS_SESSION

查找最慢方法

START_JMX_SERVER

指定端口开启JMX服务器

TOP_MEMORY_CONSUMERS

内存消耗top

FIND_SLOW_METHODS_EXECUTING_CLASS

查找最慢执行类

FIND_SLOW_METHODS_THREAD

查找最慢线程

每个方法的具体用法可以用例如: cat FIND_SLOW_METHODS_THREAD 查看。

5. 实践
进入到threads目录中,ls查看所有的线程,并且可以用grep命令。但是比较遗憾的是,不支持sort命令,所有当用ls查看的时候,很容易滚动条滚到顶了看不完所有的显示内容,并且无法输出到文本。只能调大XShell的缓冲区大小了。 ls|grep BLOCKED可以直接把处于BLOCKED状态的线程罗列出来,并且可以看到是被什么BLOCKED住的,下图所示就能看到是因为resin的TCP连接导致的:

使用 cat id 还可以查看该线程的具体信息:

通过在threads目录下的ls找到消耗CPU较多的线程,记录其ID,返回上一级的 repository 目录,就可以通过FIND_SLOW_METHODS_THREAD方法找到耗时点,其中第一个参数是ID,第二个参数是方法耗时的上限单位毫秒,第三个参数是搜索间隔单位毫秒:
[javOSize@JVM /repository]~> exec FIND_SLOW_METHODS_THREAD 85944 10 5000
App: null URL: null
Bottleneck: 860 ms. spent at sun.nio.ch.FileDispatcher.read0(Native Method) method sensitivity: 22 ms . StackTrace: 
	sun.nio.ch.FileDispatcher.read0(Native Method)
	sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:21)
	sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:198)
	sun.nio.ch.IOUtil.read(IOUtil.java:166)
	sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:245)
	com.schooner.MemCached.SchoonerSockIOPool$TCPSockIO.isAlive(Unknown Source)
	com.schooner.MemCached.SchoonerSockIOPool.getConnection(Unknown Source)
	com.schooner.MemCached.SchoonerSockIOPool.getSock(Unknown Source)
	com.schooner.MemCached.AscIIClient.get(Unknown Source)
	com.schooner.MemCached.AscIIClient.get(Unknown Source)
	com.schooner.MemCached.AscIIClient.get(Unknown Source)
	com.danga.MemCached.MemCachedClient.get(Unknown Source)
	com.netease.urs.util.UrsMemCachedClient.get(UrsMemCachedClient.java:28)
	com.netease.passport.session.HttpSessionSidWrapper.getAttribute(HttpSessionSidWrapper.java:43)
	sun.reflect.GeneratedMethodAccessor106.invoke(Unknown Source)
	sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	java.lang.reflect.Method.invoke(Method.java:597)
	com.javosize.agent.ReflectionUtils.invoke(ReflectionUtils.java:48)
	com.javosize.agent.ReflectionUtils.invoke(ReflectionUtils.java:29)
	java.util.Aspect.getUserId(Aspect.java:103)
	java.util.Aspect.methodEnd(Aspect.java:72)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:724)
	com.caucho.server.dispatch.ServletFilterChain.doFilter(ServletFilterChain.java:106)
	com.netease.urs.serverwatch.DebugFilter.doFilter(DebugFilter.java:151)
	com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:70)
	com.netease.urs.serverwatch.WatchFilter.doFilter(WatchFilter.java:22)
	com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:70)
	com.netease.urs.sentry.UrlStatsFilter.doFilter(UrlStatsFilter.java:25)
	com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:70)
	com.netease.passport.filter.UplinkSMSFilter.doFilter(UplinkSMSFilter.java:61)
	com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:70)
	com.netease.passport.filter.RiskManageFilter.doFilter(RiskManageFilter.java:146)
	com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:70)
	com.netease.passport.filter.MemcachedSessionFilter.doFilter(MemcachedSessionFilter.java:110)
	com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:70)
	com.caucho.server.webapp.WebAppFilterChain.doFilter(WebAppFilterChain.java:173)
	com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:229)
	com.caucho.server.hmux.HmuxRequest.handleRequest(HmuxRequest.java:420)
	com.caucho.server.port.TcpConnection.run(TcpConnection.java:514)
	com.caucho.util.ThreadPool.runTasks(ThreadPool.java:527)
	com.caucho.util.ThreadPool.run(ThreadPool.java:449)
	java.lang.Thread.run(Thread.java:662)
6. 高能预警!!! 可视化界面profile
除了上面讲的用运行jar包的方式使用javosize, 还可以采用 javaagent 的方法看到一个可视化的界面,在 javosize 官网注册下载 jar 包。以 tomcat 为例,在启动参数中添加: -javaagent:<FOLDER WHERE YOU PLACED THE FILE>/javosize.jar ,以我用的这台机器为例就是:
然后访问 https://www.javosize.com/platform/ ,输入你注册的账号即可看到如下的界面:
这个面板也可以自定义(具体见 javosize 的官网)。 左边导航栏,可以查找慢方法,内存泄漏, Thread inspector Session inspector Exception inspector Method inspector
下图就是根据查找慢方法的过滤规则找到的慢方法,支持正则表达式的方式:



下图就是线程检查,可以看到对应的 URL CPU 使用情况等,单击某个线程还可以看到它的堆栈情况,点击放大镜图标,还可以显示完整的堆栈跟踪:

7. 结语
说了这么多,不如自己用一下。实践证明,用javosize还是会影响java性能,所以在定位完问题后记得关掉javosize。
同一个测试任务,不采用javosize的性能:


采用javosize的性能:


本文来自网易实践者社区,经作者齐红方授权发布。