Tomcatの監視と管理

目次

はじめに

監視はシステム管理の重要な側面です。稼働中のサーバー内部を調べたり、統計情報を取得したり、アプリケーションのいくつかの側面を再構成したりすることは、すべて毎日の管理タスクです。

JMXリモートの有効化

注記: この設定は、Tomcatをリモートで監視する場合にのみ必要です。Tomcatが実行されているのと同じユーザーを使用してローカルで監視する場合は、必要ありません。

Oracleのウェブサイトには、Java 11でJMXリモートを設定する方法とオプションの一覧があります。 http://docs.oracle.com/javase/6/docs/technotes/guides/management/agent.html.

以下は、Java 11の簡単な設定ガイドです。

Tomcatの`setenv.bat`スクリプトに次のパラメーターを追加します(詳細はRUNNING.txtを参照)。
注記: この構文はMicrosoft Windows用です。コマンドは同じ行に記述する必要があります。読みやすくするために改行されています。TomcatがWindowsサービスとして実行されている場合は、サービスのJavaオプションを設定するために、その設定ダイアログを使用してください。Linux、macOSなどは、行の先頭から`"set "`を削除してください。

set CATALINA_OPTS=-Dcom.sun.management.jmxremote.port=%my.jmx.port%
  -Dcom.sun.management.jmxremote.rmi.port=%my.rmi.port%
  -Dcom.sun.management.jmxremote.ssl=false
  -Dcom.sun.management.jmxremote.authenticate=false

`com.sun.management.jmxremote.rmi.port`を設定しない場合、JSR 160 JMXアダプターはランダムにポートを選択するため、ファイアウォールでアクセスを許可する設定が難しくなります。

TLSが必要な場合

  1. 変更して追加します
      -Dcom.sun.management.jmxremote.ssl=true
      -Dcom.sun.management.jmxremote.registry.ssl=true
    
  2. プロトコルや暗号スイートを設定するには
      -Dcom.sun.management.jmxremote.ssl.enabled.protocols=%my.jmx.ssl.protocols%
      -Dcom.sun.management.jmxremote.ssl.enabled.cipher.suites=%my.jmx.cipher.suites%
    
  3. クライアント証明書認証を使用するには
      -Dcom.sun.management.jmxremote.ssl.need.client.auth=%my.jmx.ssl.clientauth%

承認が必要な場合(TLSは常に認証で使用することを強くお勧めします)

  1. 変更して追加します
      -Dcom.sun.management.jmxremote.authenticate=true
      -Dcom.sun.management.jmxremote.password.file=../conf/jmxremote.password
      -Dcom.sun.management.jmxremote.access.file=../conf/jmxremote.access
  2. アクセス承認ファイル`$CATALINA_BASE/conf/jmxremote.access`を編集します。
    monitorRole readonly
    controlRole readwrite
  3. パスワードファイル`$CATALINA_BASE/conf/jmxremote.password`を編集します。
    monitorRole tomcat
    controlRole tomcat
    ヒント: パスワードファイルは読み取り専用にし、Tomcatが実行されているオペレーティングシステムユーザーのみがアクセスできるようにする必要があります。
  4. 代わりに、JAASログインモジュールを次のように設定できます。
      -Dcom.sun.management.jmxremote.login.config=%login.module.name%

クライアントに送信されるRMIスタブで使用されるホスト名を指定する必要がある場合(例:接続するために使用する公開ホスト名がローカルホスト名と同じではない場合)、次のように設定できます。

set CATALINA_OPTS=-Djava.rmi.server.hostname

JMXサービスがバインドする特定のインターフェースを指定する必要がある場合、次のように設定できます。

set CATALINA_OPTS=-Dcom.sun.management.jmxremote.host

JMXリモートAntタスクを使用したTomcatの管理

AntでのJMXの使用を簡素化するために、antlibで使用できる一連のタスクが提供されています。

antlib: `$CATALINA_HOME/lib`から`$ANT_HOME/lib`に`catalina-ant.jar`をコピーします。

