activemq-artemis/docs/user-manual/en/jms-bridge.xml

451 lines
27 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?xml version="1.0" encoding="UTF-8"?>
<!-- ============================================================================= -->
<!-- Copyright © 2009 Red Hat, Inc. and others. -->
<!-- -->
<!-- The text of and illustrations in this document are licensed by Red Hat under -->
<!-- a Creative Commons AttributionShare Alike 3.0 Unported license ("CC-BY-SA"). -->
<!-- -->
<!-- An explanation of CC-BY-SA is available at -->
<!-- -->
<!-- http://creativecommons.org/licenses/by-sa/3.0/. -->
<!-- -->
<!-- In accordance with CC-BY-SA, if you distribute this document or an adaptation -->
<!-- of it, you must provide the URL for the original version. -->
<!-- -->
<!-- Red Hat, as the licensor of this document, waives the right to enforce, -->
<!-- and agrees not to assert, Section 4d of CC-BY-SA to the fullest extent -->
<!-- permitted by applicable law. -->
<!-- ============================================================================= -->
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY % BOOK_ENTITIES SYSTEM "HornetQ_User_Manual.ent">
%BOOK_ENTITIES;
]>
<chapter id="jms-bridge">
<title>The JMS Bridge</title>
<para>HornetQ includes a fully functional JMS message bridge.</para>
<para>The function of the bridge is to consume messages from a source queue or topic, and
send them to a target queue or topic, typically on a different server.</para>
<para>The source and target servers do not have to be in the same cluster which makes
bridging suitable for reliably sending messages from one cluster to another, for
instance across a WAN, and where the connection may be unreliable.</para>
<para>A bridge can be deployed as a standalone application, with HornetQ standalone server or inside a JBoss AS
instance. The source and the target can be located in the same virtual machine or another one.</para>
<para>The bridge can also be used to bridge messages from other non HornetQ JMS servers, as
long as they are JMS 1.1 compliant.<note><para>Do not confuse a JMS bridge with a core
bridge. A JMS bridge can be used to bridge any two JMS 1.1 compliant JMS
providers and uses the JMS API. A core bridge (described in <xref
linkend="core-bridges"/>) is used to bridge any two HornetQ instances and
uses the core API. Always use a core bridge if you can in preference to a JMS
bridge. The core bridge will typically provide better performance than a JMS
bridge. Also the core bridge can provide <emphasis>once and only once</emphasis>
delivery guarantees without using XA.</para></note></para>
<para>The bridge has built-in resilience to failure so if the source or target server
connection is lost, e.g. due to network failure, the bridge will retry connecting to the
source and/or target until they come back online. When it comes back online it will
resume operation as normal.</para>
<para>The bridge can be configured with an optional JMS selector, so it will only consume
messages matching that JMS selector</para>
<para>It can be configured to consume from a queue or a topic. When it consumes from a topic
it can be configured to consume using a non durable or durable subscription</para>
<para>Typically, the bridge is deployed by the JBoss Micro Container via a beans configuration file.
This would typically be deployed inside the JBoss Application Server and the following
example shows an example of a beans file that bridges 2 destinations which are actually
on the same server. </para>
<programlisting>
&lt;?xml version="1.0" encoding="UTF-8"?>
&lt;deployment xmlns="urn:jboss:bean-deployer:2.0">
&lt;bean name="JMSBridge" class="org.apache.activemq.api.jms.bridge.impl.JMSBridgeImpl">
&lt;!-- HornetQ must be started before the bridge -->
&lt;depends>HornetQServer&lt;/depends>
&lt;constructor>
&lt;!-- Source ConnectionFactory Factory -->
&lt;parameter>
&lt;inject bean="SourceCFF"/>
&lt;/parameter>
&lt;!-- Target ConnectionFactory Factory -->
&lt;parameter>
&lt;inject bean="TargetCFF"/>
&lt;/parameter>
&lt;!-- Source DestinationFactory -->
&lt;parameter>
&lt;inject bean="SourceDestinationFactory"/>
&lt;/parameter>
&lt;!-- Target DestinationFactory -->
&lt;parameter>
&lt;inject bean="TargetDestinationFactory"/>
&lt;/parameter>
&lt;!-- Source User Name (no username here) -->
&lt;parameter>&lt;null />&lt;/parameter>
&lt;!-- Source Password (no password here)-->
&lt;parameter>&lt;null />&lt;/parameter>
&lt;!-- Target User Name (no username here)-->
&lt;parameter>&lt;null />&lt;/parameter>
&lt;!-- Target Password (no password here)-->
&lt;parameter>&lt;null />&lt;/parameter>
&lt;!-- Selector -->
&lt;parameter>&lt;null />&lt;/parameter>
&lt;!-- Failure Retry Interval (in ms) -->
&lt;parameter>5000&lt;/parameter>
&lt;!-- Max Retries -->
&lt;parameter>10&lt;/parameter>
&lt;!-- Quality Of Service -->
&lt;parameter>ONCE_AND_ONLY_ONCE&lt;/parameter>
&lt;!-- Max Batch Size -->
&lt;parameter>1&lt;/parameter>
&lt;!-- Max Batch Time (-1 means infinite) -->
&lt;parameter>-1&lt;/parameter>
&lt;!-- Subscription name (no subscription name here)-->
&lt;parameter>&lt;null />&lt;/parameter>
&lt;!-- Client ID (no client ID here)-->
&lt;parameter>&lt;null />&lt;/parameter>
&lt;!-- Add MessageID In Header -->
&lt;parameter>true&lt;/parameter>
&lt;!-- register the JMS Bridge in the AS MBeanServer -->
&lt;parameter>
&lt;inject bean="MBeanServer"/>
&lt;/parameter>
&lt;parameter>org.apache.activemq:service=JMSBridge&lt;/parameter>
&lt;/constructor>
&lt;property name="transactionManager">
&lt;inject bean="RealTransactionManager"/>
&lt;/property>
&lt;/bean>
&lt;!-- SourceCFF describes the ConnectionFactory used to connect to the source destination -->
&lt;bean name="SourceCFF"
class="org.apache.activemq.api.jms.bridge.impl.JNDIConnectionFactoryFactory">
&lt;constructor>
&lt;parameter>
&lt;inject bean="JNDI" />
&lt;/parameter>
&lt;parameter>/ConnectionFactory&lt;/parameter>
&lt;/constructor>
&lt;/bean>
&lt;!-- TargetCFF describes the ConnectionFactory used to connect to the target destination -->
&lt;bean name="TargetCFF"
class="org.apache.activemq.api.jms.bridge.impl.JNDIConnectionFactoryFactory">
&lt;constructor>
&lt;parameter>
&lt;inject bean="JNDI" />
&lt;/parameter>
&lt;parameter>/ConnectionFactory&lt;/parameter>
&lt;/constructor>
&lt;/bean>
&lt;!-- SourceDestinationFactory describes the Destination used as the source -->
&lt;bean name="SourceDestinationFactory" class="org.apache.activemq.api.jms.bridge.impl.JNDIDestinationFactory">
&lt;constructor>
&lt;parameter>
&lt;inject bean="JNDI" />
&lt;/parameter>
&lt;parameter>/queue/source&lt;/parameter>
&lt;/constructor>
&lt;/bean>
&lt;!-- TargetDestinationFactory describes the Destination used as the target -->
&lt;bean name="TargetDestinationFactory" class="org.apache.activemq.api.jms.bridge.impl.JNDIDestinationFactory">
&lt;constructor>
&lt;parameter>
&lt;inject bean="JNDI" />
&lt;/parameter>
&lt;parameter>/queue/target&lt;/parameter>
&lt;/constructor>
&lt;/bean>
&lt;!-- JNDI is a Hashtable containing the JNDI properties required -->
&lt;!-- to connect to the sources and targets JMS resrouces -->
&lt;bean name="JNDI" class="java.util.Hashtable">
&lt;constructor class="java.util.Map">
&lt;map class="java.util.Hashtable" keyClass="String"
valueClass="String">
&lt;entry>
&lt;key>java.naming.factory.initial&lt;/key>
&lt;value>org.jnp.interfaces.NamingContextFactory&lt;/value>
&lt;/entry>
&lt;entry>
&lt;key>java.naming.provider.url&lt;/key>
&lt;value>jnp://localhost:1099&lt;/value>
&lt;/entry>
&lt;entry>
&lt;key>java.naming.factory.url.pkgs&lt;/key>
&lt;value>org.jboss.naming:org.jnp.interfaces"&lt;/value>
&lt;/entry>
&lt;entry>
&lt;key>jnp.timeout&lt;/key>
&lt;value>5000&lt;/value>
&lt;/entry>
&lt;entry>
&lt;key>jnp.sotimeout&lt;/key>
&lt;value>5000&lt;/value>
&lt;/entry>
&lt;/map>
&lt;/constructor>
&lt;/bean>
&lt;bean name="MBeanServer" class="javax.management.MBeanServer">
&lt;constructor factoryClass="org.jboss.mx.util.MBeanServerLocator" factoryMethod="locateJBoss"/>
&lt;/bean>
&lt;/deployment></programlisting>
<section>
<title>JMS Bridge Parameters</title>
<para>The main bean deployed is the <literal>JMSBridge</literal> bean. The bean is
configurable by the parameters passed to its constructor.</para>
<note>
<para>To let a parameter be unspecified (for example, if the authentication is
anonymous or no message selector is provided), use <literal>&lt;null
/></literal> for the unspecified parameter value.</para>
</note>
<itemizedlist>
<listitem>
<para>Source Connection Factory Factory</para>
<para>This injects the <literal>SourceCFF</literal> bean (also defined in the
beans file). This bean is used to create the <emphasis>source</emphasis>
<literal>ConnectionFactory</literal>
</para>
</listitem>
<listitem>
<para>Target Connection Factory Factory</para>
<para>This injects the <literal>TargetCFF</literal> bean (also defined in the
beans file). This bean is used to create the <emphasis>target</emphasis>
<literal>ConnectionFactory</literal>
</para>
</listitem>
<listitem>
<para>Source Destination Factory Factory</para>
<para>This injects the <literal>SourceDestinationFactory</literal> bean (also
defined in the beans file). This bean is used to create the
<emphasis>source</emphasis>
<literal>Destination</literal>
</para>
</listitem>
<listitem>
<para>Target Destination Factory Factory</para>
<para>This injects the <literal>TargetDestinationFactory</literal> bean (also
defined in the beans file). This bean is used to create the
<emphasis>target</emphasis>
<literal>Destination</literal>
</para>
</listitem>
<listitem>
<para>Source User Name</para>
<para>this parameter is the username for creating the
<emphasis>source</emphasis> connection</para>
</listitem>
<listitem>
<para>Source Password</para>
<para>this parameter is the parameter for creating the
<emphasis>source</emphasis> connection</para>
</listitem>
<listitem>
<para>Target User Name</para>
<para>this parameter is the username for creating the
<emphasis>target</emphasis> connection</para>
</listitem>
<listitem>
<para>Target Password</para>
<para>this parameter is the password for creating the
<emphasis>target</emphasis> connection</para>
</listitem>
<listitem>
<para>Selector</para>
<para>This represents a JMS selector expression used for consuming messages from
the source destination. Only messages that match the selector expression
will be bridged from the source to the target destination</para>
<para>The selector expression must follow the <ulink
url="http://docs.oracle.com/javaee/6/api/javax/jms/Message.html">JMS
selector syntax</ulink></para>
</listitem>
<listitem>
<para>Failure Retry Interval</para>
<para>This represents the amount of time in ms to wait between trying to
recreate connections to the source or target servers when the bridge has
detected they have failed</para>
</listitem>
<listitem>
<para>Max Retries</para>
<para>This represents the number of times to attempt to recreate connections to
the source or target servers when the bridge has detected they have failed.
The bridge will give up after trying this number of times. <literal
>-1</literal> represents 'try forever'</para>
</listitem>
<listitem>
<para>Quality Of Service</para>
<para>This parameter represents the desired quality of service mode</para>
<para>Possible values are:</para>
<itemizedlist>
<listitem>
<para><literal>AT_MOST_ONCE</literal></para>
</listitem>
<listitem>
<para><literal>DUPLICATES_OK</literal></para>
</listitem>
<listitem>
<para><literal>ONCE_AND_ONLY_ONCE</literal></para>
</listitem>
</itemizedlist>
<para>See <xref linkend="quality-of-service"/> for a explanation of these
modes.</para>
</listitem>
<listitem>
<para>Max Batch Size</para>
<para>This represents the maximum number of messages to consume from the source
destination before sending them in a batch to the target destination. Its
value must <literal>>= 1</literal>
</para>
</listitem>
<listitem>
<para>Max Batch Time</para>
<para>This represents the maximum number of milliseconds to wait before sending
a batch to target, even if the number of messages consumed has not reached
<literal>MaxBatchSize</literal>. Its value must be <literal>-1</literal>
to represent 'wait forever', or <literal>>= 1</literal> to specify an actual
time </para>
</listitem>
<listitem>
<para>Subscription Name</para>
<para>If the source destination represents a topic, and you want to consume from
the topic using a durable subscription then this parameter represents the
durable subscription name</para>
</listitem>
<listitem>
<para>Client ID</para>
<para>If the source destination represents a topic, and you want to consume from
the topic using a durable subscription then this attribute represents the
the JMS client ID to use when creating/looking up the durable
subscription</para>
</listitem>
<listitem>
<para>Add MessageID In Header</para>
<para>If <literal>true</literal>, then the original message's message ID will be
appended in the message sent to the destination in the header <literal
>HORNETQ_BRIDGE_MSG_ID_LIST</literal>. If the message is bridged more
than once, each message ID will be appended. This enables a distributed
request-response pattern to be used</para>
<note>
<para>when you receive the message you can send back a response using the
correlation id of the first message id, so when the original sender gets
it back it will be able to correlate it. </para>
</note>
</listitem>
<listitem>
<para>MBean Server</para>
<para>To manage the JMS Bridge using JMX, set the MBeanServer where the JMS Bridge MBean
must be registered (e.g. the JVM Platform MBeanServer or JBoss AS MBeanServer)</para>
</listitem>
<listitem>
<para>ObjectName</para>
<para>If you set the MBeanServer, you also need to set the ObjectName used to register
the JMS Bridge MBean (must be unique)</para>
</listitem>
</itemizedlist>
<para>The "transactionManager" property points to a JTA transaction manager implementation.
HornetQ doesn't ship with such an implementation, but one is available in the JBoss
Community. If you are running HornetQ in standalone mode and wish to use a JMS bridge
simply download the latest version of JBossTS from http://www.jboss.org/jbosstm/downloads
and add it to HornetQ's classpath. If you are running HornetQ with JBoss AS then you
won't need to do this as JBoss AS ships with a JTA transaction manager already. The
bean definition for the transaction manager would look something like this:
</para>
<programlisting>&lt;bean name="RealTransactionManager" class="com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionManagerImple"/></programlisting>
</section>
<section>
<title>Source and Target Connection Factories</title>
<para>The source and target connection factory factories are used to create the
connection factory used to create the connection for the source or target
server.</para>
<para>The configuration example above uses the default implementation provided by
HornetQ that looks up the connection factory using JNDI. For other Application
Servers or JMS providers a new implementation may have to be provided. This can
easily be done by implementing the interface <literal
>org.apache.activemq.jms.bridge.ConnectionFactoryFactory</literal>.</para>
</section>
<section>
<title>Source and Target Destination Factories</title>
<para>Again, similarly, these are used to create or lookup up the destinations.</para>
<para>In the configuration example above, we have used the default provided by HornetQ
that looks up the destination using JNDI.</para>
<para>A new implementation can be provided by implementing <literal
>org.apache.activemq.jms.bridge.DestinationFactory</literal> interface.</para>
</section>
<section id="quality-of-service">
<title>Quality Of Service</title>
<para>The quality of service modes used by the bridge are described here in more
detail.</para>
<section>
<title>AT_MOST_ONCE</title>
<para>With this QoS mode messages will reach the destination from the source at most
once. The messages are consumed from the source and acknowledged before sending
to the destination. Therefore there is a possibility that if failure occurs
between removing them from the source and them arriving at the destination they
could be lost. Hence delivery will occur at most once.</para>
<para>This mode is available for both durable and non-durable messages.</para>
</section>
<section>
<title>DUPLICATES_OK</title>
<para>With this QoS mode, the messages are consumed from the source and then
acknowledged after they have been successfully sent to the destination.
Therefore there is a possibility that if failure occurs after sending to the
destination but before acknowledging them, they could be sent again when the
system recovers. I.e. the destination might receive duplicates after a
failure.</para>
<para>This mode is available for both durable and non-durable messages.</para>
</section>
<section>
<title>ONCE_AND_ONLY_ONCE</title>
<para>This QoS mode ensures messages will reach the destination from the source once
and only once. (Sometimes this mode is known as "exactly once"). If both the
source and the destination are on the same HornetQ server instance then this can
be achieved by sending and acknowledging the messages in the same local
transaction. If the source and destination are on different servers this is
achieved by enlisting the sending and consuming sessions in a JTA transaction.
The JTA transaction is controlled by JBoss Transactions JTA * implementation
which is a fully recovering transaction manager, thus providing a very high
degree of durability. If JTA is required then both supplied connection factories
need to be XAConnectionFactory implementations. This is likely to be the slowest
mode since it requires extra persistence for the transaction logging.</para>
<para>This mode is only available for durable messages.</para>
<note>
<para>For a specific application it may possible to provide once and only once
semantics without using the ONCE_AND_ONLY_ONCE QoS level. This can be done
by using the DUPLICATES_OK mode and then checking for duplicates at the
destination and discarding them. Some JMS servers provide automatic
duplicate message detection functionality, or this may be possible to
implement on the application level by maintaining a cache of received
message ids on disk and comparing received messages to them. The cache would
only be valid for a certain period of time so this approach is not as
watertight as using ONCE_AND_ONLY_ONCE but may be a good choice depending on
your specific application.</para>
</note>
</section>
<section>
<title>Time outs and the JMS bridge</title>
<para>There is a possibility that the target or source server will not be available at some point in time.
If this occurs then the bridge will try <literal>Max Retries</literal> to reconnect every
<literal>Failure Retry Interval</literal> milliseconds as specified in the JMS Bridge definition.</para>
<para>However since a third party JNDI is used, in this case the JBoss naming server, it is possible for the
JNDI lookup to hang if the network were to disappear during the JNDI lookup. To stop this from occurring the JNDI
definition can be configured to time out if this occurs. To do this set the <literal>jnp.timeout</literal>
and the <literal>jnp.sotimeout</literal> on the Initial Context definition. The first sets the connection
timeout for the initial connection and the second the read timeout for the socket.</para>
<note>
<para>Once the initial JNDI connection has succeeded all calls are made using RMI. If you want to control
the timeouts for the RMI connections then this can be done via system properties. JBoss uses Sun's RMI
and the properties can be found <ulink
url="http://docs.oracle.com/javase/6/docs/technotes/guides/rmi/sunrmiproperties.html">here</ulink>.
The default connection timeout is 10 seconds and the default read timeout is 18 seconds.</para>
</note>
<para>If you implement your own factories for looking up JMS resources then you will have to bear in mind timeout issues.</para>
</section>
<section>
<title>Examples</title>
<para>Please see <xref linkend="examples.javaee.jms-bridge"/> which shows how to configure
and use a JMS Bridge with JBoss AS to send messages to the source destination and consume them
from the target destination.</para>
<para>Please see <xref linkend="examples.jms.jms-bridge"/> which shows how to configure
and use a JMS Bridge between two standalone HornetQ servers.</para>
</section>
</section>
</chapter>