java啟動(dòng)參數(shù)之謎的排查過(guò)程
背景
最近遇到一個(gè)有意思的事情,java應(yīng)用運(yùn)行在阿里云的ack集群中,某一天有個(gè)應(yīng)用啟動(dòng)突然發(fā)現(xiàn)阿里云上的agent都沒(méi)有注冊(cè)了,于是開(kāi)始排查原因。
排查過(guò)程
我們的應(yīng)用是java應(yīng)用,jdk版本是Open-jdk8,阿里云agent是直接注入到容器中的,因此會(huì)將agent啟動(dòng)參數(shù)自動(dòng)注入到 JAVA_TOOL_OPTIONS 環(huán)境變量中,當(dāng)應(yīng)用啟動(dòng)時(shí)會(huì)自動(dòng)帶上agent啟動(dòng)參數(shù)。
agent沒(méi)注冊(cè),首先檢查應(yīng)用的啟動(dòng)日志,發(fā)現(xiàn)應(yīng)用是啟動(dòng)成功的,tomcat端口都是正常的。仔細(xì)觀察日志,發(fā)現(xiàn)了問(wèn)題。由于agent 啟動(dòng)參數(shù)是注入到 JAVA_TOOL_OPTIONS 中的,通常jvm 在啟動(dòng)的時(shí)候會(huì)優(yōu)先加載 JAVA_TOOL_OPTIONS,日志中會(huì)出現(xiàn) Picked up JAVA_TOOL_OPTIONS 的字樣,如下圖所示,但是問(wèn)題現(xiàn)場(chǎng)卻沒(méi)有這一行和agent相關(guān)的啟動(dòng)日志,說(shuō)明 jvm 啟動(dòng)的時(shí)候并沒(méi)有加載 JAVA_TOOL_OPTIONS。

我們開(kāi)始懷疑是 agent啟動(dòng)參數(shù) 的問(wèn)題,以為是agent在容器重建時(shí)沒(méi)有將啟動(dòng)參數(shù)注入到環(huán)境變量中。但是通過(guò)環(huán)境變量一看,發(fā)現(xiàn) JAVA_TOOL_OPTIONS 是在的,而且每個(gè)agent的參數(shù)都是齊全的。

這個(gè)時(shí)候就開(kāi)始懷疑是不是啟動(dòng)腳本的問(wèn)題,是不是有人在啟動(dòng)腳本中加了unset JAVA_TOOL_OPTIONS,因?yàn)楫?dāng)存在JAVA_TOOL_OPTIONS時(shí),使用jdk相關(guān)的命令都會(huì)帶上JAVA_TOOL_OPTIONS中的參數(shù),造成一定的困擾,所以有時(shí)候在排查問(wèn)題的時(shí)候會(huì)先unset掉這個(gè)變量,但是檢查完腳本也沒(méi)有問(wèn)題。
最后開(kāi)始咨詢(xún)阿里云的工程師,懷疑是不是agent或者容器環(huán)境有問(wèn)題。經(jīng)過(guò)反復(fù)比較正常容器和問(wèn)題容器的JAVA_TOOL_OPTIONS啟動(dòng)參數(shù),發(fā)現(xiàn)問(wèn)題容器因?yàn)槎嗉虞d一個(gè)agent,JAVA_TOOL_OPTIONS多出來(lái)一段參數(shù),去掉這段參數(shù)就能恢復(fù)正常,加上就會(huì)有問(wèn)題。到這里,可能正常的思路都是懷疑是多出來(lái)的參數(shù)造成的。但在排查其他正常容器時(shí)發(fā)現(xiàn),有的容器即使有這一段參數(shù)也能正常啟動(dòng)。
這個(gè)時(shí)候,阿里云的工程師懷疑是不是參數(shù)太長(zhǎng)導(dǎo)致的,因?yàn)橛袉?wèn)題的容器的應(yīng)用名字比較長(zhǎng),于是我們開(kāi)始測(cè)試,發(fā)現(xiàn)確實(shí)是這個(gè)問(wèn)題,如下圖所示。隨后確定了問(wèn)題所在,jdk8 在加載默認(rèn)環(huán)境變量時(shí)會(huì)檢查長(zhǎng)度,當(dāng)大于1024字節(jié)時(shí)就會(huì)加載失敗。

