Java Management Extensions (JMX)

(1Q23)


eXist-db provides access to various management interfaces via Java Management Extensions (JMX). An agent in the Java Virtual Machine exposes agent services as MBeans that belong to different components running within the Virtual Machine. A JMX-compliant management application can then connect to the agent through the MBeans and access the available services in a standardized way.

The standard Java installation includes a simple client, JConsole, which will display the eXist-specific services. eXist also provides a command-line client for quick access to server statistics and other information.

eXist only exposes a limited set of read-only services. Most of them are useful for debugging purposes only.

Enabling the JMX agent

The JMX agent is enabled by default for connections to local processes only: it is not exposed over TCP by default.

To enable the platform server on the host virtual machine over TCP, pass the following Java system properties (e.g. as part of the JAVA_OPTS environment variable):

-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=1099
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

Warning:

These options make the server publicly accessible. Please check the Oracle JMX documentation for details.

Monitoring and Management

This section explains how to monitor an eXist instance using common Java tools.

Use JConsole

Use a JMX compliant management console to access the management interfaces. For example, call JConsole, which is included with the JDK:

jconsole

When connecting locally, select the entry starting org.codehaus.mojo.appessembler.booter.Appass... under "Local Proccess"

When connecting remotely over TCP, provide the hostname and port under "Remote Process", or provide them directly from the command line:

jconsole hostname:port

You may be presented with a dialogue box stating that a secure connection could not be established: it should be possible to continue with an insecure connection.

Clicking on the MBeans tab should show some eXist-specific MBeans below the standard Java MBeans (in the tree component to the left).

Use JMXClient

eXist includes a simple command-line JMX client which provides quick access to some important server statistics.

  • Unix/Linux:

    $EXIST_HOME/bin/jmxclient.sh params
  • Windows:

    $EXIST_HOME\bin\jmxclient.bat params

This accepts the following command-line parameters:

-a, --address <argument>

The Remote Method Invocation (RMI) address of the server.

-c, --cache

Displays server statistics on cache and memory usage.

-d, --db

Displays general information about the db instance.

-h, --help

Prints help on command line options and exit.

-i, --instance <argument>

The ID of the database instance to connect to.

-l, --locks

lock manager: displays locking information on all threads currently waiting for a lock on a resource or collection. Useful to debug deadlocks. During normal operation, the list will usually be empty (means: no blocked threads).

-m, --memory

Displays info on free and total memory. Can be combined with other parameters.

-p, --port <argument>

The Remote Method Invocation (RMI) port of the server.

-s, --report

Retrieves the most recent sanity/consistency check report.

-w, --wait <argument>

while displaying server statistics: keeps retrieving statistics, but waits the specified number of seconds between calls.

The following command should print some statistics about cache usage within eXist:

$EXIST_home/bin/jmxclient.sh -c -w 2000

JMXServlet

eXist also provides a servlet which connects to the JMX interface and returns a status report for the database as XML. By default, this servlet listens on:

http://localhost:8080/exist/status

For example, to get a report on current memory usage and running instances, use the following URL:

http://localhost:8080/exist/status?c=memory&c=instances

The JMX information is only accessible via the HTTP interface when either:

  • the client accesses the API on localhost

  • a valid token is provided when accessing the API from a remote IP address. A file containing this token and an example of its use can be found in the eXist data directory at $EXIST_HOME/data/jmxservlet.token.

Consider using a web proxy if you wish to provide this service separately from other eXist applications.

This returns something like:

