activemq-artemis/docs/user-manual/zh/configuring-transports.xml

377 lines
25 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. -->
<!-- ============================================================================= -->
<chapter id="configuring-transports">
<title>传输层的配置</title>
<para>HornetQ的传输层是“可插拔的”。通过灵活的配置和一套服务提供接口SPIHornetQ可以很容易地更换其传输层。</para>
<para>在本章中我们将对HornetQ的传输相关的概念作出解释并说明它的配置方法。</para>
<section id="configuring-transports.acceptors">
<title>接收器Acceptor</title>
<para>接收器(<emphasis>acceptor</emphasis>)是 HornetQ 的传输层中最为重要的概念之一。首先
介绍一下在文件<literal>hornetq-configuration.xml</literal>中是怎样定义一个接收器的:</para>
<programlisting>
&lt;acceptors&gt;
&lt;acceptor name="netty"&gt;
&lt;factory-class&gt;
org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
&lt;/factory-class&gt;
&lt;param key="port" value="5446"/&gt;
&lt;/acceptor&gt;
&lt;/acceptors&gt;
</programlisting>
<para>所有接收器都在 <literal>acceptors</literal>单元element内定义。在<literal>acceptors</literal>
内可以有零个或多个接收器的定义。每个服务器所拥有的接收器的数量是没有限制的。</para>
<para>每个接收器都要定义其与HornetQ服务器连接的方式。</para>
<para>以上的例子中我们定义了一个<ulink
url="http://jboss.org/netty">Netty</ulink>接收器。它在端口<literal>5446</literal>监听连接请求。</para>
<para><literal>acceptor</literal>单元内有一个子单元<literal>factory-class</literal>。这个单元是用来
定义创建连接器的工厂类。一个连接器工厂类必须要实现<literal>AcceptorFactory</literal>接口。上例中我们定义
的连接器工厂是类NettyAcceptorFactory使用Netty来建立连接。有个这个类定义HornetQ就知道了用什么传输来建立连接了。</para>
<para><literal>acceptor</literal>中还可以配置零或多个参数<literal>param</literal>。在每个<literal>param</literal>
中定义的是键-值对key-value。这些参数用来配置某个传输实现。不同传输有不同的配置参数。</para>
<para>像IP地址、端口号等都是传输配置参数的例子。</para>
</section>
<section id="configuring-transports.connectors">
<title>连接器Connectors</title>
<para>接收器定义的是如何在服务器端接收连接,而连接器则是定义客户端如何连接到服务器。</para>
<para>以下是<literal>hornetq-configuration.xml</literal>文件中一个连接器配置的例子。</para>
<programlisting>
&lt;connectors&gt;
&lt;connector name="netty"&gt;
&lt;factory-class&gt;
org.hornetq.core.remoting.impl.netty.NettyConnectorFactory
&lt;/factory-class&gt;
&lt;param key="port" value="5446"/&gt;
&lt;/connector&gt;
&lt;/connectors&gt;
</programlisting>
<para>连接器的配置在<literal>connectors</literal>单元中。可以定义一个或多个连接器。每个服务器配置的连接器
数量是没有限制的。</para>
<para>你可能注意到了,既然连接器是定义<emphasis>客户端</emphasis>如何连接服务器的,那么为什么要定义在
<emphasis>服务器</emphasis>端呢?原因如下:</para>
<itemizedlist>
<listitem>
<para>服务器有时也需要做为客户端去连接其它的服务器,比如当一个服务器通过桥连接到另一个服务器,或者是集群
中服务器之间的互相通迅。在这种情况下服务器就要知道如何与另一台服务器建立连接。因此需要在
<emphasis>connectors</emphasis>下定义连接器。</para>
</listitem>
<listitem>
<para>如果你使用JMS服务需要创建连接工厂的实例并绑定到JNDI。在HornetQ创建
<literal>HornetQConnectionFactory</literal>时需要连接器的必要信息,以便这个连接工厂
能知道它如何与HornetQ服务器相连接。</para>
<para>这一信息被定义在配置文件<literal
>hornetq-jms.xml</literal>中的<literal>connector-ref</literal>单元下。下面这段配置
就是从该配置文件中提取的相关部分它展示了JMS的连接工厂是如何引用定义在配置文件<literal
>hornetq-configuration.xml</literal>中的连接器的:</para>
<programlisting>
&lt;connection-factory name="ConnectionFactory"&gt;
&lt;connectors>
&lt;connector-ref connector-name="netty"/&gt;
&lt;/connectors>
&lt;entries&gt;
&lt;entry name="ConnectionFactory"/&gt;
&lt;entry name="XAConnectionFactory"/&gt;
&lt;/entries&gt;
&lt;/connection-factory&gt;
</programlisting>
</listitem>
</itemizedlist>
</section>
<section id="configuring-transports.client.side">
<title>在客户端直接配置传输层</title>
<para>怎样配置一个内核<literal>ClientSessionFactory</literal>以让它知道如何连接服务器的信息呢?</para>
<para>在直接配置内核<literal>ClientSessionFactory</literal>的时候,可以间接地使用连接器。当然在这种情况
下在服务器端定义连接器是没有意义的。我们通过将必要参数传给<literal>ClientSessionFactory</literal>
方法来告诉使用什么样的连接器工厂。</para>
<para>在下面的例子中,我们创建了一个<literal>ClientSessionFactory</literal>,它可以直接连接到我们先前定
义的接收器上。它使用的是标准的Netty TCP传输层连接主机是localhost默认端口5446</para>
<programlisting>
Map&lt;String, Object&gt; connectionParams = new HashMap&lt;String, Object&gt;();
connectionParams.put(org.hornetq.core.remoting.impl.netty.TransportConstants.PORT_PROP_NAME,
5446);
TransportConfiguration transportConfiguration =
new TransportConfiguration(
"org.hornetq.core.remoting.impl.netty.NettyConnectorFactory",
connectionParams);
ClientSessionFactory sessionFactory = HornetQClient.createClientSessionFactory(transportConfiguration);
ClientSession session = sessionFactory.createSession(...);
etc
</programlisting>
<para>如果在客户端直接使用JMS的连接工厂的话也可以用类似的方法而不需要在服务器端定义连接器或在
<literal>hornetq-jms.xml</literal>配置文件中创建连接工厂:</para>
<programlisting>
Map&lt;String, Object&gt; connectionParams = new HashMap&lt;String, Object&gt;();
connectionParams.put(org.hornetq.core.remoting.impl.netty.TransportConstants.PORT_PROP_NAME, 5446);
TransportConfiguration transportConfiguration =
new TransportConfiguration(
"org.hornetq.core.remoting.impl.netty.NettyConnectorFactory",
connectionParams);
ConnectionFactory connectionFactory = HornetQJMSClient.createConnectionFactory(transportConfiguration);
Connection jmsConnection = connectionFactory.createConnection();
etc
</programlisting>
</section>
<section>
<title>配置 Netty 传输层</title>
<para>HornetQ当前使用<ulink url="http://www.jboss.org/netty/"
>Netty</ulink>作为其默认的连接层。Netty是一个高性能的底层网络库.</para>
<para>Netty传输的配置有几种不同的方法。它可以使用传统的Java IO阻塞方式、NIO非阻塞或直接使用
TCP socket及SSL。或者使用HTTP或HTTPS协议。同时还可能使用servlet进行传输。</para>
<para>采用Netty应该能满足绝大部分的传输要求。</para>
<section>
<title>配置 Netty TCP</title>
<para>Netty TCP 是简单的非加密的基于TCP socket的传输。它可以使用阻塞式的Java IO或非阻塞式的Java NIO。
我们建议在服务器端采用非阻塞式的NIO以获得良好的并发处理能力。当并发能力并不是很重要时可以使用阻塞式
的方式以增加响应的速度。</para>
<para>如果你的应用是运行在不信任的网络上你应该选择使用SSL或HTTPS。</para>
<para>Netty TCP的所有连接都是从客户端发起的。服务器端不向客户端发起任何连接。在有防火墙的环境中这种方式
是比较适合的。因为防火墙只允许单方向的连接。</para>
<para><literal>org.hornetq.core.remoting.impl.netty.TransportConstants</literal>类中定义了所
有的配置参数的名称key。它们当中绝大多娄既用于配置接收器也用于配置连接器有一些只适用于接收器。
下面列出的参数用以配置一个简单的Netty TCP</para>
<itemizedlist>
<listitem>
<para><literal>use-nio</literal>。如果设为<literal>true</literal>则使用非阻塞的Java
NIO。如果<literal>false</literal>则使用传统的阻塞方式的Java IO。</para>
<para>我们建议使用Java NIO处理并行连接。因为Java NIO不是为每一个连接分配一个线程所以它要比传统的阻塞式
Java IO具有更强的并发连接的处理能力。如果你不需要处理并发连接那么使用旧的阻塞式的IO性能会好一些。这个参
数的默认值在服务器端是<literal>false</literal>,在客户端是<literal>false</literal>
</para>
</listitem>
<listitem>
<para><literal>host</literal>。主机名或IP地址。对于接收器来说它是服务器接收连接的地址。
对于连接器端,它是客户端连接的目标地址。默认值是<literal>localhost</literal>
在配置接收器时可以指定多个主机名或IP地址中间用逗号隔开。如果指定的主机是<code>0.0.0.0</code>
则接收器将从主机上所有的网络接口中接受连接请求。连接器不允许指定多个主机地址,它只能与一个
地址建立连接。</para>
<note>
<para>一定不要忘记指定一个主机名或IP地址一个服务器要想接受来自其它节点的连接就必需有一个
主机名或IP地址来绑定及监听外部的连接请求。默认的主机名localhost是不能接受外部的
连接请求的!</para>
</note>
</listitem>
<listitem>
<para><literal>port</literal>。连接的端口。用于配置连接器或接收器。连接器用此端口来建立
连接。接收器在些端口上监听连接请求。默认值是<literal>5445</literal></para>
</listitem>
<listitem>
<para><literal>tcp-no-delay</literal>。将它设为<literal>true</literal>就会使用
<ulink url="http://en.wikipedia.org/wiki/Nagle's_algorithm">Nagle
算法</ulink>.默认值是<literal>true</literal></para>
</listitem>
<listitem>
<para><literal>tcp-send-buffer-size</literal>。这个参数指定了TCP的发送缓冲大小单位是字节。
默认值是<literal>32768</literal>字节(32KiB)。</para>
<para>这个参数要根据你的网络的带宽与时延的情况而调整。<ulink url="http://www-didc.lbl.gov/TCP-tuning/">
这个链接</ulink>对此有很好的论述。</para>
<para>简言之TCP的发送接收缓冲的大小可以用下面公式来计算</para>
<programlisting>
缓冲大小 = 带宽 * RTT
</programlisting>
<para>其中带宽的单位是 <emphasis>每秒字节数</emphasis>RTT网络往返程时间的单位是秒。
使用<literal>ping</literal>工具可以方便地测量出RTT。</para>
<para>对于快速网络可以适当加大缓冲的大小。</para>
</listitem>
<listitem>
<para><literal>tcp-receive-buffer-size</literal>。这个参数指定了TCP接收缓冲的大小单位是字节。
默认值是<literal>32768</literal>字节(32KiB)。</para>
</listitem>
<listitem>
<para><literal>batch-delay</literal>。HornetQ可以通过配置该参数在数据包写入传输层之前有一个
最大延时(毫秒),达到批量写入的目的。这样可以提高小消息的发送效率。但这样做会增加单个消息的平均发送
延迟。默认值为<literal>0</literal>毫秒。</para>
</listitem>
<listitem>
<para><literal>direct-deliver</literal>。消息到达服务器后,默认是由一个不同的线程来将消息传递
到接收者。这样可以使服务的呑吐量和可扩展性达到最佳,特别是在多核的系统上效果更为明显。但是线程切换
会带来一些传递的延迟。如果你希望延迟最小,并不在意呑吐量的话,可以将参数<literal
>direct-deliver</literal>设为true。默认值是<literal>true</literal>。如果你更希望有
较大的呑吐量的话,将它设为<literal>false</literal></para>
</listitem>
<listitem>
<para><literal>nio-remoting-threads</literal>。如果使用NIO默认情况下HornetQ会使用系统中处理
器内核(或超线程)数量三倍的线程来处理接收的数据包。内核的数量是通过调用<literal
>Runtime.getRuntime().availableProcessors()</literal>来得到的。如果你想改变这个数量,
你可以设定本参数。默认的值是<literal>-1</literal>,表示线程数为<literal
>Runtime.getRuntime().availableProcessors()</literal> * 3。</para>
</listitem>
</itemizedlist>
</section>
<section>
<title>配置Netty SSL</title>
<para>Netty SSL的配置与Netty TCP相似。它采用了安全套接字层SSL来提供加密的TCP连接。</para>
<para>我们提供了一个Netty SSL的例子来演示其配置和应用。</para>
<para>Netty SSL拥有Netty TCP一样的参数另外还有下列的附加参数</para>
<itemizedlist>
<listitem>
<para><literal>ssl-enabled</literal>。必须设为<literal>true</literal>以使用SSL。</para>
</listitem>
<listitem>
<para><literal>key-store-path</literal>。存放SSL密钥的路径key store)。这是存放客户端证书的地方。</para>
</listitem>
<listitem>
<para><literal>key-store-password</literal>。用于访问key store的密码。</para>
</listitem>
<listitem>
<para><literal>trust-store-path</literal>。服务器端存放可信任客户证书的路径。</para>
</listitem>
<listitem>
<para><literal>trust-store-password</literal>。用于访问可信任客户证书trust store)的密码。</para>
</listitem>
</itemizedlist>
</section>
<section>
<title>配置Netty HTTP</title>
<para>Netty HTTP 通过HTTP通道传送数据包。在有些用户环境中防火墙只允许有HTTP通信这时采用Netty HTTP作为HornetQ
的传输层就能解决问题。</para>
<para>我们提供了一个Netty HTTP的例子来演示其配置和应用。</para>
<para>Netty HTTP具有和Netty TCP同样的配置参数另外它还有以下参数</para>
<itemizedlist>
<listitem>
<para><literal>http-enabled</literal>。如果要使用HTTP这个参数必须设为<literal>true</literal></para>
</listitem>
<listitem>
<para><literal>http-client-idle-time</literal>。客户端空闲时间。如果客户端的空闲时间超过
这个值Netty就会发送一个空的HTTP请求以保持连接不被关闭。</para>
</listitem>
<listitem>
<para><literal>http-client-idle-scan-period</literal>。扫描空闲客户端的间隔时间。单位是毫秒。</para>
</listitem>
<listitem>
<para><literal>http-response-time</literal>。服务器端向客户端发送空的http响应前的最大等待时间。</para>
</listitem>
<listitem>
<para><literal>http-server-scan-period</literal>。服务器扫描需要响应的客户端的时间间隔。单位是毫秒。</para>
</listitem>
<listitem>
<para><literal>http-requires-session-id</literal>。如果设为true客户端在第一次请求后将等待
接收一个会话ID。http 连接器用它来连接servlet接收器不建议这样使用</para>
</listitem>
</itemizedlist>
</section>
<section>
<title>配置Netty Servlet</title>
<para>HornetQ可以使用Netty servlet来传输消息。使用servlet可以将HornetQ的数据通过HTTP传送到一个
运行的servlet再由servlet转发给HornetQ服务器。</para>
<para>servlet与HTTP的不同之处在于当用HTTP传输时HornetQ如同一个web服务器它监听在某个端口上的HTTP
请求并返回响应。比如80端口或8080端口。而当使用servlet时HornetQ的传输数据是通过运行在某一servlet容器
中的一个特定的servlet来转发的。而这个sevlet容器中同时还可能运行其他的应用如web服务。当一个公司有多个应用
但只允许一个http端口可以访问时servlet传输可以很好的解决HornetQ的传输问题。</para>
<para>请参见HornetQ所提供的servlet例子来了解详细的配置方法。</para>
<para>要在HornetQ中使用Netty servlet传输方式需要以下步骤</para>
<itemizedlist>
<listitem>
<para>部署servlet。下面是一个web.xml例子</para>
<programlisting>&lt;?xml version="1.0" encoding="UTF-8"?>
&lt;web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
&lt;servlet>
&lt;servlet-name>HornetQServlet&lt;/servlet-name>
&lt;servlet-class>org.jboss.netty.channel.socket.http.HttpTunnelingServlet&lt;/servlet-class>
&lt;init-param>
&lt;param-name>endpoint&lt;/param-name>
&lt;param-value>local:org.hornetq&lt;/param-value>
&lt;/init-param>
&lt;load-on-startup>1&lt;/load-on-startup>
&lt;/servlet>
&lt;servlet-mapping>
&lt;servlet-name>HornetQServlet&lt;/servlet-name>
&lt;url-pattern>/HornetQServlet&lt;/url-pattern>
&lt;/servlet-mapping>
&lt;/web-app>
</programlisting>
</listitem>
<listitem>
<para>我们还需要在服务器端加上一个特殊的Netty invm 接收器。</para>
<para>下面是从<literal>hornetq-configuration.xml</literal>配置文件中摘取的定义接收器的配置部分:</para>
<programlisting>
&lt;acceptors>
&lt;acceptor name="netty-invm">
&lt;factory-class>
org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
&lt;/factory-class>
&lt;param key="use-invm" value="true"/>
&lt;param key="host" value="org.hornetq"/>
&lt;/acceptor>
&lt;/acceptors>
</programlisting>
</listitem>
<listitem>
<para>最后我们需要在客户端配置连接器,也是在<literal>hornetq-configuration.xml</literal>文件中来做。如下所示:</para>
<programlisting>&lt;connectors>
&lt;connector name="netty-servlet">
&lt;factory-class>
org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory
&lt;/factory-class>
&lt;param key="host" value="localhost"/>
&lt;param key="port" value="8080"/>
&lt;param key="use-servlet" value="true"/>
&lt;param key="servlet-path" value="/messaging/HornetQServlet"/>
&lt;/connector>
&lt;/connectors></programlisting>
</listitem>
</itemizedlist>
<para>下面列出了初始化参数以及它们的用途:</para>
<itemizedlist>
<listitem>
<para>endpoint - Netty接收器的名字。servlet将向它转发数据包。它与<literal
>host</literal>参数的值是对应的。</para>
</listitem>
</itemizedlist>
<para><literal>web.xml</literal>中定义的servlet的URL形式与在连接器配置文件中定义的
<literal>servlet-path</literal>值应该相匹配。</para>
<para>servlet可以与SSL一起使用。只需要在连接器配置中加上下面的配置即可<programlisting> &lt;connector name="netty-servlet">
&lt;factory-class>org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory&lt;/factory-class>
&lt;param key="host" value="localhost"/>
&lt;param key="port" value="8443"/>
&lt;param key="use-servlet" value="true"/>
&lt;param key="servlet-path" value="/messaging/HornetQServlet"/>
&lt;param key="ssl-enabled" value="true"/>
&lt;param key="key-store-path" value="path to a keystoree"/>
&lt;param key="key-store-password" value="keystore password"/>
&lt;/connector>
</programlisting></para>
<para>另外你还需要为服务器指定一个KeyStore。打开<literal>server/default/deploy/jbossweb.sar</literal>
下的<literal>server.xml</literal>文件按照下面的内容编辑其中的SSLTLS连接器配置<programlisting>&lt;Connector protocol="HTTP/1.1" SSLEnabled="true"
port="8443" address="${jboss.bind.address}"
scheme="https" secure="true" clientAuth="false"
keystoreFile="path to a keystore"
keystorePass="keystore password" sslProtocol = "TLS" />
</programlisting>SSL需要keystore和访问密码。参见servlet ssl例子以了解更多的有关信息。</para>
</section>
</section>
</chapter>