次の例は、JMXアクセサの使用を示しています。
注記: `name`属性の値は、読みやすくするために改行されています。スペースなしで、すべて同じ行に記述する必要があります。

<project name="Catalina Ant JMX"
      xmlns:jmx="antlib:org.apache.catalina.ant.jmx"
      default="state"
      basedir=".">
  <property name="jmx.server.name" value="localhost" />
  <property name="jmx.server.port" value="9012" />
  <property name="cluster.server.address" value="192.168.1.75" />
  <property name="cluster.server.port" value="9025" />

  <target name="state" description="Show JMX Cluster state">
    <jmx:open
      host="${jmx.server.name}"
      port="${jmx.server.port}"
      username="controlRole"
      password="tomcat"/>
    <jmx:get
      name=
"Catalina:type=IDataSender,host=localhost,
senderAddress=${cluster.server.address},senderPort=${cluster.server.port}"
      attribute="connected"
      resultproperty="IDataSender.backup.connected"
      echo="false"
    />
    <jmx:get
      name="Catalina:type=ClusterSender,host=localhost"
      attribute="senderObjectNames"
      resultproperty="senderObjectNames"
      echo="false"
    />
    <!-- get current maxActiveSession from ClusterTest application
       echo it to Ant output and store at
       property <em>clustertest.maxActiveSessions.original</em>
    -->
    <jmx:get
      name="Catalina:type=Manager,context=/ClusterTest,host=localhost"
      attribute="maxActiveSessions"
      resultproperty="clustertest.maxActiveSessions.original"
      echo="true"
    />
    <!-- set maxActiveSession to 100
    -->
    <jmx:set
      name="Catalina:type=Manager,context=/ClusterTest,host=localhost"
      attribute="maxActiveSessions"
      value="100"
      type="int"
    />
    <!-- get all sessions and split result as delimiter <em>SPACE</em> for easy
       access all session ids directly with Ant property sessions.[0..n].
    -->
    <jmx:invoke
      name="Catalina:type=Manager,context=/ClusterTest,host=localhost"
      operation="listSessionIds"
      resultproperty="sessions"
      echo="false"
      delimiter=" "
    />
    <!-- Access session attribute <em>Hello</em> from first session.
    -->
    <jmx:invoke
      name="Catalina:type=Manager,context=/ClusterTest,host=localhost"
      operation="getSessionAttribute"
      resultproperty="Hello"
      echo="false"
    >
      <arg value="${sessions.0}"/>
      <arg value="Hello"/>
    </jmx:invoke>
    <!-- Query for all application manager.of the server from all hosts
       and bind all attributes from all found manager MBeans.
    -->
    <jmx:query
      name="Catalina:type=Manager,*"
      resultproperty="manager"
      echo="true"
      attributebinding="true"
    />
    <!-- echo the create properties -->
<echo>
senderObjectNames: ${senderObjectNames.0}
IDataSender.backup.connected: ${IDataSender.backup.connected}
session: ${sessions.0}
manager.length: ${manager.length}
manager.0.name: ${manager.0.name}
manager.1.name: ${manager.1.name}
hello: ${Hello}
manager.ClusterTest.0.name: ${manager.ClusterTest.0.name}
manager.ClusterTest.0.activeSessions: ${manager.ClusterTest.0.activeSessions}
manager.ClusterTest.0.counterSend_EVT_SESSION_EXPIRED:
 ${manager.ClusterTest.0.counterSend_EVT_SESSION_EXPIRED}
manager.ClusterTest.0.counterSend_EVT_GET_ALL_SESSIONS:
 ${manager.ClusterTest.0.counterSend_EVT_GET_ALL_SESSIONS}
</echo>

  </target>

</project>

インポート: `<import file="${CATALINA.HOME}/bin/catalina-tasks.xml" />`でJMXアクセサプロジェクトをインポートし、`jmxOpen`、`jmxSet`、`jmxGet`、`jmxQuery`、`jmxInvoke`、`jmxEquals`、`jmxCondition`を使用してタスクを参照します。

