资源(CPU,memory,thread)相关快速诊断.md - liuxiang/liuxiang.github.io GitHub Wiki
# 查看java进程号(pid) :
> jps
> pidof java #java进程
> pgrep java #java进程(推荐)
> pgrep -n java #最近一个java进程
# 机器安装多java进程服务,可参考如下匹配
ps -ef |grep "holmes-web"|grep -v "grep"|awk '{print $2}'
# 信息查看:
> jinfo $pid- 单行命令(压缩)
仅适合一台机器仅一个java进程情况
# 获取进程下最消耗CPU的线程栈详情
process=`pgrep java` && echo $process; \
top -c -b -n 1 -Hp $process | sed -n '1,11p'; \
top1pid=`top -c -b -n 1 -Hp $process| sed -n '8,8p'|awk '{print $1}'` && echo top1pid: $top1pid; \
thread=`printf '%x' $top1pid`; echo thread-nid: $thread; \
[ $thread != 0 ] && jstack $process|grep 0x$thread -A20# main函数栈
process=`pgrep -n java` && echo $process; jstack $process|grep \"main\" -A20- 分解
# 1.定位java进程(也可以用pgrep java)
process=`pidof java`
echo $process "(如遇多个java进程,自行赋值)"
# 2.定位top1线程pid(第八行:sed -n '8,8p')
top1pid=`top -c -b -n 1 -Hp $process| sed -n '8,8p' | cut -d ' ' -f1`
# 3.线程pid转十六进制
thread=`printf '%x' $top1pid`; echo $thread;
# 4.打印top1线程栈[显示行数: 15 (可修改)]
[ -n $thread ] && jstack $process | grep 0x$thread -A151.[ -n $thread ] 非空, [ $thread != 0 ] 非0
2.||则与&&相反。如果||左边的命令(命令1)未执行成功,那么就执行||右边的命令(命令2);或者换句话说,“如果这个命令执行失败了||那么就执行这个命令
3.一条命令需要独占一个物理行,如果需要将多条命令放在同一行,命令之间使用命令分隔符(;)分隔。执行的效果等同于多个独立的命令单独执行的效果. 分隔符(;)也标记着一串命令的结束.
- 其它提取线程ID的几种方式
echo `head + awk`
topT=`top -c -b -n 1 -Hp $process |grep admin|head -n 1| awk '{print $1}'`
echo `cut -d`(空格分割,取数组位1)
topT=`top -c -b -n 1 -Hp $process |grep admin|head -n 1| cut -d ' ' -f1`
echo `tail -n +8` (第8行开始到最后)
topT=`top -c -b -n 1 -Hp $process|tail -n +8 | head -n 1 | cut -d ' ' -f1`
echo `sed -n '8,8p' ` (第8行开始到第8行)
topT=`top -c -b -n 1 -Hp $process|sed -n '8,8p' | cut -d ' ' -f1`参考
关于shell中,如何得到top命令显示的进程号?
https://bbs.csdn.net/topics/350053680
- GC情况:
jstat -gc <pid> 1000 5 - 堆使用情况:
jmap -heap <pid> - jvm配置情况:
jinfo -flags <pid>
pgrep -n java | xargs jmap -heap (高版本jdk已经没有了-heap)
pgrep -n java | xargs jinfo -flags
# 可能出现的问题:
1.VMVersionMismatchException
> 启动应用版本与诊断jdk版本不一致
2.Caused by: sun.jvm.hotspot.debugger.DebuggerException: Can't attach to the process. Could be caused by an incorrect pid or lack of privileges
> 权限问题 or jdk8部分版本问题(>jdk9诊断无问题)
注:可以用高版本jdk14诊断低版本jdk8启动的应用.
3.Cannot connect to core dump or remote debug server. Use jhsdb jmap instead
> 使用jhsdb (但依然会出现以上其它问题)
jhsdb jmap --heap --pid 5784
jhsdb jinfo --flags --pid 5784- 对象内存分布:jmap -histo:live $pid
pgrep -n java | xargs jmap -histo | head -n 20
pgrep -n java | xargs jmap -histo | grep cn.fraudmetrix | head -n 20
pgrep -n java | xargs jmap -histo:live | grep cn.fraudmetrix | head -n 20- heap dump (jmap -dump:format=b,file=dumpfileName.dump $pid)
pgrep java | xargs jmap -dump:format=b,file=dumpfileName.dump jinfo -flags <pid>
-XX:+Use*** 为当前使用垃圾回收器
消耗内存的top进程: ps aux|head -1; ps aux|grep -v PID|sort -rn -k +4|head
(或: ps aux | sort -k4nr |head -n 10)
Linux下如何查看哪些进程占用的CPU内存资源最多
https://www.cnblogs.com/sparkbj/p/6148817.html
linux查看进程占用cpu、内存、io信息
http://blog.51cto.com/liuqun/2049656
# 打印堆栈(相隔3s执行一次,执行5次:可获得持续3s~15s均未执行结束的线程.排除守护线程外基本可判断为高嫌疑线程)
jstack [PID] >> jstack.log
# 显示系统java线程总数
ps -eLf | grep java -c- [分组统计]堆栈中各线程状态
process=`pgrep java`;jstack $process > jstack.log;
cat jstack.log | grep 'java.lang.Thread.State' | awk '{print $2" "$3" "$4" "$5}' | sort | uniq -c
# 效果
34 RUNNABLE
4 TIMED_WAITING (on object monitor)
11 TIMED_WAITING (parking)
7 TIMED_WAITING (sleeping)
2 WAITING (on object monitor)
27 WAITING (parking) - [分组统计]各线程组
process=`pgrep java`;jstack $process > jstack.log;
cat jstack.log | grep 'tid=' | awk '{print $1}' | awk -F '-' '{print $1"-"$2"-"$3}' | uniq -c | sort -rnk 1 | head -10
cat jstack.log | grep 'tid=' | awk '{print $1}' | awk -F '-' '{print $1"-x-"$3}' | sort -rnk 1 | uniq -c |sort -rnk 1| head -10
# 示例效果
14 "http-nio-8010
6 "New--
4 "RMI--
4 "GC--
3 "JDWP--
2 "metrics-meter-tick
2 "C2--
1 "watchdog_sync_data_liuxiangs-MacBook-Air.local
1 "watchdog_sync_data_liuxiangs-MacBook-Air.local
1 "statDailyScheduler-1"-"pool-15780-thread-1" #15980 prio=5 os_prio=0 tid=0x00007f5830d05000 nid=0x6e9f waiting on condition [0x00007f53c6ef2000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000005d09e7d40> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
tid: java内的线程id
nid: 操作系统级别线程的线程id
prio: java内定义的线程的优先级
os_prio: 操作系统级别的优先级# 连接数
netstat -na | wc -l
# 有效连接数
netstat -nat | grep ESTABLISHED | wc -l
# 对各种状态的连接数分组统计结果
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
SYN_SENT 2
LAST_ACK 1
CLOSE_WAIT 4
TIME_WAIT 256
ESTABLISHED 96- 获取当前ip
inet_ip=`/sbin/ifconfig|grep inet|grep -v inet6|grep -v 127.0.0.1|awk '{if(substr($2,1,5)=="addr:"){print substr($2,6)} else{print $2}}'|head -n 1`
echo $inet_ip
或
inet_ip=`/sbin/ifconfig|grep inet|grep -v inet6|grep -v 127.0.0.1 | cut -d ' ' -f2`
echo $inet_ip
或
IP=`ip a|grep -w 'inet'|grep 'global'|sed 's/^.*inet //g'|sed 's/\/[0-9][0-9].*$//g'`
echo $IP- 查看连接某服务端口最多的的IP地址
netstat -nat | grep "ESTABLISHED" | grep $inet_ip | awk '{print $5}' | awk -F: '{print $1}' | sort | uniq -c | sort -nr | head -20
14 192.168.6.28.80
12 192.168.6.70.3306
10 10.57.17.28.3306
4 192.168.6.56.2181
4 192.168.6.55.9092
3 192.168.8.126.993
2 192.168.6.57.2181
2 192.168.6.56.9092
2 151.101.72.133.443
2 10.57.22.129.8080
1 18.204.186.74.443- curl获取http各阶段的响应时间
curl -o ~ -s -w %{time_namelookup}::%{time_connect}::%{time_starttransfer}::%{time_total}::%{speed_download}"\n" "baidu.com"[tdops@turing-d-016013 ~]$ sar -n DEV 2
Linux 3.10.0-693.11.6.el7.x86_64 (turing-d-016013.te.td) 2021年04月16日 _x86_64_ (8 CPU)
20时35分26秒 IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s
20时35分28秒 eth0 53.00 28.00 4.88 19.13 0.00 0.00 0.00
20时35分28秒 lo 7360.50 7360.50 3119.00 3119.00 0.00 0.00 0.00
20时35分28秒 docker0 0.00 0.00 0.00 0.00 0.00 0.00 0.00
20时35分28秒 IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s
20时35分30秒 eth0 44.00 20.50 4.06 2.38 0.00 0.00 0.00
20时35分30秒 lo 7384.00 7384.00 3124.16 3124.16 0.00 0.00 0.00
20时35分30秒 docker0 0.00 0.00 0.00 0.00 0.00 0.00 0.00
IFACE: LAN接口
rxpck/s: 每秒钟接收的数据包
txpck/s: 每秒钟发送的数据包
rxbyt/s: 每秒钟接收的字节数
txbyt/s: 每秒钟发送的字节数
rxcmp/s: 每秒钟接收的压缩数据包
txcmp/s: 每秒钟发送的压缩数据包
rxmcst/s: 每秒钟接收的多播数据包- 服务端配置远程调试
# 服务端配置远程调试
- Jdk1.7之前:
CATALINA_OPTS="$CATALINA_OPTS -server -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5888"
- jdk1.7之后:
CATALINA_OPTS="$CATALINA_OPTS -server -agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n"# jconsole,jvisualvm,JMC 监控配置(rmi)
# -Dcom.sun.management.jmxremote.authenticate=false 为 JMC 关闭飞行模式
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.port=8999 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.managementote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Djava.rmi.server.hostname=***.***.***.***"
或
# set tomcat jmx
inet_ip=`/sbin/ifconfig|grep inet|grep -v inet6|grep -v 127.0.0.1|awk '{if(substr($2,1,5)=="addr:"){print substr($2,6)} else{print $2}}'|head -n 1`
CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=8999 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=$inet_ip"- 配置安全策略
在jdk的bin目录(which java)下创建文件jstatd.all.policy
写入下面的安全配置
grant codebase "file:${java.home}/../lib/tools.jar" {
permission java.security.AllPermission;
};
或
grant codebase "file:/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-1.el7_6.x86_64/lib/tools.jar" {
permission java.security.AllPermission;
};
此处写绝对路径,主要是防止路径错误问题,排查问题,应该写成相对路径。- 生成
jstatd.all.policy
cd `which java` # 为参考
sudo tee jstatd.all.policy <<-'EOF'
grant codebase "file:${java.home}/../lib/tools.jar" {
permission java.security.AllPermission;
};
EOF- 启动jstatd
./jstatd -J-Djava.security.policy=jstatd.all.policy -J-Djava.rmi.server.hostname=106.15.95.37 &
或
inet_ip=`/sbin/ifconfig|grep inet|grep -v inet6|grep -v 127.0.0.1|awk '{if(substr($2,1,5)=="addr:"){print substr($2,6)} else{print $2}}'|head -n 1`
./jstatd -J-Djava.security.policy=jstatd.all.policy -J-Djava.rmi.server.hostname=$inet_ip &- 查看jstatd是否启动成功
[root@sunpyServer bin]# jps -l
3040 sun.tools.jstatd.Jstatd
3094 sun.tools.jps.Jps- 日常GC日志以文件的方式输出到服务器(可用于回溯)
# 配置tomcat,日常GC日志. 可记录下服务器历史的GC情况
# 注意:tomcat启动后如果webapps下未自动创建sys目录,请手动创建 */webapps>mkdir sys
# 配置路径到webapps下,方便日志文件的下载和直接定位:
# 访问:
# http://121.40.87.121:8080/sys/gc.log
# http://121.40.84.8:8080/sys/gc.log
# 可视化工具:GCViewer可以使用网络地址直接查看
CATALINA_OPTS="$CATALINA_OPTS -Xloggc:webapps/sys/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps"示例:
# YoungGC+OldGC分配失败 GC (Allocation Failure) [PSYoungGen: 22716K->680K(33280K)] 22716K->7810K(110080K), 0.0929256 secs] [Times: user=0.13 sys=0.00, real=0.09 secs] # OOM [Full GC (Allocation Failure) [PSYoungGen: 480K->0K(2560K)] [ParOldGen: 249K->680K(7168K)] 729K->680K(9728K), [Metaspace: 3259K->3259K(1056768K)], 0.0076754 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
- jprofile服务器端配置
# jprofile服务器端配置
CATALINA_OPTS="$CATALINA_OPTS -agentlib:jprofilerti=port=8849,nowait -Xbootclasspath/a:/usr/local/jprofile/jprofiler9/bin/agent.jar"- jvm shut down时,输出dump文件
# jvm shut down时,输出dump文件
CATALINA_OPTS="$CATALINA_OPTS -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/apache-tomcat-7.0.59/logs/heap.dump"- JMC & JFR
# 1.定位目标java进程
pid=`pgrep java`; ps -ef |grep "holmes-web"|grep -v "grep"|awk '{print $2}'
# pid=`ps -ef |grep "holmes-web"|grep -v "grep"|awk '{print $2}'`; # 机器中多java进程情况参考
# 2.先解锁技能
jcmd $pid VM.unlock_commercial_features
# 3.采集(其中,delay参数表示profile延迟启动时间,duration表示持续采集时间,这里设置为2分钟)
jcmd $pid JFR.start name=myrec delay=20s duration=2m filename=/tmp/$pid.jfr
#settings定制采集配置,如tongdun.jfc.它默认有一个名为profile的配置,如果不想采集异常信息,也可以直接用它。
# jcmd $pid JFR.start name=myrec settings=tongdun delay=20s duration=2m filename=/tmp/$pid.jfr
# 4.移除: 采集数据生成后请执行下列命令移除这个采集
jcmd $pid JFR.stop name=myrec
# 5.分析
这样就好了,等待2分钟+20秒,/tmp/pid.jfr文件就生成好了,这个文件直接导入JMC工具即可.idea-profiler还可分析火焰图.settings表示使用哪种采集配置,这里用的就是第二步中放入的tongdun.jfc配置,它默认有一个名为profile的配置,如果不想采集异常信息,也可以直接用它。 查看工具: $JAVA_HOME/bin/jmc 介绍: https://www.oracle.com/java/technologies/javase/jmc-relnotes.html 单独安装:
$ tar zxf jmc-<version>_osx-x64.tar.gz $ open ./jmc-<version>_osx-x64/JDK\ Mission\ Control.app https://jdk.java.net/jmc/8/ https://www.oracle.com/java/technologies/javase/jmc8-install.html
- GCViewer
- 输出gc.log
CATALINA_OPTS="$CATALINA_OPTS -Xloggc:/usr/local/apache-tomcat-7.0.59/webapps/sys/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps"
或(启动处)
CATALINA_OPTS="$CATALINA_OPTS -Xloggc:gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps"
```bash
- 访问 `open:open-file` 或 gc.log放置为静态资源:http://localhost:8080/gc.log
- JProfiler
> ...
- spring-boot-admin
https://github.com/codecentric/spring-boot-admin
- dump分析工具: jvisualvm / IBM HeapAnalyzer / jmc / Idea-Profiler / jprofiler
# IBM HeapAnalyzer(ha456.jar) ★★★
生成dump: jmap -dump:format=b,file=dumpfileName.dump $pid
分析dump: 打开*.dump文件
# jvisualvm(可装插件Visual GC)
生成dump: 抽样器-内存-堆Dump (heapdump-***.hprof)
分析dump: 文件-载入(下载服务器上dump:heapdump-***.hprof)
# jmc
生成dump: jmap -dump:format=b,file=dumpfileName.hprof $pid
分析dump: 拖拽*.hprof文件到面板即可
# Idea - Profiler分析工具
Open Snapshot: 选择分析目标文件(*.hprof or *.jfr)
# jprofiler(试用/收费)- 远程下载dump
scp [email protected]:/home/admin/forseti-gateway/deploy/tomcat/temp/heapdump-1523203218367.hprof ~-
greys > arthas > jvm-sandbox

-
jvm-tools
-
vjtools

