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。
我们开始怀疑是 agent启动参数 的问题,以为是agent在容器重建时没有将启动参数注入到环境变量中。但是通过环境变量一看,发现 JAVA_TOOL_OPTIONS 是在的,而且每个agent的参数都是齐全的。
这个时候就开始怀疑是不是启动脚本的问题,是不是有人在启动脚本中加了unset JAVA_TOOL_OPTIONS
,因为当存在JAVA_TOOL_OPTIONS时,使用jdk相关的命令都会带上JAVA_TOOL_OPTIONS中的参数,造成一定的困扰,所以有时候在排查问题的时候会先unset掉这个变量,但是检查完脚本也没有问题。
最后开始咨询阿里云的工程师,怀疑是不是agent或者容器环境有问题。经过反复比较正常容器和问题容器的JAVA_TOOL_OPTIONS启动参数,发现问题容器因为多加载一个agent,JAVA_TOOL_OPTIONS多出来一段参数,去掉这段参数就能恢复正常,加上就会有问题。到这里,可能正常的思路都是怀疑是多出来的参数造成的。但在排查其他正常容器时发现,有的容器即使有这一段参数也能正常启动。
这个时候,阿里云的工程师怀疑是不是参数太长导致的,因为有问题的容器的应用名字比较长,于是我们开始测试,发现确实是这个问题,如下图所示。随后确定了问题所在,jdk8 在加载默认环境变量时会检查长度,当大于1024字节时就会加载失败。
环境变量
在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_OPTS
、SPRINGBOOT_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


猜你喜欢
- Android 开发,不可避免的会用到网络技术,而多数情况下,我们都是使用 HTTP 协议来发送和接收网络数据。Android 系统主要提供
- 题目要求:两人比赛,A,B,每人最开始分得6张手牌,手牌大小为从1到9 A先出牌,B后出牌,若出牌在桌面上存在,在出牌人获得两张相同牌中间的
- 本文实例为大家分享了Android Glide图片加载的具体代码,供大家参考,具体内容如下1.普通用法Glide.with(context)
- 前言有时候我们在项目中,会用到一些本地 jar 包文件,比如隔壁公司自己打包的;此时无法从maven远程仓库拉取;那么我们可以考虑把 jar
- ActivityThread功能它管理应用进程的主线程的执行(相当于普通Java程序的main入口函数),并根据AMS的要求(通过IAppl
- 异常分类可查的异常(checked exceptions):Exception下除了RuntimeException外的异常不可查的异常(u
- 什么是代理模式代理模式是开发中常见的一种设计模式,使用代理模式可以很好的对程序进行横向扩展。代理,顾名思义就是一个真实对象会存在一个代理对象
- 一、什么是内存泄漏内存泄漏是指你向系统申请分配内存进行使用(new/malloc),然后系统在堆内存中给这个对象申请一块内存空间,但当我们使
- 缘起随着 App 的成长,我们难免会遇到以下这些需求:H5 跳原生界面Notification 点击调相关界面根据后台返回数据跳转界面,例如
- 本文实例为大家分享了Winform实现石头剪刀布游戏的具体代码,供大家参考,具体内容如下新建一个windows窗体程序,用数字1代表石头,用
- 为什么写?今天去上班的公交上,有朋友在张队(张善友)的微信群里,发了一个介绍C# 6.0新特性的视频,视频7分钟,加上本人英语实在太low,
- 首先给出一段代码:public class AslistMethod { public static void main(String[]
- 1、使用FileStream读写文件 文件头:using System;using System.Collections.Gene
- 这篇文章主要介绍了JAVA内存溢出解决方案图解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参
- 本文实例讲述了C#编程获取客户端计算机硬件及系统信息功能。分享给大家供大家参考,具体如下:这里使用C#获取客户端计算机硬件及系统信息 ,包括
- 一、问题描述有时候,我们会遇到在遍历List集合的过程中删除数据的情况。看着自己写的代码,感觉完全没有问题,但就是达不到预期的效果,这是为什
- 使用Convert接口实现类型转换器在Spring3中引入了一个Converter接口,它支持从一个Object转为另一个Object。除了
- 1.修改主站点的elasticsearch.yml添加一下行:xpack.security.enabled: true2.生成安全秘钥切到E
- 前言最近遇到了这样一个工作场景,需要写一批dubbo接口,再将dubbo接口注册到网关中,但是当dubbo接口异常的时候会给前端返回非常不友
- 背景最近在研究搭建spring源码调试环境时,接触到到gradle项目构建工具。由于之前习惯于maven项目的构建,故通过此文记录相关gra