JMXAccessorOpenTask - JMX接続オープンタスク

属性一覧

属性 説明 デフォルト値
url JMX接続URLを設定します - `service:jmx:rmi:///jndi/rmi://localhost:8050/jmxrmi`
host ホストを設定し、非常に長いURL構文を短縮します。 localhost
port リモート接続ポートを設定します 8050
username リモートJMX接続のユーザー名。
password リモートJMX接続のパスワード。
ref 内部接続参照の名前。この属性を使用すると、同じAntプロジェクト内で複数の接続を設定できます。 jmx.server
echo コマンドの使用状況を出力します(アクセス分析またはデバッグ用) false
if 現在のプロジェクトに指定された名前の属性が存在する場合にのみ実行されます。
unless 現在のプロジェクトに指定された名前の属性が存在しない場合にのみ実行されます。

新しいJMX接続を開く例

  <jmx:open
    host="${jmx.server.name}"
    port="${jmx.server.port}"
  />

認証を使用してURLからJMX接続を開き、別の参照に格納する例

  <jmx:open
    url="service:jmx:rmi:///jndi/rmi://localhost:9024/jmxrmi"
    ref="jmx.server.9024"
    username="controlRole"
    password="tomcat"
  />

認証を使用してURLからJMX接続を開き、別の参照に格納しますが、プロパティ`jmx.if`が存在し`jmx.unless`が存在しない場合のみ実行する例

  <jmx:open
    url="service:jmx:rmi:///jndi/rmi://localhost:9024/jmxrmi"
    ref="jmx.server.9024"
    username="controlRole"
    password="tomcat"
    if="jmx.if"
    unless="jmx.unless"
  />

注記: `jmxOpen`タスクのプロパティは、他のすべてのタスクと条件にも存在します。

JMXAccessorGetTask: 属性値取得Antタスク

属性一覧

属性 説明 デフォルト値
name 完全修飾JMX ObjectName -- `Catalina:type=Server`
attribute 既存のMBean属性(上記のTomcat MBeanの説明を参照)
ref JMX接続参照 jmx.server
echo コマンドの使用状況を出力します(アクセスと結果) false
resultproperty 結果をこのプロジェクトプロパティに保存します
delimiter デリミタ(`java.util.StringTokenizer`)で結果を分割し、結果プロパティをプレフィックスとして使用してトークンを保存します。
separatearrayresults 戻り値が配列の場合、結果をプロパティリストとして保存します(`$resultproperty.[0..N]`と`$resultproperty.length`) true

デフォルトのJMX接続からリモートMBean属性を取得する例

  <jmx:get
    name="Catalina:type=Manager,context=/servlets-examples,host=localhost"
    attribute="maxActiveSessions"
    resultproperty="servlets-examples.maxActiveSessions"
  />

結果配列を取得して、個別のプロパティに分割する例

  <jmx:get
      name="Catalina:type=ClusterSender,host=localhost"
      attribute="senderObjectNames"
      resultproperty="senderObjectNames"
  />

`senderObjectNames`プロパティにアクセスするには

  ${senderObjectNames.length} give the number of returned sender list.
  ${senderObjectNames.[0..N]} found all sender object names

クラスタが構成されている場合にのみ接続されている`IDataSender`属性を取得する例。
注記: `name`属性の値は、読みやすくするために改行されています。スペースなしで、すべて同じ行に記述する必要があります。


  <jmx:query
    failonerror="false"
    name="Catalina:type=Cluster,host=${tomcat.application.host}"
    resultproperty="cluster"
  />
  <jmx:get
    name=
"Catalina:type=IDataSender,host=${tomcat.application.host},
senderAddress=${cluster.backup.address},senderPort=${cluster.backup.port}"
    attribute="connected"
    resultproperty="datasender.connected"
    if="cluster.0.name" />

JMXAccessorSetTask: 属性値設定Antタスク

属性一覧

