传输层的配置 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例子以了解更多的有关信息。