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