属性 説明 デフォルト値
name 完全修飾JMX ObjectName -- `Catalina:type=Server`
attribute 既存のMBean属性(上記のTomcat MBeanの説明を参照)
value 属性に設定する値
type 属性の型。 `java.lang.String`
ref JMX接続参照 jmx.server
echo コマンドの使用状況を出力します(アクセスと結果) false

リモートMBean属性値を設定する例

  <jmx:set
    name="Catalina:type=Manager,context=/servlets-examples,host=localhost"
    attribute="maxActiveSessions"
    value="500"
    type="int"
  />

JMXAccessorInvokeTask: MBean操作呼び出しAntタスク

属性一覧

属性 説明 デフォルト値
name 完全修飾JMX ObjectName -- `Catalina:type=Server`
operation 既存のMBean操作
ref JMX接続参照 jmx.server
echo コマンドの使用状況を出力します(アクセスと結果) false
resultproperty 結果をこのプロジェクトプロパティに保存します
delimiter デリミタ(`java.util.StringTokenizer`)で結果を分割し、結果プロパティをプレフィックスとして使用してトークンを保存します。
separatearrayresults 戻り値が配列の場合、結果をプロパティリストとして保存します(`$resultproperty.[0..N]`と`$resultproperty.length`) true

アプリケーションを停止する

  <jmx:invoke
    name="Catalina:type=Manager,context=/servlets-examples,host=localhost"
    operation="stop"/>

これで、`${sessions.[0..N}`プロパティで`sessionid`を見つけることができ、`${sessions.length}`プロパティでカウントにアクセスできます。

すべての`sessionid`を取得する例

  <jmx:invoke
    name="Catalina:type=Manager,context=/servlets-examples,host=localhost"
    operation="listSessionIds"
    resultproperty="sessions"
    delimiter=" "
  />

これで、`${sessions.[0..N}`プロパティで`sessionid`を見つけることができ、`${sessions.length}`プロパティでカウントにアクセスできます。

セッション`${sessionid.0}`からリモートMBeanセッション属性を取得する例

  <jmx:invoke
    name="Catalina:type=Manager,context=/ClusterTest,host=localhost"
    operation="getSessionAttribute"
    resultproperty="hello">
     <arg value="${sessionid.0}"/>
     <arg value="Hello" />
  </jmx:invoke>

仮想ホスト`localhost`に新しいアクセスロガーバルブを作成する例

 <jmx:invoke
         name="Catalina:type=MBeanFactory"
         operation="createAccessLoggerValve"
         resultproperty="accessLoggerObjectName"
 >
     <arg value="Catalina:type=Host,host=localhost"/>
 </jmx:invoke>

これで、`${accessLoggerObjectName}`プロパティに格納されている名前で新しいMBeanを見つけることができます。

JMXAccessorQueryTask: MBeanクエリAntタスク

属性一覧

属性 説明 デフォルト値
name JMX ObjectNameクエリ文字列 -- `Catalina:type=Manager,*`
ref JMX接続参照 jmx.server
echo コマンドの使用状況を出力します(アクセスと結果) false
resultproperty 検出されたすべてのMBeanにプロジェクトプロパティ名をプレフィックスとして付けます(`mbeans.[0..N].objectname`)
attributebinding `name`に加えて、すべてのMBean属性をバインドします false
delimiter デリミタ(`java.util.StringTokenizer`)で結果を分割し、結果プロパティをプレフィックスとして使用してトークンを保存します。
separatearrayresults 戻り値が配列の場合、結果をプロパティリストとして保存します(`$resultproperty.[0..N]`と`$resultproperty.length`) true

すべてのサービスとホストからすべてのマネージャーObjectNameを取得します

  <jmx:query
    name="Catalina:type=Manager,*
    resultproperty="manager" />

これで、`${manager.[0..N].name}`プロパティでセッションマネージャーを見つけることができ、`${manager.length}`プロパティで結果オブジェクトカウンターにアクセスできます。

`servlet-examples`アプリケーションからマネージャーを取得し、すべてのMBeanプロパティをバインドする例

  <jmx:query
    name="Catalina:type=Manager,context=/servlet-examples,host=localhost*"
    attributebinding="true"
    resultproperty="manager.servletExamples" />

