java启动参数之谜的排查过程

作者:邪笑风 时间:2023-02-18 19:47:50 

背景

最近遇到一个有意思的事情,java应用运行在阿里云的ack集群中,某一天有个应用启动突然发现阿里云上的agent都没有注册了,于是开始排查原因。

排查过程

我们的应用是java应用,jdk版本是Open-jdk8,阿里云agent是直接注入到容器中的,因此会将agent启动参数自动注入到 JAVA_TOOL_OPTIONS 环境变量中,当应用启动时会自动带上agent启动参数。

agent没注册,首先检查应用的启动日志,发现应用是启动成功的,tomcat端口都是正常的。仔细观察日志,发现了问题。由于agent 启动参数是注入到 JAVA_TOOL_OPTIONS 中的,通常jvm 在启动的时候会优先加载 JAVA_TOOL_OPTIONS,日志中会出现 Picked up JAVA_TOOL_OPTIONS 的字样,如下图所示,但是问题现场却没有这一行和agent相关的启动日志,说明 jvm 启动的时候并没有加载 JAVA_TOOL_OPTIONS。

java启动参数之谜的排查过程

我们开始怀疑是 agent启动参数 的问题,以为是agent在容器重建时没有将启动参数注入到环境变量中。但是通过环境变量一看,发现 JAVA_TOOL_OPTIONS 是在的,而且每个agent的参数都是齐全的。

java启动参数之谜的排查过程

这个时候就开始怀疑是不是启动脚本的问题,是不是有人在启动脚本中加了unset JAVA_TOOL_OPTIONS,因为当存在JAVA_TOOL_OPTIONS时,使用jdk相关的命令都会带上JAVA_TOOL_OPTIONS中的参数,造成一定的困扰,所以有时候在排查问题的时候会先unset掉这个变量,但是检查完脚本也没有问题。

最后开始咨询阿里云的工程师,怀疑是不是agent或者容器环境有问题。经过反复比较正常容器和问题容器的JAVA_TOOL_OPTIONS启动参数,发现问题容器因为多加载一个agent,JAVA_TOOL_OPTIONS多出来一段参数,去掉这段参数就能恢复正常,加上就会有问题。到这里,可能正常的思路都是怀疑是多出来的参数造成的。但在排查其他正常容器时发现,有的容器即使有这一段参数也能正常启动。

这个时候,阿里云的工程师怀疑是不是参数太长导致的,因为有问题的容器的应用名字比较长,于是我们开始测试,发现确实是这个问题,如下图所示。随后确定了问题所在,jdk8 在加载默认环境变量时会检查长度,当大于1024字节时就会加载失败

java启动参数之谜的排查过程

环境变量

在jdk相关的环境变量中,有两种默认的环境变量 JAVA_TOOL_OPTIONS_JAVA_OPTIONS

JAVA_TOOL_OPTIONS:在jdk8及之前版本中,该变量是最标准的,所有虚拟机都能识别和应用的环境变量,在jdk9之后被JDK_JAVA_OPTIONS所取代。该变量限制1024字节,在不同虚拟机中表现不一样,有的是加载失败,有的是截取一段。

_JAVA_OPTIONS:也是默认的环境变量,但是它是JVM厂家自定义的,可以覆盖JAVA_TOOL_OPTIONS,但各厂家的命名不同,_JAVA_OPTIONS是Oracle的JVM,而IBM的则是用IBM_JAVA_OPTIONS。

因此为避免出现问题,我们应该尽量避免使用默认的环境变量,通常情况下可以在脚本中自定义启动变量如 JAVA_OPTSSPRINGBOOT_OPTS等等。然后在启动java时显式的指定启动参数。

java [-options] -jar xxx.jar [args…]
可以写成
JAVA_OPTS="[-options]"
JAVA_ARGS="[args…]"
java ${JAVA_OPTS} -jar xxx.jar ${JAVA_ARGS}

附:启停脚本

项目打包后在测试环境的启停都是个体力活,刚好又给笔者遇到了,综合别人的脚本记录了一下

判断 Java 进程是否存在

APP_NAME=xxx.jar
pid=jps -l | grep $APP_NAME

if [ -z $pid ]; then
echo "$APP_NAME started"
else
echo "$APP_NAME stoped"
fi

# 普通进程的
# pid=ps -ef | grep $APP_NAME | grep -v grep | awk '{print $2}'

启停脚本

APP_NAME=xxxx-1.0-SNAPSHOT.jar

pid=0
checkpid() {
   javaps=`jps -l | grep $APP_NAME`
   if [ -n "$javaps" ]; then
   pid=`echo $javaps | awk '{print $1}'`
   else
   pid=0
}

start() {
   checkpid
   if [ $psid -ne 0 ]; then
   echo "$APP_NAME already started"
   else
   echo "Starting $APP_NAME ..."
   `nohup java -jar $APP_NAME > $APP_NAME'.out' 2>&1 &`
   checkpid
   if [ $pid -ne 0]; then
   echo "$APP_NAME start success"
   else
   echo "$APP_NAME start faild"
   fi
   fi
}

stop() {
   checkpid
   if [ $pid -ne 0 ]; then
   echo "Stoping $APP_NAME..."
       kill -9 $pid
       if [$? -eq 0 ]; then
       echo "$APP_NAME stop success"
       else
       echo "$APP_NAME stop faild"
      fi
   else
   echo "$APP_NAME already stoped"
  fi
}

case "$1" in
'start')
start
;;
'stop')
stop
;;
'restart')
stop
start
;;
*)# 其他任何情况

echo "help: $0 {start|stop|restart}"
echo "例子: ./deploy start
exit 1
esac
exit 0

来源:https://juejin.cn/post/7106145007093940231

标签:java,启动,参数
0
投稿

猜你喜欢

  • Android实现悬浮窗效果

    2022-08-17 05:59:40
  • 关于springBoot yml文件的list读取问题总结(亲测)

    2023-11-04 12:37:08
  • Android MTU 值修改的实例详解

    2021-09-20 02:27:07
  • Spring注解驱动之BeanPostProcessor后置处理器讲解

    2023-01-04 17:13:26
  • wenserver获取天气预报数据实例分享

    2021-07-22 14:22:52
  • Android Studio 打包生成APK文件方法

    2023-06-11 23:46:51
  • Java中Jackson快速入门

    2023-01-18 10:24:44
  • Unity3D网格功能生成球体网格模型

    2021-08-01 01:21:47
  • C#移除所有事件绑定的方法

    2023-07-25 11:00:52
  • Java最全文件操作实例汇总

    2023-11-14 13:00:17
  • Android百度定位导航之基于百度地图移动获取位置和自动定位

    2022-10-21 10:50:18
  • Android支付宝支付封装代码

    2023-08-02 15:10:06
  • C#实现类似新浪微博长URL转短地址的方法

    2023-06-02 12:59:28
  • obix协议在java中的配置和使用详解

    2023-11-25 20:59:42
  • C#单例模式(Singleton Pattern)实例教程

    2022-11-23 10:44:05
  • Android查看文件夹大小以及删除文件夹的工具类

    2023-06-12 05:51:10
  • Socket通信原理和实践

    2022-07-05 02:42:31
  • Android实现网络图片浏览功能

    2023-10-17 14:05:38
  • C# 注册表 操作实现代码

    2023-07-02 21:53:22
  • Android实现图片点击放大

    2023-03-19 17:40:59
  • asp之家 软件编程 m.aspxhome.com