<jmx:jmx xmlns:jmx="http://exist-db.org/jmx">
  <jmx:MemoryImpl name="java.lang:type=Memory">
    <jmx:HeapMemoryUsage>
      <jmx:committed>
        128647168
      </jmx:committed>
      <jmx:init>
        134217728
      </jmx:init>
      <jmx:max>
        1908932608
      </jmx:max>
      <jmx:used>
        34854528
      </jmx:used>
    </jmx:HeapMemoryUsage>
    <jmx:NonHeapMemoryUsage>
      <jmx:committed>
        42008576
      </jmx:committed>
      <jmx:init>
        24313856
      </jmx:init>
      <jmx:max>
        138412032
      </jmx:max>
      <jmx:used>
        40648936
      </jmx:used>
    </jmx:NonHeapMemoryUsage>
    <jmx:ObjectPendingFinalizationCount>
      0
    </jmx:ObjectPendingFinalizationCount>
    <jmx:Verbose>
      false
    </jmx:Verbose>
  </jmx:MemoryImpl>
  <jmx:Database name="org.exist.management.exist:type=Database">
    <jmx:ReservedMem>
      671455641
    </jmx:ReservedMem>
    <jmx:ActiveBrokers>
      0
    </jmx:ActiveBrokers>
    <jmx:InstanceId>
      exist
    </jmx:InstanceId>
    <jmx:MaxBrokers>
      2
    </jmx:MaxBrokers>
    <jmx:AvailableBrokers>
      2
    </jmx:AvailableBrokers>
    <jmx:ActiveBrokersMap/>
    <jmx:CacheMem>
      268435456
    </jmx:CacheMem>
    <jmx:CollectionCacheMem>
      25165824
    </jmx:CollectionCacheMem>
  </jmx:Database>
</jmx:jmx>

The different JMX objects in eXist are organized into categories. One or more categories can be passed to the servlet in the URL parameter c. The following categories are recognized:

memory

current memory consumption of the Java virtual machine

instances

general information about the db instance, active db broker objects etc.

disk

Contains current hard disk usage of the database files.

system

Contains system information, such as the running eXist version.

caches

Contains statistics on eXist's internal caches.

locking

Contains current information on collection and resource locks of running operations.

sanity

Feedback from the latest sanity check or ping request (see below).

all

Dumps all known JMX objects in eXist's namespace.

Testing responsiveness using "ping"

This servlet also implements a simple "ping" operation. Ping will first try to obtain an internal database broker object. If the db is under very high load or deadlocked, it will run out of broker objects and ping will not be able to obtain one within a certain time. This is an indication that the database has become unresponsive for requests. If a broker object could be obtained, the servlet will run a simple XQuery to test the availability of the XQuery engine.

To run a "ping", call the servlet with parameter operation=ping. The operation accepts an optional timeout parameter, t=timeout-in-ms.

For example, the following URL starts a ping with a timeout of 2 seconds:

http://localhost:8080/exist/status?operation=ping&t=2000

If the ping returns within the specified timeout, the servlet returns the attributes of the SanityReport JMX bean, which will include an element <jmx:Status>PING_OK</jmx:Status>:

<jmx:jmx xmlns:jmx="http://exist-db.org/jmx">
  <jmx:SanityReport name="org.exist.management.exist.tasks:type=SanityReport">
    <jmx:Status>
      PING_OK
    </jmx:Status>
    <jmx:LastCheckEnd/>
    <jmx:LastCheckStart/>
    <jmx:ActualCheckStart/>
    <jmx:LastActionInfo>
      Ping
    </jmx:LastActionInfo>
    <jmx:PingTime>
      39
    </jmx:PingTime>
    <jmx:Errors/>
  </jmx:SanityReport>
</jmx:jmx>

If the ping takes longer than the timeout, you'll instead find an element <jmx:error> in the returned XML. In this case, additional information on running queries, memory consumption and database locks will be provided:

<jmx:jmx xmlns:jmx="http://exist-db.org/jmx">
  <jmx:error>
    no response on ping after 2000ms
  </jmx:error>
  <jmx:SanityReport name="org.exist.management.exist.tasks:type=SanityReport">
    <jmx:Status>
      PING_WAIT
    </jmx:Status>
    <jmx:LastCheckEnd/>
    <jmx:LastCheckStart/>
    <jmx:ActualCheckStart/>
    <jmx:LastActionInfo>
      Ping
    </jmx:LastActionInfo>
    <jmx:PingTime>
      -1
    </jmx:PingTime>
    <jmx:Errors/>
  </jmx:SanityReport>
  ...
</jmx:jmx>