Tomcat の監視と管理

目次

イントロダクション

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

JMX Remote の有効化

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

Oracle の Web サイトには、Java 11 での JMX Remote のオプションと構成方法のリストが含まれています: 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-Adaptor はランダムなポートを選択するため、アクセスを許可するようにファイアウォールを構成するのが難しくなる可能性があります。

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 remote Ant タスクによる Tomcat の管理

Ant での JMX の使用を簡素化するために、antlib で使用できるタスクのセットが用意されています。

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

次の例は、JMX Accessor の使用方法を示しています
注: ここでは、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: <import file="${CATALINA.HOME}/bin/catalina-tasks.xml" /> を使用して JMX Accessor プロジェクトをインポートし、jmxOpenjmxSetjmxGetjmxQueryjmxInvokejmxEquals、および jmxCondition でタスクを参照します。

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

属性のリスト

属性 説明 デフォルト値
url JMX 接続 URL を設定します - service:jmx:rmi:///jndi/rmi://: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://:9024/jmxrmi"
    ref="jmx.server.9024"
    username="controlRole"
    password="tomcat"
  />

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

  <jmx:open
    url="service:jmx:rmi:///jndi/rmi://: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) で結果を分割し、resultproperty をトークンを格納するためのプレフィックスとして使用します。
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) で結果を分割し、resultproperty をトークンを格納するためのプレフィックスとして使用します。
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>

vhost 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) で結果を分割し、resultproperty をトークンを格納するためのプレフィックスとして使用します。
separatearrayresults 戻り値が配列の場合、結果をプロパティリストとして保存します ($resultproperty.[0..N] および $resultproperty.length) true

すべてのサービスとホストからすべての Manager 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 attribute names]} でこのマネージャーのすべてのプロパティにアクセスできます。 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 は、一度
作成すると、親にリンクできません。 Valve、Cluster、Realm MBean は自動的に
親に接続されません。 代わりに、MBeanFactory 作成
操作を使用します。

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
削除操作を使用します。

JMXAccessorCondition: 条件式

属性のリスト

属性 説明 デフォルト値
url JMX 接続 URL を設定します - service:jmx:rmi:///jndi/rmi://: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 操作を表現するための値の型 (longdouble をサポート) long
operation 式 1
  • == 等しい
  • != 等しくない
  • > より大きい (&gt;)
  • >= 以上 (&gt;=)
  • < 未満 (&lt;)
  • <= 以下 (&lt;=)
==

サーバー接続を待機し、クラスターバックアップノードがアクセス可能であることを確認します

<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: equals MBean Ant 条件

属性のリスト

属性 説明 デフォルト値
url JMX 接続 URL を設定します - service:jmx:rmi:///jndi/rmi://: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 を直接使用するよりも、次の利点があります

  • 実行中のサーバーから小さなデータを 1 つ要求するだけで、完全な JVM を起動してリモート JMX 接続を確立する必要はありません。
  • JMX 接続の操作方法を知る必要はありません
  • このページの残りの部分で説明されている複雑な構成は必要ありません
  • クライアントプログラムを Java で記述する必要はありません

JMX の過剰な使用の完璧な例は、Nagios や Icinga などの一般的なサーバー監視ソフトウェアの場合に見られます。JMX 経由で 10 個の項目を監視する場合、10 個の JVM を起動し、10 個の JMX 接続を確立してから、すべてを数分ごとにシャットダウンする必要があります。 JMXProxyServlet を使用すると、10 個の HTTP 接続を確立して完了することができます。

JMXProxyServlet の詳細については、Tomcat マネージャーのドキュメントを参照してください。