activema in action 第四章:连接到ActiveMQ
转自:http://blog.sina.com.cn/s/blog_616e189f0100nuyn.html
第四章:连接到ActiveMQ
ActiveMQ的主要作用就是向客户应用程序提供面向消息通信的架构。ActiveMQ提供了一种用于客户端和代理之间(Client-to-Broker)以及代理与代理(Broker-to-Broker)之间连接的连接器(connectors)。ActiveMQ允许客户端的应用程序使用多种协议连接到代理,并且代理之间可以创建复杂的连接通道。
这一章中将解释下面的连接概念:
1. 连接URIs(connector URIs),用于表示代理的地址
2. 传输连接(Transport connectors),将Broker暴露给客户端使用,负责客户端与代理之间的连接通信。
3. 网络连接(Network Connectors),用于创建代理网络拓扑,主要负责代理与代理之间的连接通信。
4. 发现代理(Discovery Agent),客户端或代理用于探测并连接网络中的其他代理。
5. 其他常用的连接器
4.1 理解连接器URIs(Connector URIs)
在描述连接器细节和他们在ActiveMQ体系结构中的作用之前,您需要了解连接器URIs。ActiveMQ中的链接器URIs在是一种标准URI地址。
统一资源定位符(Uniform Resource Identifiers,URIs),被WWW(world wide web)引入标识一个网络资源。URI规范指出:一个URI标识一个抽象的或物理的资源。
每一个URI具有如下语法格式:
<scheme>:<scheme-specific-part>
例如下面的URI:
注意到mailto是主题,后面附带一个电子邮件地址,用来指定服务器和服务器上的具体资源。
更为常用的URIs是一种具有等级结构的URIs,如下所示:
<scheme>://<authority><path><?query>
例如下面的实例:
http://www.nabble.com/forum/NewTopic.jtp?forum=2356
上述的URL使用了http主题,并且包含了路径和查询元素(查询元素就是附加的参数)。
由于URIs的简单灵活,ActiveMQ使用URIs定位一个特定的brokers。例如:
tcp://localhost:61616
意思是说标识一个本地的端口号位61616的TCP连接。
ActiveMQ连接器将这种简单等级结构的URI模式称为低等级的连接器(low-level connectors),并为这些连接器实现了基本的网络通信协议。低等级连接器URIs使用主题(scheme)标识底层使用的网络协议,使用路径元素定位网络资源服务(一般为主机名加上端口号),使用查询元素用来确定连接器附加信息。如下图:
如果使用符合URIs,当一个客户端连接不可用时,ActiveMQ中的TCP传输连接器会使用自动重连接。复合重连接示例如下:
可以看出URI的主题使用static协议,路径部分包含了多个低层次的URIs。每个低层次的URIs都可以有自己的参数。
注意,不要在多个低等级的URI之间添加任何空白符,这是URI规范所不允许的,这也是一种常见的ActiveMQ配置错误。
4.2 配置传输连接器。
客户端与代理(Client-to-Broker)之间的通信连接器称为传输连接器(transport connectors)。
传输连接器用于接收和监听客户端的请求。您可以从默认的ActiveMQ的配置文档(conf/Activemq.xml)中看到一些对传输连接器的配置,如下:
正如您看到的,传输连接器组使用<transportConnectors>元素进行定义,通过<transportConnector>来定义单个连接器。ActiveMQ中可以使用多种协议的在不同端口上进行监听。URI定义网络协议和可选的参数,通过URI将ActiveMQ的连接暴露给外部客户端或者其他代理进行链接。上述描述的在openwire连接器中定义DiscoveryUrl属性是可选的。
在ActiveMQ启动时,您可以看到连接器启动的状况:
在客户端可以使用下面的方法连接到ActiveMQ:
上面的例子中,使用TCP协议,与ActiveMQ中介取得连接。
需要注意的是,URI的参数字段有些仅适用于代理中介的配置,有些仅适用于客户端连接使用,有些两者都适用,在您使用参数时,请参考相关协议文档。
4.2.1 使用传输连接器
略
4.2.2 使用网络协议
通常的使用场景是这样的,将ActiveMQ以一个Java应用程序单独运行,这就意味着客户端(消息发送者和消费者)需要使用一些网络协议才能访问目标代理中介。
4.2.2.1 传输控制协议(transmission control protocol TCP)
TCP协议是一种以包交换进行主机通信的可靠的传输协议。
由于客户端应用程序和代理之间希望以一种可靠的方式进行通信,所以使用TCP协议实现JMS是合理的,并且也是ActiveMQ中使用最多的协议。
在消息进行交换之前,需要将他们串行化为特定的传输格式。将消息串行化成比特序列的协议称为包装协议(wire protocol)。ActiveMQ默认使用的包装协议为OpenWire协议。包装的目的是使得网络消息传输更有效更快速。除此之外,包装协议还会允许消息在不同编程语言编写的应用之间进行交换。为了完成消息的包装,TCP传输连接器使用OpenWire协议将消息串行化并通过TCP协议在网络上进行传输。
正如我们前面看到的那样,默认的TCP连接器使用61616端口。
Tcp://hostname:port?key=value&key=value
示例如下:
上例中使用了trace选项,表明所有的连接都需要记录日志,一般用于对brokers调试。注意当配置文档修改后,必须重新启动ActiveMQ,配置才能生效。
使用TCP传输连接器的优点:
1. 高效 – TCP连接器默认情况下使用OpenWire协议对传输的消息进行串行化,这在网络传输中是十分高效的。
2. 高可用 – 基本上所有的平台都支持TCP网络协议。
3. 可靠 – 能够确保消息在传输过程中不会丢失。
4.2.2.2 新I/O API 协议(New I/O API Protocol ,NIO)
NIO是在Java SE1.4规范中定义的Java标准I/O API。NIO并不是想取代传统Java I/O API的地位,而是提供了一种可替代的用于网络编程和访问操作系统底层I/O操作的方法。NIO的特点在于NIO selectors和无阻塞I/O编程,使得开发者使用同一网络资源解决更多的网络客户端连接,并在服务之间平衡负载。
从使用者的角度来看,NIO传输连接器与TCP传输连接器没有什么必然区别,NIO在底层也使用TCP协议,并且也是用OpenWire作为消息串行化包装协议。唯一的区别在于底层实现的不同,NIO传输连接器是使用NIO API实现的。NOI传输连接器的使用场景:
1. 您需要有大量的客户端连接到JMS中介。
一般来说,能够连接到中介的客户端的数量取决于操作系统支持的线程数量的上限。由于NIO连接器的实现与TCP连接器相比启动了更少的线程,如果使用TCP不能够满足您的需要时,请考虑使用NIO。
2. 您的中介需要大量的网络传输。NIO连接器与TCP连接器相比,效能上会更高一些,因为NIO占用更少的资源。
需要注意的是,ActiveMQ的效能调节不能简单的通过使用哪个连接器就能完成。其他很多方面会影响到ActiveMQ的性能调节,例如,正确的选择网络拓扑,为brokers设置多种选项,消息发送者和消费者的操作等。
配置NIO如下:
nio://hostname:port?key=value
一个配置的例子:
<transportonnector
Name=”tcp”
Uri=”tcp://localhost:61616?trace=true”/>
<transportConnector
Name=”nio”
Uri=”nio://localhost:61618?trace=true”/>
</transportConnectors>
下面给出一个发布者和消费者的示例,如下图:
从图中看出消息发布者和消费者可以采用不同的网络连接器。消息发布者使用nio发布消息,消息消费者使用tcp消费消息。
4.2.2.3 用户数据报协议(User Datagram Protocol ,UDP)
UDP与TCP的区别:
1. TCP是一种面向流的协议,这意味着数据包的顺序将得到保证。换句话说,数据报不可能出现重复和乱序接收的现象。UDP不能保证数据包的有序接收,也不能保证数据包的重复发送。
2. TCP可以保证数据报可靠的传输,意味着数据报在传输过程中不会出现丢失。这是通过在发送者和接收者之间管理一个活跃连接完成的。UDP是一种无连接的协议,不能保证数据报的完整传输。
TCP用于可靠的数据传输,而UDP用于快速的数据传输。
你可以使用UDP连接到ActiveMQ。语法如下:
Udp://hostname:port?key=value
TCP和UDP传输连接器的比较:
UDP的优势:
1. 代理安装在防火墙后面,防火墙不允许使用TCP,这种情况您只能使用UDP。
2. 应用是时间敏感的,您想尽量消除网络延时。
UDP的劣势:
1. UDP是不可靠的,您可能丢失一些消息,所以您的应用程序应当解决这种消息丢失的情况。
2. 在客户端和JMS中介之间传递的消息不单单是普通消息,这里还夹杂着控制命令,如果一些控制命令由于UDP的不可靠丢失,那么JMS连接是危险的。所以你必须提供一层可靠的传输确保控制消息的正确传输。
配置示例如下:
<transportonnector
Name=”tcp”
Uri=”tcp://localhost:61616?trace=true”/>
<transportConnector
Name=”udp”
Uri=”udp://localhost:61618?trace=true”/>
</transportConnectors>
4.2.2.4 安全套接字层协议(secure socket layer protocol,ssl)
使用TCP传输普通数据是不安全的,为了确保数据传输的安全性需要使用Secure Sockets Layer(SSL)协议。SSL协议在TCP协议的基础上传输加密的安全数据。它使用一组密钥(公钥和私钥)确保传输通道的安全性。ActiveMQ提供了SSL传输连接器,SSL传输连接器在客户端和代理之间的TCP连接通道上添加了一层加密协议。语法如下:
ssl://hostname:port?key=value
由于SSL传输是基于TCP实现的,所有配置上也和TCP很相似。在默认的情况下SSL的端口号是61617。配置示例如下:
<transportonnector
Name=”tcp”
Uri=”tcp://localhost:61616?trace=true”/>
<transportConnector
Name=”ssl”
Uri=”ssl://localhost:61617?trace=true”/>
</transportConnectors>
需要特别注意的是SSL需要一个证书和密钥。具体内容参考原版ActiveMQ in Action第100页。略。
4.2.4.5 超文本传输协议(HTTP/HTTPS)
在一些环境下,防火墙仅允许使用一些基础的协议访问。这是HTTP协议出现的原因。
ActiveMQ实现了HTTP传输连接器,能够提供基于xml的消息传输。可以使用HTTP协议绕过防火墙。
语法如下:
http://hostname:port?key=value
https://hostname:port?key=value
示例:
<transportConnectors>
<transportonnector
Name=”tcp”
Uri=”tcp://localhost:61616?trace=true”/>
<transportConnector
Name=”http”
Uri=”http://localhost:8080?trace=true”/>
</transportConnectors>
略。
4.2.3 使用虚拟机协议(Virtual Machine Protocol, VM)
前面讨论的都是客户端通过网络协议连接到中介。ActiveMQ可以内嵌到Java应用程序中,这就允许客户端与中介之间的交互通过本地JVM完成,而不是通过网络。为了支持这种VM内部通信,ActiveMQ提供了VM协议。
4.2.3.1 VM协议
Java应用程序使用VM传输连接器加载一个内嵌的中介代理并且与之连接。使用VM表示在客户端和内嵌的中介之间不需要网络连接,通信是直接使用方法调用的形式。由于不使用网络协议栈,效能会得到明显的提高。当第一个连接使用VM协议被创建时中介被开启。同一虚拟机的后续的VM传输连接都会连接到同一个中介。
使用VM协议创建的中介具有独立ActiveMQ的所有特性,并且这个中介也可以被其他的传输连接配置。当所有的连接到这个VM传输连接代理的连接都结束后,中介代理将会自动关闭。
语法如下:
vm://brokerName?key=value
VM 的代理名字在这里起到了至关重要的作用,用于标识一个中介。例如,您可以通过指定特定的中介名字创建不同的内嵌代理。不同的内嵌代理名字必须不同。
VM传输协议配置属性中与其他连接不同之处在于,可以通过参数来调节代理性能。以Broker.开头的属性用于调节中介的性能。例如下面的配置终止持久化:
Vm://broker1?marshal=false&broker.persistent=false
可替代的URI语法:
Vm:broker(transprotURI,network:networkURI)/brokerName?key=value
实例如下:
Vm:broker:(tcp://localhost:6000)?brokerName=embeddedbroker&persistent=false
上例中我们定义了一个名字为embeddedBroker的内嵌中介,并且配置了TCP传输连接在端口6000进行监听。最后取消了代理的持久化。如下图所示:
上图给出了客户端可以通过TCP连接到一个内嵌的代理。
可以通过配置文件对内嵌代理进行配置,然后进行引用,如下:
Vm://localhost?brokerConfig=xbean:activemq.xml
这个例子将会从classpath使用XBean协议加载activemq.xml文件配置内嵌代理。
使用内嵌代理的一个明显好处就是改进了客户端和代理之间的通信。并且您的Java应用仅需要一个应用程序(一个jvm中)而不是两个(独立运行ActiveMQ时,ActiveMQ自身是一个Java应用程序),简化您的程序配置过程。同时也意味着减少一个Java处理过程。
另一方面,如果很多的Java应用程序使用一个内嵌的代理,管理问题可能就会出现。这种情况应当使用单独的集群式代理而不是内嵌代理。
4.3 配置网络连接器(Network Connectors)
当应用程序具有大规模和高可用性需求时,最好使用网络代理(Network of brokers)。一个网络代理创建一个有多个ActiveMQ实例组成的集群系统,他们之间连接完成复杂的消息使用场景。前面讨论的是由客户端和代理之间的连接,这里强调的是代理与代理之间的连接。默认的网络连接通道是单向的。同时ActiveMQ也支持双向的通道。如下图所示:
网络连接器的配置是通过对ActiveMQ的xml文档进行配置完成的,如下所示:
网络连接器有一个重要概念叫发现(Discovery)。发现就是探测远程的代理服务的过程。客户端经常想要发现可用代理。代理本身也想发现其他的可用代理,这样就可以创建网络(集群式)代理了。
有两种形式的方法配置和连接客户端到网络代理。一种方法是客户端使用静态的方法配置访问特定的网络代理。另外一种方法是代理或者客户端可以使用发现中介(agents)动态的探测代理。
4.3.1 定义静态的网络代理(static Networks)
静态网络代理连接要求您知道您需要使用的网络代理的URIs列表。
4.3.3.1 静态协议(static Protocol)
静态网络连接器(static Network connector)用来为多代理创建静态的连接。这些协议使用组合URI – 即,一个URI中包含了其他的URIs。组合URI中包含了多个代理的地址(URIs)。语法如下:
Static:(uri1,uri2,uri3,…)?key=value
下面给出一个配置实例:
<networkConnectors>
<networkConnector name=”local network”
Uri=”static://(tcp://remotehost1:61616,tcp://remotehost2:61616)”/>
</networkConnectors>
假设,您使用的Broker为localhost,并且remotehost1和remotehost2这两个Broker已经开启。输出信息如下:
上面的输出表明:localhost已经成功的与其他两个代理之间创建了转送桥接(forwarding bridge),换句话说,发往本地代理的消息将会转发到远程主机1和远程主机2。
4.3.1.2 Failover Protocol
到目前为止,客户端都是连接到一个指定的代理。但是如果指定代理不可用该如何处理。可以有两种可用的方案。第一种方案是,你提供一个静态的可用代理链表,使用failover transport connector。另外一种方案是,动态的去发现可用的代理。
语法:
Failover:(uri1, … , uriN)?key=value
或者:
Failover:uri1, … ,uriN)
在默认情况下会采用一种随机算法选取一个连接器进行链接。如果一个出现错误,那么连接器会选择另外一个连接器进行链接。默认的连接采用一种重连接延迟逻辑(reconnection delay logic),意味着,一个连接失败后将延迟10ms重新启动,之后将以30000ms重新尝试。重试连接将是无限此的。当然您可以使用相应的参数来配置重新连接。
4.3.2 定义动态网络(Dynamic networks)
4.3.2.1 多播协议(Multicast Protocol)
ActiveMQ代理使用多播协议使本地的服务和代理创建网络代理。客户端可以使用多播协议定位本地代理并创建连接。
语法:
Muticast://ipaddress:port?key=value
实例:
<broker xmlns=http://activemq.apache.org/schema/core brokerName=”multicast”
dataDirectory=”${activema.base}/data”>
<networkConnectors>
<networkConnector name=”default-nc” uri=”multicast://default”/>
</networkConnectors>
<transportConnectors>
<transportConnector name=”openwire” uri=”tcp://localhost:61616”
discoveryUri=”multicast://default”/>
</broker>
在例子中的default组用来代表特殊的IP地址。这意味着,代理将会使用239.255.2.3地址发送多播包。
需要强调的是,多播仅能在本地局域网中使用(local area Network,LAN)。这是由于使用IP 多播协议的限制。
多播协议多用于代理更替频繁的情况下。
多播协议的缺陷之一是,你可能不希望有些代理接收一些消息,这种配置是相当复杂的。另外,多播可能会造成巨大的网络负担。很多网络管理员将不允许使用多播协议。当您打算使用多播协议时,请综合考虑利弊。
4.3.2.2 发现协议(Discovery Protocol)
发现传输连接器(Discovery transport connector)用于客户端使用多播协议发现可用的ActiveMQ。他将动态的发现可用代理并且随机选择其中一个代理进行链接。
语法:
Discovery:(discoveryAgentURI)?key=value
4.2.2.3 对等协议(Peer Protocol)
对等传输连接器(peer transport connector)是用于嵌入式代理构建网络代理的协议。
语法如下:
Peer://peergroup/brokerName?key=value
例如:
4.3.2.4 扇出协议(fanout Protocol)
使用扇出传输连接,一个客户端可以连接多个代理。
Fanout:(fanoutURI)?key=value
例如:
Fanout:(static:(tcp://host1:61616,tcp://host2:61616,tcp://host3:61616))
如图所示:
使用动态扇出:
Fanout:(multicast://default)
不提倡消费者使用扇出协议,他主要适用于生产消息发向多个代理。如果多个代理出现环路,可能造成消费者接收重复的消息。所以,扇出协议仅适用于将消息发送给多个不相连接的代理。
4.4 总结
现在您应该了解了ActiveMQ的URIs和不同的传输连接器。内嵌的代理和网络型代理,并知道如何使用和配置他们。最后你也了解了重连接协议和发现代理。
当您要搭建JMS系统的拓扑结构是,知道并理解不同的连接器类型和协议间的不同是非常重要的。