摘要: jvm monitor
JVM 监控
基于 jstack 监控定位
查看CPU负载
系统负载/ CPU负载 - 是Linux系统中CPU过度使用率或利用率不足的度量; CPU正在执行或处于等待状态的进程数。
负载平均值 - 是在给定的1,5和15分钟时间段内计算的平均系统负载。
top 命令 (定位到我们cpu高的进程)
1
2
3
4
5
6
7
8
9top
top - 16:40:59 up 388 days, 1:04, 1 user, load average: 0.00, 0.01, 0.05
Tasks: 75 total, 1 running, 72 sleeping, 0 stopped, 2 zombie
Cpu(s): 0.7 us, 0.3 sy, 0.0 ni, 99.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 1883492 total, 247312 free, 473204 used, 1162976 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 1188144 avail Mem
uptime
16:42:36 up 388 days, 1:06, 1 user, load average: 0.00, 0.01, 0.05其中
load average
代表的是cpu的平均负载,三个数字分别代表1分钟、5分钟、15分钟内cpu的平均负载。负荷的大小跟cpu个数以及当前负荷有关系,例如1h 处理器,负载为5 则大概表面有1成的在running 4成的在等待,也就意味着此时可能服务器已经无法处理新的请求了,系统也就凉咯
查看cpu个数
1
cat /proc/cpuinfo | grep "cpu cores"
定位具体线程
jstack 命令
例如我们由top定位到了某个异常的进程,拿到了pid,为9048
接下来我们使用
jstack
命令导出 9048 进程中线程栈的信息1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26jstack 9048 > 9048.txt
top -p 9048 -H # 拿到所有线程的cpu信息,定位具体线程pid
9243 root 20 0 2498028 59096 7008 S 91.0 3.1 0:00.00 java
9244 root 20 0 2498028 59096 7008 S 99.0 3.1 0:00.32 java
定位到线程pid为 9243 9244的cpu占用高
printf "%x" 9243 # 转为16进制--> 2353
printf "%x" 9244 # 转为16进制--> 2354
在9048.txt 查找nid为 0x2353 和 0x2354的线程栈信息,最后发现是nio的WindowsSelectorImpl导致的
cat 9048.txt
"http-nio-8499-ClientPoller-0" #27 daemon prio=5 os_prio=0 tid=0x4e69c800 nid=0x2353 runnable [0x5108f000]
java.lang.Thread.State: RUNNABLE
at sun.nio.ch.WindowsSelectorImpl.resetWakeupSocket0(Native Method)
at sun.nio.ch.WindowsSelectorImpl.resetWakeupSocket(Unknown Source)
- locked <0x257756d8> (a java.lang.Object)
at sun.nio.ch.WindowsSelectorImpl.doSelect(Unknown Source)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(Unknown Source)
- locked <0x257756b8> (a sun.nio.ch.Util$2)
- locked <0x257756a8> (a java.util.Collections$UnmodifiableSet)
- locked <0x2575d518> (a sun.nio.ch.WindowsSelectorImpl)
at sun.nio.ch.SelectorImpl.select(Unknown Source)
at org.apache.tomcat.util.net.NioEndpoint$Poller.run(NioEndpoint.java:744)
at java.lang.Thread.run(Unknown Source)
Locked ownable synchronizers:
- None
基于 JvisualVM 的可视化监控
本地监控
打开 JDK 安装目录 bin 文件夹下的 jvisualvm.exe
,在左侧的本地下可以看到正常运行的java 应用,除了正常的类似命令行界面化的操作外,我们可以安装别的好用的插件
工具–插件–设置–编辑 将URL修改为 https://visualvm.github.io/pluginscenters.html 中对应的JDK版本下的地址,如JDK 8 Update 131 - 192
切换TAB至可用插件,在其列表中选中 Visual GC 插件安装后重启
jvisualvm.exe
即可看到多出的 Visual GC Tab
远程监控
监控远程Tomcat
修改
Catalina.sh
文件1
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=xx -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.net.preferlPv4Stack=true -Djava.rmi.server.hostname=xx.xx.xx.xx"
监控远程普通java进程
添加启动参数
1
nohup java -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=xx -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.net.preferlPv4Stack=true -Djava.rmi.server.hostname=xx.xx.xx.xx -jar xx.jar &
基于Btrace的监控调试
Btrace可用动态的向目标应用程序的字节码注入追踪代码
下载安装
下载安装包
https://github.com/btraceio/btrace
下载realse版本我这里是 v1.3.11.3解压并配置环境变量
新增环境变量
BTRACE_HOME
,Path 中追加%BTRACE_HOME%\bin
运行方式
- 在
JVisualVM
中添加Btrace插件,添加classpath
- 使用命令行
btrace <pid> <trace_script>
使用方法
Demo
这里举在JVisualVM
中使用的例子,安装完Btrace插件后,对其中的 java 应用列表右键打开Trace application,例如对某个应用的某个查询方法的脚本如下:
1 | import com.sun.btrace.AnyType; |
勾上 Output
Class-Path
(Class-Path 可以用来增加第三方jar包),点击 Start
即可等待执行到 query
方法后的打印输出
Doc
- 普通方法 @OnMethod(clazz=””,method=””)
- 构造方法 @OnMethod(clazz=””,method=”“)
- 重载方法通过参数区分
- Kind 拦截时机
- Kind.ENTRY 入口,默认值
- Kind.RETURN 返回
- Kind.THROW 异常
- Kind.Line 行
- this: 形参+@Self 可以拦截this对象
- 复杂的参数可以通过反射获取
- printXxx()
注意事项
- 默认只能本地运行
- 生产环境下也可以使用,但是被修改的字节码不会被还原