LoginSignup
2
0

More than 3 years have passed since last update.

JavaアプリケーションのJMX監視を有効にしたらデプロイが稀にコケるようになった

Last updated at Posted at 2019-09-04

事象

Datadog にJVM のメトリクスをレポートするためにアプリケーション起動時に JMX 監視を有効にするようにしたら3回に1回くらいの確率でデプロイが失敗するようになった。

デプロイガチャ😂

状況整理

エラーメッセージ

Error: JMX connector server communication error: service:jmx:rmi://ip-xxx-xxx-xxx-xxx:7199

7199 はJMX用に割り当てたポート。

JMXの設定

デプロイはシェルスクリプトで Java プロセスを kill してから再起動している。
JMXの設定は再起動時に Java オプションから。

deploy.sh
#!/bin/bash

set -ue

service_restart() {
  ssh "$DEPLOY_HOST" 'pkill java; test $? -le 1'
  echo "java process stopped"
  START_JAVA_COMMAND=$(cat << EOS
    nohup /path/to/app_start_script \
      -Dconfig.file=/path/to/stage/conf/application.conf \
      -Dcom.sun.management.jmxremote \
      -Dcom.sun.management.jmxremote.port=7199 \
      -Dcom.sun.management.jmxremote.rmi.port=7199 \
      -Dcom.sun.management.jmxremote.authenticate=false \
      -Dcom.sun.management.jmxremote.ssl=false \
      > /var/log/nohup.out \
      2>&1 &
EOS
)
  ssh "$DEPLOY_HOST" "$START_JAVA_COMMAND"
  echo "java process started"
}

service_restart

app_start_script は単に Java オプションを受け取ってアプリケーションを起動するスクリプト。

調査

調べてみたところ jmxremote が有効になっているとアプリケーションの再起動に失敗するという事例は結構あるみたいだった。

原因

どうやら Java プロセスを kill した後もしばらくの間、JMXに指定ポートを掴まれてしまっていることが原因みたいだった。

具体的には、再起動の時点でJMXに割り当てたいポートが LISTEN もしくは TIME_WAIT の状態なってしまっていた。

対策

ということなので netstat で JMXのプロセスを監視して解放されたことを確認してから Java アプリケーションを再起動させるようにシェルを改修した。

#!/bin/bash

set -ue

# JMXのポートが空くまで待機する関数
wait_until_port_opened() {
  while :
  do
    if ! ssh "$DEPLOY_HOST" "netstat -an | grep 7199" > /dev/null
    then
      break
    fi
    sleep 1
  done
}

service_restart() {
  ssh "$DEPLOY_HOST" 'pkill java; test $? -le 1'
  # JMXのポートが空くまで待機
  wait_until_port_opened
  echo "java process stopped"
  START_JAVA_COMMAND=$(cat << EOS
    nohup /path/to/app_start_script \
      -Dconfig.file=/path/to/stage/conf/application.conf \
      -Dcom.sun.management.jmxremote \
      -Dcom.sun.management.jmxremote.port=7199 \
      -Dcom.sun.management.jmxremote.rmi.port=7199 \
      -Dcom.sun.management.jmxremote.authenticate=false \
      -Dcom.sun.management.jmxremote.ssl=false \
      > /var/log/nohup.out \
      2>&1 &
EOS
)
  ssh "$DEPLOY_HOST" "$START_JAVA_COMMAND"
  echo "java process started"
}

service_restart

他の解決策

いろいろ調べてる時に教えてもらったことだけれども、ライブラリを利用してJMXの設定にポートを利用しないというアプローチもあるようだった。

こちらはまたの機会に。

おしまい

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0