INT-3651: JMX Improvements Documentation
JIRA: https://jira.spring.io/browse/INT-3651 - Add documentation for the new JMX environment - Add the ability to customize the default metrics implementations - Fix LifecycleMessageHandlerMetrics to get a custom `MessageHandlerMetrics` - Add an escape to the bean pattern matcher to handle beans starting with `!` INT-3651: More Docs/Polishing * JavaDocs polishing * Change `jmx.xml` to describe `public void stopActiveComponents(long howLong)` not that removed with `boolean force`
This commit is contained in:
committed by
Artem Bilan
parent
40c4cb0d41
commit
134c7c870b
@@ -25,8 +25,7 @@ import org.springframework.integration.support.management.MetricsContext;
|
||||
import org.springframework.integration.support.management.Statistics;
|
||||
|
||||
/**
|
||||
* Registers all message channels, and accumulates statistics about their performance. The statistics are then published
|
||||
* locally for other components to consume and publish remotely.
|
||||
* Default implementation; use the full constructor to customize the moving averages.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Helena Edelson
|
||||
@@ -43,17 +42,13 @@ public class DefaultMessageChannelMetrics extends AbstractMessageChannelMetrics
|
||||
|
||||
public static final int DEFAULT_MOVING_AVERAGE_WINDOW = 10;
|
||||
|
||||
private final ExponentialMovingAverage sendDuration = new ExponentialMovingAverage(
|
||||
DEFAULT_MOVING_AVERAGE_WINDOW, 1000000.);
|
||||
private final ExponentialMovingAverage sendDuration;
|
||||
|
||||
private final ExponentialMovingAverageRate sendErrorRate = new ExponentialMovingAverageRate(
|
||||
ONE_SECOND_SECONDS, ONE_MINUTE_SECONDS, DEFAULT_MOVING_AVERAGE_WINDOW, true);
|
||||
private final ExponentialMovingAverageRate sendErrorRate;
|
||||
|
||||
private final ExponentialMovingAverageRatio sendSuccessRatio = new ExponentialMovingAverageRatio(
|
||||
ONE_MINUTE_SECONDS, DEFAULT_MOVING_AVERAGE_WINDOW, true);
|
||||
private final ExponentialMovingAverageRatio sendSuccessRatio;
|
||||
|
||||
private final ExponentialMovingAverageRate sendRate = new ExponentialMovingAverageRate(
|
||||
ONE_SECOND_SECONDS, ONE_MINUTE_SECONDS, DEFAULT_MOVING_AVERAGE_WINDOW, true);
|
||||
private final ExponentialMovingAverageRate sendRate;
|
||||
|
||||
private final AtomicLong sendCount = new AtomicLong();
|
||||
|
||||
@@ -64,11 +59,43 @@ public class DefaultMessageChannelMetrics extends AbstractMessageChannelMetrics
|
||||
protected final AtomicLong receiveErrorCount = new AtomicLong();
|
||||
|
||||
public DefaultMessageChannelMetrics() {
|
||||
super(null);
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an instance with default metrics with {@code window=10, period=1 second,
|
||||
* lapsePeriod=1 minute}.
|
||||
* @param name the name.
|
||||
*/
|
||||
public DefaultMessageChannelMetrics(String name) {
|
||||
this(name, new ExponentialMovingAverage(DEFAULT_MOVING_AVERAGE_WINDOW, 1000000.),
|
||||
new ExponentialMovingAverageRate(
|
||||
ONE_SECOND_SECONDS, ONE_MINUTE_SECONDS, DEFAULT_MOVING_AVERAGE_WINDOW, true),
|
||||
new ExponentialMovingAverageRatio(
|
||||
ONE_MINUTE_SECONDS, DEFAULT_MOVING_AVERAGE_WINDOW, true),
|
||||
new ExponentialMovingAverageRate(
|
||||
ONE_SECOND_SECONDS, ONE_MINUTE_SECONDS, DEFAULT_MOVING_AVERAGE_WINDOW, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an instance with the supplied metrics. For proper representation of metrics, the
|
||||
* supplied sendDuration must have a {@code factor=1000000.} and the the other arguments
|
||||
* must be created with the {@code millis} constructor argument set to true.
|
||||
* @param name the name.
|
||||
* @param sendDuration an {@link ExponentialMovingAverage} for calculating the send duration.
|
||||
* @param sendErrorRate an {@link ExponentialMovingAverageRate} for calculating the send error rate.
|
||||
* @param sendSuccessRatio an {@link ExponentialMovingAverageRatio} for calculating the success ratio.
|
||||
* @param sendRate an {@link ExponentialMovingAverageRate} for calculating the send rate.
|
||||
* @since 4.2
|
||||
*/
|
||||
public DefaultMessageChannelMetrics(String name, ExponentialMovingAverage sendDuration,
|
||||
ExponentialMovingAverageRate sendErrorRate, ExponentialMovingAverageRatio sendSuccessRatio,
|
||||
ExponentialMovingAverageRate sendRate) {
|
||||
super(name);
|
||||
this.sendDuration = sendDuration;
|
||||
this.sendErrorRate = sendErrorRate;
|
||||
this.sendSuccessRatio = sendSuccessRatio;
|
||||
this.sendRate = sendRate;
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
|
||||
@@ -58,13 +58,13 @@ public abstract class AbstractMessageHandlerMetrics implements ConfigurableMetri
|
||||
/**
|
||||
* Begin a handle event.
|
||||
* @param message the message to handle.
|
||||
* @return the context.
|
||||
* @return the context to be used in the {@link #afterHandle(MetricsContext, boolean)}.
|
||||
*/
|
||||
public abstract MetricsContext beforeHandle(Message<?> message);
|
||||
|
||||
/**
|
||||
* End a handle event
|
||||
* @param context the context.
|
||||
* @param context the context from the previous {@link #beforeHandle(Message)}.
|
||||
* @param success true for success, false otherwise.
|
||||
*/
|
||||
public abstract void afterHandle(MetricsContext context, boolean success);
|
||||
|
||||
@@ -24,6 +24,8 @@ import org.springframework.integration.support.management.Statistics;
|
||||
import org.springframework.messaging.Message;
|
||||
|
||||
/**
|
||||
* Default implementation; use the full constructor to customize the moving averages.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Gary Russell
|
||||
* @since 2.0
|
||||
@@ -39,17 +41,32 @@ public class DefaultMessageHandlerMetrics extends AbstractMessageHandlerMetrics
|
||||
|
||||
private final AtomicLong errorCount = new AtomicLong();
|
||||
|
||||
private final ExponentialMovingAverage duration = new ExponentialMovingAverage(DEFAULT_MOVING_AVERAGE_WINDOW,
|
||||
1000000.);
|
||||
private final ExponentialMovingAverage duration;
|
||||
|
||||
public DefaultMessageHandlerMetrics() {
|
||||
super(null);
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an instance with the default moving average window (10).
|
||||
* @param name the name.
|
||||
*/
|
||||
public DefaultMessageHandlerMetrics(String name) {
|
||||
super(name);
|
||||
this(name, new ExponentialMovingAverage(DEFAULT_MOVING_AVERAGE_WINDOW, 1000000.));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an instance with the supplied {@link ExponentialMovingAverage} calculating
|
||||
* the duration of processing by the message handler (and any downstream synchronous
|
||||
* endpoints).
|
||||
* @param name the name.
|
||||
* @param duration an {@link ExponentialMovingAverage} for calculating the duration.
|
||||
* @since 4.2
|
||||
*/
|
||||
public DefaultMessageHandlerMetrics(String name, ExponentialMovingAverage duration) {
|
||||
super(name);
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetricsContext beforeHandle(Message<?> message) {
|
||||
|
||||
@@ -105,7 +105,7 @@ public class ExponentialMovingAverageRate {
|
||||
|
||||
/**
|
||||
* Add a new event to the series at time t.
|
||||
* @param t a new event to the series in milliseconds.
|
||||
* @param t a new event to the series (System.nanoTime()).
|
||||
*/
|
||||
public synchronized void increment(long t) {
|
||||
if (this.times.size() == this.retention) {
|
||||
|
||||
@@ -92,7 +92,7 @@ public class ExponentialMovingAverageRatio {
|
||||
|
||||
/**
|
||||
* Add a new event with successful outcome at time t.
|
||||
* @param t the time in milliseconds.
|
||||
* @param t the System.nanoTime().
|
||||
*/
|
||||
public void success(long t) {
|
||||
append(1, t);
|
||||
|
||||
@@ -915,6 +915,9 @@ public class IntegrationMBeanExporter extends MBeanExporter implements BeanPostP
|
||||
reverse = true;
|
||||
patternToUse = pattern.substring(1);
|
||||
}
|
||||
else if (pattern.startsWith("\\")) {
|
||||
patternToUse = pattern.substring(1);
|
||||
}
|
||||
if (PatternMatchUtils.simpleMatch(patternToUse, name)) {
|
||||
return !reverse;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
package org.springframework.integration.monitor;
|
||||
|
||||
import org.springframework.context.Lifecycle;
|
||||
import org.springframework.integration.handler.management.AbstractMessageHandlerMetrics;
|
||||
import org.springframework.integration.handler.management.MessageHandlerMetrics;
|
||||
import org.springframework.integration.support.management.ConfigurableMetricsAware;
|
||||
import org.springframework.integration.support.management.IntegrationManagedResource;
|
||||
import org.springframework.integration.support.management.Statistics;
|
||||
import org.springframework.jmx.export.annotation.ManagedAttribute;
|
||||
@@ -32,7 +34,8 @@ import org.springframework.jmx.export.annotation.ManagedOperation;
|
||||
* @since 2.0
|
||||
*/
|
||||
@IntegrationManagedResource
|
||||
public class LifecycleMessageHandlerMetrics implements MessageHandlerMetrics, Lifecycle {
|
||||
public class LifecycleMessageHandlerMetrics implements MessageHandlerMetrics, Lifecycle,
|
||||
ConfigurableMetricsAware<AbstractMessageHandlerMetrics> {
|
||||
|
||||
private final Lifecycle lifecycle;
|
||||
|
||||
@@ -44,6 +47,14 @@ public class LifecycleMessageHandlerMetrics implements MessageHandlerMetrics, Li
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void configureMetrics(AbstractMessageHandlerMetrics metrics) {
|
||||
if (this.delegate instanceof ConfigurableMetricsAware) {
|
||||
((ConfigurableMetricsAware<AbstractMessageHandlerMetrics>) this.delegate).configureMetrics(metrics);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ManagedAttribute
|
||||
public boolean isRunning() {
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
object-naming-strategy="keyNamer"
|
||||
counts-enabled="foo, !baz, ba*"
|
||||
stats-enabled="fiz, buz"
|
||||
managed-components="\!excluded, f*, b*, q*, t*"
|
||||
metrics-factory="mf" />
|
||||
|
||||
<util:properties id="appProperties">
|
||||
@@ -43,6 +44,10 @@
|
||||
|
||||
<si:channel id="buz" />
|
||||
|
||||
<bean id="mf" class="org.springframework.integration.monitor.DefaultMetricsFactory" />
|
||||
<si:channel id="!excluded" />
|
||||
|
||||
<si:transformer id="transformer" input-channel="foo" expression="payload" />
|
||||
|
||||
<bean id="mf" class="org.springframework.integration.jmx.config.MBeanExporterParserTests$CustomMetrics" />
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -31,9 +31,17 @@ import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.integration.channel.management.AbstractMessageChannelMetrics;
|
||||
import org.springframework.integration.channel.management.DefaultMessageChannelMetrics;
|
||||
import org.springframework.integration.channel.management.MessageChannelMetrics;
|
||||
import org.springframework.integration.handler.management.AbstractMessageHandlerMetrics;
|
||||
import org.springframework.integration.handler.management.DefaultMessageHandlerMetrics;
|
||||
import org.springframework.integration.handler.management.MessageHandlerMetrics;
|
||||
import org.springframework.integration.monitor.IntegrationMBeanExporter;
|
||||
import org.springframework.integration.monitor.MetricsFactory;
|
||||
import org.springframework.integration.support.management.ExponentialMovingAverage;
|
||||
import org.springframework.integration.support.management.ExponentialMovingAverageRate;
|
||||
import org.springframework.integration.support.management.ExponentialMovingAverageRatio;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
@@ -68,6 +76,9 @@ public class MBeanExporterParserTests {
|
||||
MessageChannelMetrics metrics = context.getBean("foo", MessageChannelMetrics.class);
|
||||
assertTrue(metrics.isCountsEnabled());
|
||||
assertFalse(metrics.isStatsEnabled());
|
||||
checkCustomized(metrics);
|
||||
MessageHandlerMetrics handlerMetrics = context.getBean("transformer.handler", MessageHandlerMetrics.class);
|
||||
checkCustomized(handlerMetrics);
|
||||
metrics = context.getBean("bar", MessageChannelMetrics.class);
|
||||
assertTrue(metrics.isCountsEnabled());
|
||||
assertFalse(metrics.isStatsEnabled());
|
||||
@@ -83,9 +94,57 @@ public class MBeanExporterParserTests {
|
||||
metrics = context.getBean("buz", MessageChannelMetrics.class);
|
||||
assertTrue(metrics.isCountsEnabled());
|
||||
assertTrue(metrics.isStatsEnabled());
|
||||
metrics = context.getBean("!excluded", MessageChannelMetrics.class);
|
||||
assertFalse(metrics.isCountsEnabled());
|
||||
assertFalse(metrics.isStatsEnabled());
|
||||
checkCustomized(metrics);
|
||||
MetricsFactory factory = context.getBean(MetricsFactory.class);
|
||||
assertSame(factory, TestUtils.getPropertyValue(exporter, "metricsFactory"));
|
||||
exporter.destroy();
|
||||
}
|
||||
|
||||
private void checkCustomized(MessageChannelMetrics metrics) {
|
||||
assertEquals(20, TestUtils.getPropertyValue(metrics, "channelMetrics.sendDuration.window"));
|
||||
assertEquals(1000000., TestUtils.getPropertyValue(metrics, "channelMetrics.sendDuration.factor", Double.class),
|
||||
.01);
|
||||
assertEquals(30, TestUtils.getPropertyValue(metrics, "channelMetrics.sendErrorRate.window"));
|
||||
assertEquals(2000000.,
|
||||
TestUtils.getPropertyValue(metrics, "channelMetrics.sendErrorRate.period", Double.class), .01);
|
||||
assertEquals(.001 / 120000,
|
||||
TestUtils.getPropertyValue(metrics, "channelMetrics.sendErrorRate.lapse", Double.class), .01);
|
||||
|
||||
assertEquals(40, TestUtils.getPropertyValue(metrics, "channelMetrics.sendSuccessRatio.window"));
|
||||
assertEquals(.001 / 130000, TestUtils.getPropertyValue(metrics, "channelMetrics.sendRate.lapse", Double.class),
|
||||
.01);
|
||||
|
||||
assertEquals(50, TestUtils.getPropertyValue(metrics, "channelMetrics.sendRate.window"));
|
||||
assertEquals(3000000., TestUtils.getPropertyValue(metrics, "channelMetrics.sendRate.period", Double.class), .01);
|
||||
assertEquals(.001 / 140000, TestUtils.getPropertyValue(metrics, "channelMetrics.sendRate.lapse", Double.class),
|
||||
.01);
|
||||
}
|
||||
|
||||
private void checkCustomized(MessageHandlerMetrics metrics) {
|
||||
assertEquals(20, TestUtils.getPropertyValue(metrics, "handlerMetrics.duration.window"));
|
||||
assertEquals(1000000., TestUtils.getPropertyValue(metrics, "handlerMetrics.duration.factor", Double.class),
|
||||
.01);
|
||||
}
|
||||
|
||||
public static class CustomMetrics implements MetricsFactory {
|
||||
|
||||
@Override
|
||||
public AbstractMessageChannelMetrics createChannelMetrics(String name) {
|
||||
return new DefaultMessageChannelMetrics(name,
|
||||
new ExponentialMovingAverage(20, 1000000.),
|
||||
new ExponentialMovingAverageRate(2000, 120000, 30, true),
|
||||
new ExponentialMovingAverageRatio(130000, 40, true),
|
||||
new ExponentialMovingAverageRate(3000, 140000, 50, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractMessageHandlerMetrics createHandlerMetrics(String name) {
|
||||
return new DefaultMessageHandlerMetrics(name, new ExponentialMovingAverage(20, 1000000.));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -248,20 +248,6 @@
|
||||
<bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean">
|
||||
<property name="locateExistingServerIfPossible" value="true"/>
|
||||
</bean>]]></programlisting>
|
||||
<para>
|
||||
Once the exporter is defined, start up your application with:
|
||||
</para>
|
||||
<screen> -Dcom.sun.management.jmxremote
|
||||
-Dcom.sun.management.jmxremote.port=6969
|
||||
-Dcom.sun.management.jmxremote.ssl=false
|
||||
-Dcom.sun.management.jmxremote.authenticate=false</screen>
|
||||
<para>
|
||||
Then start JConsole (free with the JDK), and connect to the local process on
|
||||
<literal>localhost:6969</literal> to get a look at the management
|
||||
endpoints exposed. (The port and client are just examples to get you
|
||||
started quickly, there are other JMX clients available and some offer more
|
||||
sophisticated features than JConsole.)
|
||||
</para>
|
||||
|
||||
<important>
|
||||
<para>
|
||||
@@ -441,7 +427,7 @@ public class ContextConfiguration {
|
||||
cases there are some metrics that are simple counters (message
|
||||
count and error count), and some that are estimates of averages
|
||||
of interesting quantities. The algorithms used to calculate these
|
||||
estimates are described briefly in the table below:
|
||||
estimates are described briefly in the section below.
|
||||
</para>
|
||||
|
||||
<table>
|
||||
@@ -462,17 +448,25 @@ public class ContextConfiguration {
|
||||
<row>
|
||||
<entry>Count</entry>
|
||||
<entry>Send Count</entry>
|
||||
<entry>Simple incrementer. Increase by one when an event
|
||||
<entry>Simple incrementer. Increases by one when an event
|
||||
occurs.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Error Count</entry>
|
||||
<entry>Send Error Count</entry>
|
||||
<entry>
|
||||
Simple incrementer. Increases by one when an send results
|
||||
in an error.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Duration</entry>
|
||||
<entry>Send Duration (method execution time in
|
||||
milliseconds)
|
||||
</entry>
|
||||
<entry>Exponential Moving Average with decay factor 10. Average
|
||||
of the method execution time over roughly the last 10
|
||||
<entry>Exponential Moving Average with decay factor (10 by default). Average
|
||||
of the method execution time over roughly the last 10 (default)
|
||||
measurements.
|
||||
</entry>
|
||||
</row>
|
||||
@@ -480,23 +474,97 @@ public class ContextConfiguration {
|
||||
<entry>Rate</entry>
|
||||
<entry>Send Rate (number of operations per second)</entry>
|
||||
<entry>Inverse of Exponential Moving Average of the interval
|
||||
between events with decay in time (lapsing over 60 seconds) and
|
||||
per measurement (last 10 events).
|
||||
between events with decay in time (lapsing over 60 seconds
|
||||
by default) and per measurement (last 10 events by default).
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Error Rate</entry>
|
||||
<entry>Send Error Rate (number of errors per second)</entry>
|
||||
<entry>Inverse of Exponential Moving Average of the interval
|
||||
between error events with decay in time (lapsing over 60 seconds
|
||||
by default) and per measurement (last 10 events by default).
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Ratio</entry>
|
||||
<entry>Send Error Ratio (ratio of errors to total sends)</entry>
|
||||
<entry>Send Success Ratio (ratio of successful to total sends)</entry>
|
||||
<entry>Estimate the success ratio as the Exponential Moving
|
||||
Average of the series composed of values 1 for success and 0 for
|
||||
failure (decaying as per the rate measurement over time and
|
||||
events). Error ratio is 1 - success ratio.
|
||||
events by default). Error ratio is 1 - success ratio.
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</section>
|
||||
<section id="jmx-handler-features">
|
||||
<title>MessageHandler MBean Features</title>
|
||||
|
||||
<para>
|
||||
The following table shows the statistics maintained for message
|
||||
handlers. Some metrics are simple counters (message
|
||||
count and error count), and one is an estimate of averages
|
||||
of send duration. The algorithms used to calculate these
|
||||
estimates are described briefly in the table below:
|
||||
</para>
|
||||
|
||||
<table>
|
||||
<title />
|
||||
|
||||
<tgroup cols="3">
|
||||
<colspec colnum="1" colname="col1" colwidth="1*"/>
|
||||
<colspec colnum="2" colname="col2" colwidth="1.5*"/>
|
||||
<colspec colnum="3" colname="col3" colwidth="3*"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry align="center">Metric Type</entry>
|
||||
<entry align="center">Example</entry>
|
||||
<entry align="center">Algorithm</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>Count</entry>
|
||||
<entry>Handle Count</entry>
|
||||
<entry>Simple incrementer. Increases by one when an event
|
||||
occurs.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Error Count</entry>
|
||||
<entry>Handler Error Count</entry>
|
||||
<entry>
|
||||
Simple incrementer. Increases by one when an invocation results
|
||||
in an error.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Active Count</entry>
|
||||
<entry>Handler Active Count</entry>
|
||||
<entry>
|
||||
Indicates the number of currently active threads currently invoking
|
||||
the handler (or any downstream synchronous flow).
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>Duration</entry>
|
||||
<entry>Handle Duration (method execution time in
|
||||
milliseconds)
|
||||
</entry>
|
||||
<entry>Exponential Moving Average with decay factor (10 by default). Average
|
||||
of the method execution time over roughly the last 10 (default)
|
||||
measurements.
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section id="jmx-statistics">
|
||||
<title>Time-Based Average Estimates</title>
|
||||
<para>
|
||||
A feature of the time-based average estimates is that they decay
|
||||
with time if no new measurements arrive. To help interpret the behaviour
|
||||
@@ -534,6 +602,267 @@ public class ContextConfiguration {
|
||||
seconds).
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="jmx-42-improvements">
|
||||
<title>JMX Improvements</title>
|
||||
<para>
|
||||
<emphasis>Version 4.2</emphasis> introduced some important improvements, representing
|
||||
a fairly major overhaul to the JMX support in the framework. These resulted in a
|
||||
significant performance improvement of the JMX statistics collection and
|
||||
much more control thereof, but has some
|
||||
implications for user code in a few specific (uncommon) situations. These
|
||||
changes are detailed below, with a <emphasis role="bold">caution</emphasis> where
|
||||
necessary.
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><emphasis role="bold">Metrics Capture</emphasis></para>
|
||||
<para>
|
||||
Previously, <classname>MessageSource</classname>, <classname>MessageChannel</classname>
|
||||
and <classname>MessageHandler</classname> metrics were captured by wrapping
|
||||
the object in a JDK dynamic proxy to intercept appropriate method calls and
|
||||
capture the statistics. The proxy was added when an integration MBean exporter
|
||||
was declared in the context.
|
||||
</para>
|
||||
<para>
|
||||
Now, the statistics are captured by the beans themselves; but they are still enabled
|
||||
(by default) only if the integration MBean exporter is declared.
|
||||
</para>
|
||||
<caution>
|
||||
This change means that you no longer automatically get an MBean or statistics for custom
|
||||
<interfacename>MessageHandler</interfacename> implementations, unless those custom
|
||||
handlers extend <classname>AbstractMessageHandler</classname>. The simplest
|
||||
way to resolve this is to extend <classname>AbstractMessageHandler</classname>.
|
||||
If that's not possible, or desired, another work-around is to implement the
|
||||
<interfacename>MessageHandlerMetrics</interfacename> interface. For convenience,
|
||||
a <classname>DefaultMessageHandlerMetrics</classname> is provided to capture
|
||||
and report statistics. Invoke the <code>beforeHandle</code> and
|
||||
<code>afterHandle</code>at the appropriate times. Your
|
||||
<interface>MessageHandlerMetrics</interface> methods can then delegate to this
|
||||
object to obtain each statistic. Similarly, <interface>MessageSource</interface>
|
||||
implementations must extend <classname>AbstractMessageSource</classname>
|
||||
or implement <interfacename>MessageSourceMetrics</interfacename>. Message sources
|
||||
only capture a count so there is no provided convenience class; simply maintain
|
||||
the count in an <classname>AtomicLong</classname> field.
|
||||
</caution>
|
||||
<para>
|
||||
The removal of the proxy has two additional benefits; 1) stack traces in
|
||||
exceptions are reduced (when JMX is enabled) because the proxy is not on the
|
||||
stack; 2) cases where 2 MBeans were exported for the same bean now only
|
||||
export a single MBean with consolidated attributes/operations (see the MBean
|
||||
consolidation bullet below).
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><emphasis role="bold">Resolution</emphasis></para>
|
||||
<para>
|
||||
<code>System.nanoTime()</code> is now used to capture times instead of
|
||||
<code>System.currentTimeMillis()</code>. This may provide more accuracy on
|
||||
some JVMs, espcially when durations of less than 1 millisecond are expected
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><emphasis role="bold">Setting Initial Statistics Collection State</emphasis></para>
|
||||
<para>
|
||||
Previously, when JMX was enabled, all sources, channels, handlers captured
|
||||
statistics. It is now possible to control whether the statisics are enabled
|
||||
on an individual component. Further, it is possible to capture simple counts
|
||||
on <interfacename>MessageChannel</interfacename>s and
|
||||
<interfacename>MessageHandler</interfacename>s instead of the complete
|
||||
time-based statistics. This can have significant performance implications
|
||||
because you can selectively configure where you need detailed statistics,
|
||||
as well as enable/disable at runtime. Also see the bullet below about
|
||||
setting initial collection state.
|
||||
</para>
|
||||
<para>
|
||||
Two new attributes have been added to the <code><int-jmx:mbean-exporter/></code>.
|
||||
<code>counts-enabled</code> is a list of bean name patterns where simple message counts
|
||||
will be enabled. <code>stats-enabled</code> is a list of bean name patterns where full
|
||||
time-based statistics will be enabled. These are initial settings only and each component
|
||||
can have its settings changed at runtime, using JMX or a <control-bus/> using the
|
||||
<code>enableCounts()</code> and <code>enableStats()</code> operations.
|
||||
<emphasis role="bold">Note:</emphasis> stats is a superset of counts, enabling stats
|
||||
will enable counts (this is true for the initial setting via the patterns and at
|
||||
runtime). Disabling counts at runtime will also disable stats.
|
||||
</para>
|
||||
<para>
|
||||
A pattern can be negated by preceding it with <code>!</code>; patterns are evaluated
|
||||
left to right; the first match (positive or negative) wins and the remaining
|
||||
patterns won't be evaluated against that bean. If your bean name begins with
|
||||
<code>!</code>, the <code>!</code> in the pattern can be escaped. <code>"\!foo"</code>
|
||||
will positively match a bean named <code>"!foo"</code>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><emphasis role="bold">@IntegrationManagedResource</emphasis></para>
|
||||
<para>
|
||||
Similar to the <classname>@ManagedResource</classname> annotation, the
|
||||
<classname>@IntegrationManagedResource</classname> marks a class as eligible
|
||||
to be exported as an MBean; however, it will only be exported if there is
|
||||
an <classname>IntegrationMBeanExporter</classname> in the application
|
||||
context.
|
||||
</para>
|
||||
<para>
|
||||
Certain Spring Integration classes (in the <code>org.springframework.integration</code>)
|
||||
package) that were previously annotated with
|
||||
<classname>@ManagedResource</classname> are now annotated with both
|
||||
<classname>@ManagedResource</classname> and
|
||||
<classname>@IntegrationManagedResource</classname>. This is for backwards
|
||||
compatibility (see the next bullet). Such MBeans will be exported by any
|
||||
context <interfacename>MBeanServer</interfacename> <emphasis role="bold"
|
||||
>or</emphasis> an <classname>IntegrationMBeanExporter</classname> (but not
|
||||
both - if both exporters are present, the bean is exported by the
|
||||
integration exporter if the bean matches a <code>managed-components</code>
|
||||
pattern).
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><emphasis role="bold">Consolidated MBeans</emphasis></para>
|
||||
<para>
|
||||
Certain classes within the framework (mapping routers for example) have additional
|
||||
attributes/operations over and above those provided by metrics and
|
||||
<interfacename>Lifecycle</interfacename>. We will use a <classname
|
||||
>Router</classname> as an example here.
|
||||
</para>
|
||||
<para>
|
||||
Previously, beans of these types were exported as two distinct MBeans: 1) the
|
||||
metrics MBean (with an objectName such as: <code
|
||||
>intDomain:type=MessageHandler,name=myRouter,bean=endpoint</code>).
|
||||
This MBean had metrics attributes and metrics/Lifecycle operations.
|
||||
</para>
|
||||
<para>
|
||||
A second MBean (with an objectName such as: <code
|
||||
>ctxDomain:name=org.springframework.integration.config.RouterFactoryBean#0
|
||||
,type=MethodInvokingRouter</code>) was exported with the channel mappings attribute
|
||||
and operations.
|
||||
</para>
|
||||
<para>
|
||||
Now, the attributes and operations are consolidated into a single MBean. The
|
||||
objectName will depend on the exporter. If exported by the integration
|
||||
MBean exporter, the objectName will be, for example: <code
|
||||
>intDomain:type=MessageHandler,name=myRouter,bean=endpoint</code>. If exported
|
||||
by another exporter, the objectName will be, for example: <code
|
||||
>ctxDomain:name=org.springframework.integration.config.RouterFactoryBean#0
|
||||
,type=MethodInvokingRouter</code>. There is no difference between these MBeans (aside from
|
||||
the objectName), except that the statistics will <emphasis role="bold">not</emphasis>
|
||||
be enabled (the attributes will be 0) by exporters other than the integration exporter;
|
||||
statistics can be enabled at runtime using the JMX operations. When exported
|
||||
by the integration MBean exporter, the initial state can be managed as described above.
|
||||
</para>
|
||||
<caution>
|
||||
If you are currently using the second MBean to change, for example, channel mappings,
|
||||
<emphasis role="bold">and</emphasis> you are using the integration MBean
|
||||
exporter, note that the objectName has changed because of the MBean consolidation.
|
||||
There is no change if you are not using the integration MBean exporter.
|
||||
</caution>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><emphasis role="bold">MBean Exporter Bean Name Patterns</emphasis></para>
|
||||
<para>
|
||||
Previously, the <code>managed-components</code> patterns were inclusive only. If a bean
|
||||
name matched one of the patterns it would be included. Now, the pattern can be
|
||||
negated by prefixing it with <code>!</code>. i.e. <code>"!foo*, foox"</code> will match
|
||||
all beans that don't start with <code>foo</code>, except <code>foox</code>. Patterns
|
||||
are evaluated left to right and the first match (positive or negative) wins and no
|
||||
further patterns are applied.
|
||||
</para>
|
||||
<caution>
|
||||
The addition of this syntax to the pattern causes one possible (although perhaps unlikey)
|
||||
problem. If you have a bean <code>"!foo"</code> <emphasis role="bold">and</emphasis>
|
||||
you included a pattern <code>"!foo"</code> in your MBean exporter's
|
||||
<code>managed-components</code> patterns; it will no long match; the pattern will now match all
|
||||
beans <emphasis role="bold">not</emphasis> named <code>foo</code>. In this case, you
|
||||
can escape the <code>!</code> in the pattern with <code>\</code>. The pattern
|
||||
<code>"\!foo"</code> means match a bean named <code>"!foo"</code>.
|
||||
</caution>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><emphasis role="bold">Replacing the Default Channel/Handler Statistics</emphasis></para>
|
||||
<para>
|
||||
A new strategy interface <interfacename>MetricsFactory</interfacename> has been introduced
|
||||
allowing you to provide custom channel metrics for your <interfacename>MessageChannel</interfacename>s
|
||||
and <interfacename>MessageHandler</interfacename>s. By default, a
|
||||
<classname>DefaultMetricsFactory</classname> provides default implementation of
|
||||
<interfacename>MessageChannelMetrics</interfacename> and
|
||||
<interfacename>MessageHandlerMetrics</interfacename> which are described in the next bullet.
|
||||
To override the default <interfacename>MetricsFactory</interfacename> use the MBean exporter's
|
||||
<code>metrics-factory</code> attribute to provide a reference to your
|
||||
<interface>MetricsFactory</interface> bean instance. You can either customize the
|
||||
default implementations as described in the next bullet, or provide completely different
|
||||
implementations by overriding <classname>AbstractMessageChannelMetrics</classname>
|
||||
and/or <classname>AbstractMessageHandlerMetrics</classname>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><emphasis role="bold">Customizing the Default Channel/Handler Statistics</emphasis></para>
|
||||
<para>
|
||||
See <xref linkend="jmx-statistics" /> and the Javadocs for the
|
||||
<classname>ExponentialMovingAverage*</classname> classes for more information about these
|
||||
values.
|
||||
</para>
|
||||
<para>
|
||||
By default, the <classname>DefaultMessageChannelMetrics</classname> and
|
||||
<classname>DefaultMessageHandlerMetrics</classname> use a <code>window</code> of
|
||||
10 measurements, a rate period of 1 second (rate per second) and a decay lapse period
|
||||
of 1 minute.
|
||||
</para>
|
||||
<para>
|
||||
If you wish to override these defaults, you can provide a custom
|
||||
<interfacename>MetricsFactory</interfacename> that returns appropriately configured
|
||||
metrics and provide a reference to it to the MBean exporter as described above.
|
||||
</para>
|
||||
<para>
|
||||
Example:
|
||||
</para>
|
||||
<para>
|
||||
<programlisting language="java"><![CDATA[public static class CustomMetrics implements MetricsFactory {
|
||||
|
||||
@Override
|
||||
public AbstractMessageChannelMetrics createChannelMetrics(String name) {
|
||||
return new DefaultMessageChannelMetrics(name,
|
||||
new ExponentialMovingAverage(20, 1000000.),
|
||||
new ExponentialMovingAverageRate(2000, 120000, 30, true),
|
||||
new ExponentialMovingAverageRatio(130000, 40, true),
|
||||
new ExponentialMovingAverageRate(3000, 140000, 50, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractMessageHandlerMetrics createHandlerMetrics(String name) {
|
||||
return new DefaultMessageHandlerMetrics(name, new ExponentialMovingAverage(20, 1000000.));
|
||||
}
|
||||
|
||||
}]]></programlisting>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><emphasis role="bold">Advanced Customization</emphasis></para>
|
||||
<para>
|
||||
The customizations described above are wholesale and will apply to all appropriate
|
||||
beans exported by the MBean exporter. This is the extent of customization available
|
||||
using XML configuration.
|
||||
</para>
|
||||
<para>
|
||||
Individual beans can be provided with different implementations using java
|
||||
<code>@Configuration</code> or programmatically at runtime, after the application
|
||||
context has been refreshed, by invoking the <code>configureMetrics</code> methods
|
||||
on <classname>AbstractMessageChannel</classname> and
|
||||
<classname>AbstractMessageHandler</classname>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><emphasis role="bold">Performance Improvement</emphasis></para>
|
||||
<para>
|
||||
Previously, the time-based metrics (see <xref linkend="jmx-statistics"/>) were
|
||||
calculated in real time. The statistics are now calculated when retrieved instead.
|
||||
This resulted in a significant performance improvement, at the expense of a
|
||||
small amount of additional memory for each statistic. As discussed in the bullet
|
||||
above, the statistics can be disabled altogether, while retaining the MBean
|
||||
allowing the invocation of <interfacename>Lifecycle</interfacename> methods.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section id="jmx-mbean-shutdown">
|
||||
<title>Orderly Shutdown Managed Operation</title>
|
||||
|
||||
@@ -541,7 +870,7 @@ public class ContextConfiguration {
|
||||
The MBean exporter provides a JMX operation to shut down the application
|
||||
in an orderly manner, intended for use before terminating the JVM.
|
||||
</para>
|
||||
<programlisting language="java"><![CDATA[public void stopActiveComponents(boolean force, long howLong)
|
||||
<programlisting language="java"><![CDATA[public void stopActiveComponents(long howLong)
|
||||
]]></programlisting>
|
||||
<para>
|
||||
Its use and operation are described in <xref linkend="jmx-shutdown"/>.
|
||||
|
||||
@@ -11,6 +11,20 @@
|
||||
</para>
|
||||
<section id="4.2-new-components">
|
||||
<title>New Components</title>
|
||||
<section id="4.2-JMX">
|
||||
<title>Major JMX Rework</title>
|
||||
<para>
|
||||
A new <classname>MetricsFactory</classname> strategy interface has been introduced. This,
|
||||
together with other changes in the JMX infrastructure provides much more control
|
||||
over JMX configuration and runtime performance.
|
||||
</para>
|
||||
<para>
|
||||
However, this has some important implications for (some) user environments.
|
||||
</para>
|
||||
<para>
|
||||
For complete details, see <xref linkend="jmx-42-improvements" />.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
<section id="4.2-general">
|
||||
<title>General Changes</title>
|
||||
|
||||
Reference in New Issue
Block a user