これで、`${manager.servletExamples.0.name}`プロパティでマネージャーを見つけることができ、`${manager.servletExamples.0.[manager属性名]}`でこのマネージャーのすべてのプロパティにアクセスできます。MBeanの結果オブジェクトカウンターは`${manager.length}`プロパティに保存されます。

サーバーからすべてのMBeanを取得し、外部XMLプロパティファイルに格納する例

<project name="jmx.query"
            xmlns:jmx="antlib:org.apache.catalina.ant.jmx"
            default="query-all" basedir=".">
<property name="jmx.host" value="localhost"/>
<property name="jmx.port" value="8050"/>
<property name="jmx.username" value="controlRole"/>
<property name="jmx.password" value="tomcat"/>

<target name="query-all" description="Query all MBeans of a server">
  <!-- Configure connection -->
  <jmx:open
    host="${jmx.host}"
    port="${jmx.port}"
    ref="jmx.server"
    username="${jmx.username}"
    password="${jmx.password}"/>

  <!-- Query MBean list -->
  <jmx:query
    name="*:*"
    resultproperty="mbeans"
    attributebinding="false"/>

  <echoproperties
    destfile="mbeans.properties"
    prefix="mbeans."
    format="xml"/>

  <!-- Print results -->
  <echo message=
    "Number of MBeans in server ${jmx.host}:${jmx.port} is ${mbeans.length}"/>
</target>
</project>

これで、`mbeans.properties`ファイル内のすべてのMBeanを見つけることができます。

JMXAccessorCreateTask: リモートMBean作成Antタスク

属性一覧

属性 説明 デフォルト値
name 完全修飾JMX ObjectName -- `Catalina:type=MBeanFactory`
className 既存のMBeanの完全修飾クラス名(上記のTomcat MBeanの説明を参照)
classLoader サーバーまたはWebアプリケーションクラスローダーのObjectName
(`Catalina:type=ServerClassLoader,name=[server,common,shared]`または
`Catalina:type=WebappClassLoader,context=/myapps,host=localhost`)
ref JMX接続参照 jmx.server
echo コマンドの使用状況を出力します(アクセスと結果) false

リモートMBeanを作成する例

  <jmx:create
    ref="${jmx.reference}"
    name="Catalina:type=MBeanFactory"
    className="org.apache.commons.modeler.BaseModelMBean"
    classLoader="Catalina:type=ServerClassLoader,name=server">
    <arg value="org.apache.catalina.mbeans.MBeanFactory" />
  </jmx:create>

警告: 作成された多くのTomcat MBeanは、親にリンクできません。
バルブ、クラスタ、レルムMBeanは、親に自動的に
接続されません。代わりに`MBeanFactory` create
操作を使用してください。

JMXAccessorUnregisterTask: リモートMBean登録解除Antタスク

属性一覧

属性 説明 デフォルト値
name 完全修飾JMX ObjectName -- `Catalina:type=MBeanFactory`
ref JMX接続参照 jmx.server
echo コマンドの使用状況を出力します(アクセスと結果) false

リモートMBeanの登録を解除する例

  <jmx:unregister
    name="Catalina:type=MBeanFactory"
  />

警告: 多くのTomcat MBeanは登録解除できません。
MBeanは親からリンク解除されません。代わりに`MBeanFactory`
remove操作を使用してください。

JMXAccessorCondition: 条件式

属性一覧

