在开始诊断之前, 我们通常要确定几件事情, 以帮助我们诊断过程更有效和有针对性.
确认对应的 Java 程序在运行.
有时有人报告说某个程序运行不正常, 我们去查看各种指标和日志, 却找不到相关信息, 各种查找以后发现找错了机器,或者对应的程序其实已经退出了. 所以在线诊断一定要先确定要诊断的程序是否正在运行.
有时候我们登录了某台机器, 却无法查看到对应的Java 程序在运行, 可能是我们权限不够, 又或者是在不同的 pod/container 里面. 所以在开始诊断之前, 这些信息最好确认好, 否则会浪费时间.
比如下面的例子中, 我们使用 jps
命令只能看到当时正在运行的 jps
命令本身, 看不到其它 Java 在运行程序. 但是但我们使用 pgrep
命令, 或者 ps
命令的时候, 却能看到这些在 Docker container 里面运行的 Java 程序.
supra@suprabox:~$ jps
3769076 Jps
supra@suprabox:~$ pgrep java
3567
3780
4535
supra@suprabox:~$ ps aux | grep java
7474 3567 0.8 1.8 10073680 308672 ? Sl Jan27 511:09 /opt/java/openjdk/bin/java -cp /var/lib/neo4j/plugins/*:/var/lib/neo4j/conf/*:/var/lib/neo4j/lib/* -XX:+UseG1GC -XX:-OmitStackTraceInFastThrow -XX:+AlwaysPreTouch -XX:+UnlockExperimentalVMOptions -XX:+TrustFinalNonStaticFields --console-mode
supra 3780 9.1 9.6 7020176 1561912 ? Sl Jan27 5667:41 /usr/share/elasticsearch/jdk/bin/java -Xshare:auto -Des.networkaddress.cache.ttl=60 -Des.networkaddress.cache.negative.ttl=10 -Dio.netty.noUnsafe=true
999 4535 0.1 24.0 8232288 3913624 ? Ssl Jan27 104:44 /usr/local/openjdk-8/bin/java -Dlog4j.configuration=file:/opt/janusgraph/conf/log4j-server.properties -Xms4096m -Xmx4096m -javaagent:/opt/janusgraph/lib/jamm-0.3.0.jar
确认 Java 的版本
尽管 Java 会向前兼容, 但不同的 Java 发行版本, 会有不同的默认行为和不同的参数, 确认版本, 帮助我们在后面的诊断中判断某种症状是不是合理.
比如, 对于上面结果中的3个 Java 程序, 它们都运行在 Docker container 中, 我们查看他们的 Java 版本, 发现它们分别都是使用了不同版本的 Java.
supra@suprabox:~$ sudo nsenter -t 3567 -a /opt/java/openjdk/bin/java -version
[sudo] password for supra:
openjdk version "17.0.5" 2022-10-18
OpenJDK Runtime Environment Temurin-17.0.5+8 (build 17.0.5+8)
OpenJDK 64-Bit Server VM Temurin-17.0.5+8 (build 17.0.5+8, mixed mode, sharing)
supra@suprabox:~$ sudo nsenter -t 3780 -a /usr/share/elasticsearch/jdk/bin/java -version
openjdk version "17.0.1" 2021-10-19
OpenJDK Runtime Environment Temurin-17.0.1+12 (build 17.0.1+12)
OpenJDK 64-Bit Server VM Temurin-17.0.1+12 (build 17.0.1+12, mixed mode, sharing)
supra@suprabox:~$ sudo nsenter -t 4535 -a /usr/local/openjdk-8/bin/java -version
openjdk version "1.8.0_332"
OpenJDK Runtime Environment (build 1.8.0_332-b09)
OpenJDK 64-Bit Server VM (build 25.332-b09, mixed mode)
不同版本的Java 可能对应不同的默认参数, 我们可以通过下面的命令来查看这些默认参数的名字,及默认值:
supra@suprabox:~$ java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal -version
[Global flags]
int AVX3Threshold = 4096 {ARCH diagnostic} {default}
int ActiveProcessorCount = -1 {product} {default}
intx AliasLevel = 3 {C2 product} {default}
size_t TLABSize = 0 {product} {default}
... 省略更多 ...
这个列表很长, 大多数你可能都用不到, 但是某些值对于以后诊断某些问题的细节很有用. 第一列是类型, 第二列是参数的名字, 第三列显示默认值, 第四列里面的不同值表示不同的意思, 比如是否跟某些平台架构想管, 是不是诊断用的参数, 是不是某个特定的编译器才有的参数等, 最后的 {default} 表示是不是一定有默认值.
确认启动命令及参数
有些参数的不设置是有默认值的, 比如初始堆大小, 有些值是根据不同的平台及硬件特性在启动时根据算法选择的, 有些是用户在启动命令参数设置的, 有些虽然可能有默认值或启动设置值, 但是运行时是可以改的. 所以我们要了解这些启动参数是不是有默认值, 默认值是如何设置或计算的, 是不是用户设置了它的值, 它的值在启动后是不是被改动了.