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

383 lines
24 KiB
XML
Raw Normal View History

<?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. -->
<!-- ============================================================================= -->
<chapter id="jms-bridge">
<title>JMS桥Bridge</title>
<para>HornetQ提供了JMS消息桥服务。</para>
<para>桥的作用是从一个消息源队列或话题topic接收消息然后将它们发送到一个目标队列或话题。通常源和
目的不在同一台服务器上。</para>
<para>作为消息源的服务器与目的服务器不必在同一个集群内。通过桥的作用,两台服务器可以通过非可靠的网络连接
起来比如WAN。</para>
<para>桥可以作为单独的服务部署或者部署于HornetQ单独服务器内或者部署在JBoss应用服务器中。源或目的可以
在同一个VM中也可以在其它的VM中。</para>
<para>桥还可以在HornetQ服务器与其它JMS 1.1 兼容的服务器之间进行消息的传递。
<note><para>还要将JMS桥与核心桥混淆。JMB桥可以连接两个JMS 1.1兼容的服务器它使用的是JMS接口。
而核心桥(在<xref linkend="core-bridges"/>中描述使用核心API将两个HornetQ实例连接
起来。核心桥的性能通常要比JMS桥的性能高所以尽可能使用核心桥。另外核心桥可以不用XA
就可以实现<emphasis>一次并只有一次</emphasis>的消息传递保证。</para></note></para>
<para>桥可以适当处理连接故障。当源的连接或目的的连接发生故障时,例如网络故障,桥将不断重试连接直到连接
恢复为止。当连接恢复后,桥会继续正常工作。</para>
<para>桥还可以有一个可选的JMS选择器它可以使桥只接收选择器选择的消息。</para>
<para>可以配置桥从队列还是从话题中接收消息。如果配置成从话题中接收消息,还以设定是以非持久订阅的方式接收,还是
以持久订阅的方式接收。</para>
<para>通常桥是通过一个bean配置文件由JBoss Micro Container部署到JBoss应用服务器中。下面的就是一
个桥的bean文件例子。这个桥将同一服务器上的两个目标连接起来。</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.activemq6.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.activemq6: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.activemq6.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.activemq6.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.activemq6.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.activemq6.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桥的配置参数</title>
<para>桥的主要的bean是<literal>JMSBridge</literal>。所有的配置参数需要传递给这个bean的
构造函数。</para>
<note>
<para>如果不想指定某个参数的值(例如匿名认证或没有选择器),将该参数设为<literal>&lt;null
/&gt;</literal>即可。</para>
</note>
<itemizedlist>
<listitem>
<para>源连接工厂的工厂Source ConnectionFactory Factory</para>
<para>这个参数注入一个<literal>SourceCFF</literal>bean由bean文件定义。它被
用来创建<emphasis></emphasis><literal>ConnectionFactory</literal>
</para>
</listitem>
<listitem>
<para>目标连接工厂的工厂Target ConnectionFactory Factory</para>
<para>这个参数注入一个<literal>TargetCFF</literal>bean由bean文件定义。它被
用来创建<emphasis>目的</emphasis><literal>ConnectionFactory</literal>
</para>
</listitem>
<listitem>
<para>源目标工厂Source DestinationFactory</para>
<para>这个参数注入一个<literal>SourceDestinationFactory</literal>bean
bean文件定义。它用来创建<emphasis></emphasis>
<literal>目标Destination</literal>
</para>
</listitem>
<listitem>
<para>目的目标工厂Target DestinationFactory</para>
<para>这个参数注入一个<literal>TargetDestinationFactory</literal>bean
bean文件定义。它用来创建<emphasis>目的</emphasis>
<literal>目标Destination</literal>
</para>
</listitem>
<listitem>
<para>源用户名Source User Name</para>
<para>用于创建到<emphasis></emphasis>的连接的用户名</para>
</listitem>
<listitem>
<para>源密码Source Password</para>
<para>用于创建<emphasis></emphasis>连接的密码</para>
</listitem>
<listitem>
<para>目的用户名Target User Name</para>
<para>用于创建<emphasis>目的</emphasis>连接的用户名</para>
</listitem>
<listitem>
<para>目的密码Target Password</para>
<para>t用于创建<emphasis>目的</emphasis>连接的密码</para>
</listitem>
<listitem>
<para>选择器Selector</para>
<para>这是一个JMS的选择器表达式它用于从源目标接收消息。只有与选择器相匹配的消息才会被桥
转发到目的目标</para>
<para>选择器必须符合<ulink
url="http://java.sun.com/j2ee/1.4/docs/api/javax/jms/Message.html">JMS
选择器语法</ulink></para>
</listitem>
<listitem>
<para>故障重试间隔Failure Retry Interval</para>
<para>代表当桥发现连接故障时在每两次重试连接之间所要等待的时间间隔,单位毫秒</para>
</listitem>
<listitem>
<para>最大重试次数Max Retries</para>
<para>表示桥在发现连接故障时所进行的最大重试次数。超过这个次数,桥就放弃重试。
<literal
>-1</literal>代表一直重试下去</para>
</listitem>
<listitem>
<para>服务质量Quality Of Service</para>
<para>这个参数代表所需要的服务质量模式</para>
<para>有效的值为:</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>有关这些模式的解释,参见<xref linkend="quality-of-service"/></para>
</listitem>
<listitem>
<para>最大批量Max Batch Size</para>
<para>表示桥一次性从源目标最多接收多少消息,并将它们一次发往目的地。它的值必须是
<literal>>= 1</literal>
</para>
</listitem>
<listitem>
<para>最大批时间Max Batch Time</para>
<para>代表桥在将一批消息发向目的之前等待的最大毫秒数。这个时间过后,即使接收的消息数小于
<literal>MaxBatchSize</literal>,桥也会开始向目的发送消息。它的值必须是
<literal>-1</literal> (代表永远等待)或<literal>>= 1</literal></para>
</listitem>
<listitem>
<para>订阅名Subscription Name</para>
<para>如果源的目标是一个话题topic你想使用持久的订阅来接收消息的话这个参数可以指定
订阅名。</para>
</listitem>
<listitem>
<para>客户IDClient ID</para>
<para>如果源的目标是一个话题topic你想使用持久的订阅来接收消息的话这个参数可以指定
JMS的客户ID。它用于创建查找持久订阅。</para>
</listitem>
<listitem>
<para>在消息头添加MessageIDAdd MessageID In Header</para>
<para>如果值为<literal>true</literal>原始的消息ID在发往目的是回到消息的名为<literal
>HORNETQ_BRIDGE_MSG_ID_LIST</literal>的头中。如果一个消息被桥转发了多次,
则每次转发的消息ID都添加在这个头中。这用于分布式请求回答的消息模式。</para>
<note>
<para>当收到一个消息时通过它的相关IDcoorelation id可以发送一个回答。这样
在消息发送方得到这个回答消息时,它可以与原消息相关联起来。</para>
</note>
</listitem>
<listitem>
<para>MBean服务器MBean Server</para>
<para>要使用JMX管理JMS桥需指定JMS桥所要注册的MBeanServer如JVM Platform MBeanServer 或
JBoss 应用服务器的MBeanServer</para>
</listitem>
<listitem>
<para>ObjectName</para>
<para>设置了MBeanServer后你还需要设置JMS桥MBean注册用的ObjectName必须是唯一的</para>
</listitem>
</itemizedlist>
</section>
<section>
<title>源和目的的连接工厂</title>
<para>源工目的的连接工厂分别用于创建到源和到目的的连接。</para>
<para>上面的配置例子中使用的是HornetQ提供的默认实现。它使用JNDI查找连接工厂。对于其它的应用服务器
或JMS提供者需要实现相应的实现即实现<literal
>org.apache.activemq6.jms.bridge.ConnectionFactoryFactory</literal>接口。</para>
</section>
<section>
<title>源和目的的目标工厂</title>
<para>它们用来创建或查找相应的目标。</para>
<para>上面例子中我们使用了HornetQ的默认实现从JNDI中查找相应的对象。</para>
<para>要提供新的实现,只要实现接口<literal
>org.apache.activemq6.jms.bridge.DestinationFactory</literal>即可。</para>
</section>
<section id="quality-of-service">
<title>服务质量</title>
<para>下面给是桥的三种服务质量的详细说明。</para>
<section>
<title>AT_MOST_ONCE</title>
<para>这种QoS模式表示的是消息最多送达目标一次。在消息发往目的之前消息就会被通知。因此
如果在消息被源删除但并未到达目的时发生故障,消息有可能丢失。所以说消息的
发送最多一次。 </para>
<para>这个模式适用于持久或非持久的消息。</para>
</section>
<section>
<title>DUPLICATES_OK</title>
<para>在这个QoS模式下消息从源接收后再发送到目的之后才对源进行消息通知。这样如果在发送成功之后
消息通知前的时间内发生故障的话,在故障恢复时同一个消息可能被再次传递。結果可能是在目的处
该消息收到了两次。</para>
<para>这个模式适用于持久或非持久的消息。</para>
</section>
<section>
<title>ONCE_AND_ONLY_ONCE</title>
<para>这个模式保证消息从源发送到目的一次,并且只有一次。(有时这个模式又称为“只一次”)。若源与目的处于
同一个HornetQ服务器中这个模式通过本地事务来保证消息的发送和通知。如果是在不同的服务器上
则会使用一个JTA的事务将发送和接收包括其中。这里使用的JTA事务是JBoss的实现它包含有一个
完整的事务恢复管理器所以能提供高度可靠的持久性。如果使用JTA则桥的所有连接工厂必须是
XAConnectionFactory。这种模式的效率通常是最低的因为它需要额外记录事务的日志。</para>
<para>这个模式只适用于持久性消息。</para>
<note>
<para>某些情况下可以不使用ONCE_AND_ONLY_ONCE模式而同样可以保证“一次且只一次”的效果。
这是通过使用DUPLICATES_OK模式加上在目的端应用程序来检测重复的消息如果有则将其丢弃。
一些JMS服务器本身提供自动重复消息检测的功能这样节省了在应用层实现的工作。在应用层常见
的实现方法是将接收到的消息的ID存放到缓存文件中然后与每个新到的消息进行对比。这种方式
可能在某段时间内有效所以它不如ONCE_AND_ONLY_ONCE那样严格它视具体情况也可能是一个
不错的选择。</para>
</note>
</section>
<section>
<title>JMS bridge中的超时问题</title>
<para>有时候目标服务器或源服务器会连接不上,这里桥就会尝试重新连接。重新连接的次数由<literal>Max Retries</literal>
参数决定,两次重新连接的时间间隔由<literal>Failure Retry Interval</literal>定义。</para>
<para>在重新尝试时会进行JNDI的查找。HornetQ的JNDI使用的是JBoss的实现如果在JNDI查找过程中网络出现故障
查找的操作可能挂起。为了避免这种情况的发生我们可以为JNDI设置适当的超时。这是通过定义初始上下文的
<literal>jnp.timeout</literal>参数和<literal>jnp.sotimeout</literal>参数来
实现的。第一个参数定义了初始连接的超时,第二个参数定义的是套接字的读取超时。</para>
<note>
<para>一旦JNDI连接成功所有调用都是通过RMI完成。如果你想要控制RMI连接的超时你需要定义相应的系统变量。
JBoss使用Sun的RMI实现它的控制参数可以在<ulink
url="http://java.sun.com/j2se/1.5.0/docs/guide/rmi/sunrmiproperties.html">这里</ulink>找到。
默认的连接超时是10秒默认的读超时是18秒。</para>
</note>
<para>如果你使用自己的实现来查找JMS资源你需要注意超时问题。</para>
</section>
<section>
<title>例子</title>
<para>参见<xref linkend="examples.javaee.jms-bridge"/>。这个例子展示了如何在JBoss应用服务器中配置并使用
JMS桥从一处目标将消息转发到另一个目标。</para>
<para>关于如何在两个单独HornetQ服务器间使用桥的例子请参见<xref linkend="examples.jms.jms-bridge"/></para>
</section>
</section>
</chapter>