属性 説明 デフォルト値
url JMX接続URLを設定します - `service:jmx:rmi:///jndi/rmi://localhost:8050/jmxrmi`
host ホストを設定し、非常に長いURL構文を短縮します。 localhost
port リモート接続ポートを設定します 8050
username リモートJMX接続のユーザー名。
password リモートJMX接続のパスワード。
ref 内部接続参照の名前。この属性を使用すると、同じAntプロジェクト内で複数の接続を設定できます。 jmx.server
name 完全修飾JMX ObjectName -- `Catalina:type=Server`
echo 条件の使用状況を出力します(アクセスと結果) false
if 現在のプロジェクトに指定された名前の属性が存在する場合にのみ実行されます。
unless 現在のプロジェクトに指定された名前の属性が存在しない場合にのみ実行されます。
value (必須) 操作の第2引数
type 操作を表す値の型(`long`と`double`をサポート) long
operation 式1
  • == 等しい
  • != 等しくない
  • > より大きい (>)
  • >= 以上 (>=)
  • < 小さい (<)
  • <= 以下 (<=)
==

サーバー接続とクラスタバックアップノードへのアクセスを待機します

<target name="wait">
  <waitfor maxwait="${maxwait}" maxwaitunit="second" timeoutproperty="server.timeout" >
    <and>
      <socket server="${server.name}" port="${server.port}"/>
      <http url="${url}"/>
      <jmx:condition
        operation="=="
        host="localhost"
        port="9014"
        username="controlRole"
        password="tomcat"
        name=
"Catalina:type=IDataSender,host=localhost,senderAddress=192.168.111.1,senderPort=9025"
        attribute="connected"
        value="true"
      />
    </and>
  </waitfor>
  <fail if="server.timeout" message="Server ${url} don't answer inside ${maxwait} sec" />
  <echo message="Server ${url} alive" />
</target>

JMXAccessorEqualsCondition: MBean等価条件Ant条件

属性一覧

属性 説明 デフォルト値
url JMX接続URLを設定します - `service:jmx:rmi:///jndi/rmi://localhost:8050/jmxrmi`
host ホストを設定し、非常に長いURL構文を短縮します。 localhost
port リモート接続ポートを設定します 8050
username リモートJMX接続のユーザー名。
password リモートJMX接続のパスワード。
ref 内部接続参照の名前。この属性を使用すると、同じAntプロジェクト内で複数の接続を設定できます。 jmx.server
name 完全修飾JMX ObjectName -- `Catalina:type=Server`
echo 条件の使用状況を出力します(アクセスと結果) false

サーバー接続とクラスタバックアップノードへのアクセスを待機します

<target name="wait">
  <waitfor maxwait="${maxwait}" maxwaitunit="second" timeoutproperty="server.timeout" >
    <and>
      <socket server="${server.name}" port="${server.port}"/>
      <http url="${url}"/>
      <jmx:equals
        host="localhost"
        port="9014"
        username="controlRole"
        password="tomcat"
        name=
"Catalina:type=IDataSender,host=localhost,senderAddress=192.168.111.1,senderPort=9025"
        attribute="connected"
        value="true"
      />
    </and>
  </waitfor>
  <fail if="server.timeout" message="Server ${url} don't answer inside ${maxwait} sec" />
  <echo message="Server ${url} alive" />
</target>

JMXProxyServletの使用

Tomcatは、リモート(またはローカル)JMX接続を使用する代わりに、JMXが提供するすべての機能にアクセスできる代替手段を提供します。TomcatのJMXProxyServletです。

JMXProxyServletを使用すると、クライアントはHTTPインターフェースを介してJMXクエリを発行できます。この方法は、クライアントプログラムから直接JMXを使用するよりも、次のような利点があります。

  • 稼働中のサーバーから少量のデータだけを要求するために、完全なJVMを起動してリモートJMX接続を行う必要はありません。
  • JMX接続の使用方法を知る必要はありません。
  • このページの残りの部分で説明されている複雑な設定は必要ありません。
  • クライアントプログラムをJavaで記述する必要はありません。

NagiosやIcingaなどの一般的なサーバー監視ソフトウェアの場合、JMXを介して10個のアイテムを監視する場合、10個のJVMを起動し、10個のJMX接続を行い、数分ごとにすべてをシャットダウンする必要があります。JMXProxyServletを使用すると、10個のHTTP接続を行い、それで済みます。

Tomcatマネージャーのドキュメントで、JMXProxyServletの詳細を確認できます。