環(huán)境變量
在jdk相關(guān)的環(huán)境變量中,有兩種默認(rèn)的環(huán)境變量 JAVA_TOOL_OPTIONS 和 _JAVA_OPTIONS。
JAVA_TOOL_OPTIONS:在jdk8及之前版本中,該變量是最標(biāo)準(zhǔn)的,所有虛擬機(jī)都能識(shí)別和應(yīng)用的環(huán)境變量,在jdk9之后被JDK_JAVA_OPTIONS所取代。該變量限制1024字節(jié),在不同虛擬機(jī)中表現(xiàn)不一樣,有的是加載失敗,有的是截取一段。
_JAVA_OPTIONS:也是默認(rèn)的環(huán)境變量,但是它是JVM廠(chǎng)家自定義的,可以覆蓋JAVA_TOOL_OPTIONS,但各廠(chǎng)家的命名不同,_JAVA_OPTIONS是Oracle的JVM,而IBM的則是用IBM_JAVA_OPTIONS。
因此為避免出現(xiàn)問(wèn)題,我們應(yīng)該盡量避免使用默認(rèn)的環(huán)境變量,通常情況下可以在腳本中自定義啟動(dòng)變量如 JAVA_OPTS、SPRINGBOOT_OPTS等等。然后在啟動(dòng)java時(shí)顯式的指定啟動(dòng)參數(shù)。
java [-options] -jar xxx.jar [args…]
可以寫(xiě)成
JAVA_OPTS="[-options]"
JAVA_ARGS="[args…]"
java ${JAVA_OPTS} -jar xxx.jar ${JAVA_ARGS}附:?jiǎn)⑼D_本
項(xiàng)目打包后在測(cè)試環(huán)境的啟停都是個(gè)體力活,剛好又給筆者遇到了,綜合別人的腳本記錄了一下
判斷 Java 進(jìn)程是否存在
APP_NAME=xxx.jar
pid=jps -l | grep $APP_NAME
if [ -z $pid ]; then
echo "$APP_NAME started"
else
echo "$APP_NAME stoped"
fi
# 普通進(jìn)程的
# 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總結(jié)
到此這篇關(guān)于java啟動(dòng)參數(shù)之謎的文章就介紹到這了,更多相關(guān)java啟動(dòng)參數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java多線(xiàn)程Future實(shí)現(xiàn)優(yōu)雅獲取線(xiàn)程的執(zhí)行結(jié)果
這篇文章主要為大家詳細(xì)介紹了Java如何利用Future實(shí)現(xiàn)優(yōu)雅獲取線(xiàn)程的執(zhí)行結(jié)果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-07-07
Java中的 VO,BO,DO 對(duì)象命名問(wèn)題小結(jié)
本文講解VO,BO,DO 的作用以及如何使用,分析了如何消除三者之間重復(fù)的代碼,同樣結(jié)合現(xiàn)實(shí)生活中領(lǐng)導(dǎo)配秘書(shū)來(lái)類(lèi)比講解,對(duì)Java VO 對(duì)象命名相關(guān)知識(shí)感興趣的朋友一起看看吧2024-01-01
Java項(xiàng)目如何防止SQL注入(多種方案匯總)
SQL注入即是指web應(yīng)用程序?qū)τ脩?hù)輸入數(shù)據(jù)的合法性沒(méi)有判斷或過(guò)濾不嚴(yán),攻擊者可以在web應(yīng)用程序中事先定義好的查詢(xún)語(yǔ)句的結(jié)尾上添加額外的SQL語(yǔ)句,這篇文章主要介紹了?Java項(xiàng)目防止SQL注入的四種方案,需要的朋友可以參考下2023-12-12

