監(jiān)控是系統(tǒng)管理中的重要環(huán)節(jié)。系統(tǒng)管理員的日常工作就包括:觀察服務器的運行細節(jié),獲取統(tǒng)計數(shù)據(jù),或者重新配置應用的某些內容。
注意:該配置只適用于需用遠程監(jiān)控 Tomcat 的情況,使用同樣的用戶在本地監(jiān)控 Tomcat 則不需要這么配置。
Oracle 的網(wǎng)站上介紹了如何在 Java 6 上配置 JMX 遠程: http://docs.oracle.com/javase/6/docs/technotes/guides/management/agent.html。
下面是在 Java 6 上的快速配置向導:
將下列參數(shù)添加到 Tomcat 的 setenv.bat
腳本(具體詳細信息請查看 RUNNING.txt)。
注意:該語法格式適用于 Windows 系統(tǒng)。命令行只能寫在同一行中,包裝起來更具可讀性。如果 Tomcat 以 Windows 服務的形式運行,使用它的系統(tǒng)配置對話設置該服務的 java 選項。對于 UN\*X
系統(tǒng)來說,要將命令行開頭的 "set "
去掉。
set CATALINA_OPTS=-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=%my.jmx.port%
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
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 的操作系統(tǒng)用戶所訪問。
注意:JSR 160 JMX 適配器在一個隨機端口上打開了第二個數(shù)據(jù)通道。假如本地安裝了防火墻,這就會出現(xiàn)問題。要想解決它,可以按照偵聽器文檔中介紹的方法,配置一個 JmxRemoteLifecycleListener
。
為了簡化 JMX 的用法,加入了一些可能會與 antlib 使用的一系列任務。
antlib:將 catalina-ant.jar 從 $CATALINA_HOME/lib
復制到 $ANT_HOME/lib
。
下面的例子展示了 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.orginal</em>
-->
<jmx:get
name="Catalina:type=Manager,context=/ClusterTest,host=localhost"
attribute="maxActiveSessions"
resultproperty="clustertest.maxActiveSessions.orginal"
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 來引用任務。
屬性列表
屬性 | 描述 | 默認值 |
---|---|---|
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 | Echo 命令用途(用于訪問分析或調試) | false
|
if | 只有當指定名稱的屬性存在于當前項目時才執(zhí)行 | - |
unless | 只有當指定名稱的屬性不存在于當前項目時才執(zhí)行 | - |
打開新的 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 任務中所有屬性也存在于其他所有任務和條件中。
屬性列表
屬性 | 描述 | 默認值 |
---|---|---|
name
|
完全限定的 JMX ObjectName——Catalina:type=Server | - |
attribute
|
已有的 MBean 屬性(參看上文介紹的 Tomcat MBean 描述) | - |
ref
|
JMX 連接引用 | jmx.server
|
echo
|
Echo 命令用途(訪問與結果) | false
|
resultproperty
|
在該項目屬性中保存結果 | - |
delimiter
|
用分隔符(java.util.StringTokenizier )分隔結果,使用 resultproperty 作為前綴來保存令牌 |
- |
separatearrayresults
|
返回值為數(shù)組時,將結果保存為屬性列表($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"
/>
獲取結果數(shù)組,并將其分隔成獨立的一些屬性:
<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" />
屬性列表
屬性 | 說明 | 默認值 |
---|---|---|
name
|
完全限定的 JMX ObjectName——Catalina:type=Server
|
- |
attribute
|
已有的 MBean 屬性(詳情參見上文介紹的 Tomcat MBean 說明) | - |
value
|
設定為屬性的值 | - |
type
|
屬性類型 | java.lang.String
|
ref
|
JMX 連接引用 | jmx.server
|
echo
|
Echo 命令用途(訪問與結果) | false
|
設定遠程 MBean 屬性值的范例如下:
<jmx:set
name="Catalina:type=Manager,context=/servlets-examples,host=localhost"
attribute="maxActiveSessions"
value="500"
type="int"
/>
屬性列表
屬性 | 說明 | 默認值 | |
---|---|---|---|
name
|
完全限定的 JMX ObjectName——Catalina:type=Server
|
- | |
operation
|
已有的 MBean 操作(funcspecs/fs-admin-opers.html) | - | |
ref
|
JMX 連接引用 | jmx.server
|
jmx.server
|
echo
|
Echo 命令用途(訪問與結果) | false
|
|
resultproperty
|
在這一項目屬性中保存結果 | - | |
delimiter
|
用分隔符(java.util.StringTokenizier )分隔結果,使用 resultproperty 作為前綴來保存令牌 |
- | |
separatearrayresults
|
返回值為數(shù)組時,將結果保存為屬性列表($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}
屬性來訪問計數(shù)。
獲取所有 sessionid 的范例如下:
<jmx:invoke
name="Catalina:type=Manager,context=/servlets-examples,host=localhost"
operation="listSessionIds"
resultproperty="sessions"
delimiter=" "
/>
現(xiàn)在你可以在 ${sessions.[0..N} 屬性中找到 sessionid,然后利用 ${sessions.length}
屬性來訪問計數(shù)。
從 ${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 上創(chuàng)建新的訪問日志記錄器值:
<jmx:invoke
name="Catalina:type=MBeanFactory"
operation="createAccessLoggerValve"
resultproperty="accessLoggerObjectName"
>
<arg value="Catalina:type=Host,host=localhost"/>
</jmx:invoke>
現(xiàn)在可以利用 ${accessLoggerObjectName} 屬性上存儲的名稱找到新的 MBean 了。
屬性列表:
屬性 | 描述 | 默認值 |
---|---|---|
name
|
JMX ObjectName 查詢字符串——Catalina:type=Manager,* | - |
ref
|
JMX 連接引用 | jmx.server
|
echo
|
Echo 命令用途(訪問及結果) | false
|
resultproperty
|
將項目屬性名做為前綴加到所有已建立的 MBean 上(mbeans.[0..N].objectname ) |
- |
attributebinduing
|
除了 name 之外,綁定所有的 MBean 屬性 |
false
|
delimiter
|
用分隔符(java.util.StringTokenizier )分隔結果,使用 resultproperty 作為前綴來保存令牌 |
- |
separatearrayresults
|
返回值為數(shù)組時,將結果保存為屬性列表($resultproperty.[0..N] 和 $resultproperty.length) | true
|
從所有的服務及主機中獲取所有的 Manager ObjectName:
<jmx:query
name="Catalina:type=Manager,*
resultproperty="manager" />
現(xiàn)在,在 ${manager.[0..N].name} 屬性上可以找到 Session Manager,利用 ${manager.length} 屬性來訪問結果對象計數(shù)器。
從 servlet-examples 程序中獲取 Manager,并綁定所有的 MBean 屬性:
<jmx:query
name="Catalina:type=Manager,context=/servlet-examples,host=localhost*"
attributebinding="true"
resultproperty="manager.servletExamples" />
現(xiàn)在我們可以在 ${manager.servletExamples.0.name} 屬性中找到 manager,并利用 ${manager.servletExamples.0.[manager attribute names]} 訪問該 manager 的所有屬性。MBean 的結果對象計數(shù)器被保存在 ${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>
現(xiàn)在就可以在 mbeans.properties 文件中找到所有的 MBean 了。
屬性列表
屬性 | 描述 | 默認值 |
---|---|---|
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
|
Echo 命令用途(訪問及結果) | false
|
創(chuàng)建遠程 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 一經(jīng)創(chuàng)建就沒有與父級連接。Valve、集群以及Realm 的 MBean 都不會自動與父級相連。作為替代,可以使用 MBeanFactory 來創(chuàng)建操作。
屬性列表
屬性 | 描述 | 默認值 |
---|---|---|
name
|
完全限定的 JMX ObjectName——Catalina:type=MBeanFactory | = |
ref
|
JMX 連接引用 | jmx.server
|
echo
|
Echo 命令使用(訪問及結果) | false
|
注銷遠程 MBean 范例如下:
<jmx:unregister
name="Catalina:type=MBeanFactory"
/>
警告:許多 Tomcat MBean 都無法注銷。MBean 無法從其父級脫離。可以使用 MBeanFactory 來移除操作。
屬性列表
屬性 | 描述 | 默認值 |
---|---|---|
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
|
Echo 命令使用(訪問及結果) | false
|
if
|
只有當給定名稱的屬性存在于當前項目中才執(zhí)行 | - |
unless
|
只有當給定名稱的屬性不存在于當前項目中才執(zhí)行 | - |
value (必須)
|
操作的第二個參數(shù) | - |
type
|
表達操作的值類型(支持 long 和 double) | long
|
operation
|
提供以下操作
== 等于!= 不等于> 大于(> )>= 大于或等于(>= )< 小于(< )<= 小于或等于(<= ) |
==
|
等待服務器連接,集群備份節(jié)點可訪問。
<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>
屬性列表
屬性 | 描述 | 默認值 |
---|---|---|
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
|
Echo 命令使用(訪問及結果) | false
|
等待服務器連接,集群備份節(jié)點可訪問。
<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>
Tomcat 為使用遠程(或者甚至本地的)JMX 連接提供了一個替代方案:Tomcat 的 JMXProxyServlet,但它仍能讓你訪問 JMX 所提供的任何內容。
JMXProxyServlet 允許客戶端通過 HTTP 接口來發(fā)送 JMX 查詢。相比直接從客戶端程序使用 JMX 來說,該技術具有以下優(yōu)勢:
常見的服務器監(jiān)控軟件(比如 Nagios 或 Ichinga)中都存在過度使用 JMX 的問題:如果想通過 JMX 監(jiān)控 10 項,就必須啟動 10 個 JVM,保持 10 個 JMX 連接,每過幾分鐘就要將它們全部關閉。有了 JMXProxyServlet,利用 10 個 HTTP 連接就能搞定了。
關于 JMXProxyServlet 的詳細說明,可查閱 Tomcat Manager。
更多建議: