本章内容:
· ActiveMQ连接器URIs的描述和演示
· 客户端如何使用传输连接器连接ActiveMQ
· 如何使用网络连接器创建一个集群ActiveMQ消息代理器
ActiveMQ等JMS代理器的目的是为客户端应用提供一个交互的架构。所以,ActiveMQ提供连接器(connectors)。连接器提供客户端到代理器的交互(使用transport connectors),和代理器间的交互(使用network connectors)。ActiveMQ允许客户端使用各种协议进行连接,同时也运行代理器间通过连接通道来形成复杂的连接器网络。
这章我们先解释连接器URIs,它们是用来指明代理器的地址的。之后,我们介绍传输连接器(transport connectors)以及有哪些协议可以用来连接ActiveMQ代理器。
注意:
我们这里会用到连接器(connector)和协议(protocol)两个概念。协议是一个通用的概念,而连接器是ActiveMQ特定的一个东西。每个ActiveMQ连接器,实现一个特定的协议,并用它来作为自己的名字。对于下面将的内容要注意我们是在讨论某个协议还是在讨论一个特定的ActiveMQ连接器。
我们先解释如果配置传输连接器。然后,我们修改股票投资的例子,使之使用各种不同的连接器,并演示该例子。看完该例子后,我们移到特定的连接器,讨论的传输连接器将包括TCP,SSL和HTTP。接下来,我们将介绍使用VM协议的嵌入式代理器。
最后讨论的是使用网络连接器进行ActiveMQ集群的一些基本概念。我们将演示如果通过static协议创建静态的网络连接器,以及客户端如何通过failover协议稳定地连接到这些网络连接器上面。使用multicast和disvovery协议的动态连接器也会被讨论。这一节只是介绍网络连接器的一些基本的概念和协议,更多的内容将放到第10章。
4.1理解连接器URIs
在讨论连接器细节和它们在ActiveMQ架构的角色之前,理解连接器URIs很重要。统一资源定位符(Uniform resource identifiers),作为一个概念,并不新,而且你可能已经多次使用过它们而没有意识到而已。URIs第一次被引入来定位资源是在万维网(World Wide Web)。规范(http://mng.bz/8iPP)对URI的定义是:一个用来标识抽象或物理资源的简洁的字符串。因为URI的简单和灵活,它已经很多互联网服务使用。Web URLs和email地址就是我们日常用的URI的两个例子。
我们不去深入讨论URIs,不过必须简要地讲一下URI的结构。这对于了解为什么ActiveMQ使用URI来定位连接器很有帮助。
基本地,每个URI都遵循下面的格式:
<scheme>:<scheme-specific-part>
考虑下面的URI:
mailto:users@activemq.apache.org
注意使用到了mailto 协议,跟着的是一个email地址唯一地标识了我们要用到的服务和特定的资源。
最常用的URIs是分层的URIs,它的格式如下:
<scheme>://<authority><path><?query>
这类URI被浏览器用来标识网站。有一种类型的URI叫做URL(Uniform Resource Locator)。下面是一个例子:
http://www.nabble.com/forum/NewTopic.jtp?forum=2356
这个URL使用http协议并且使用path和query元素来指定额外的参数。
因为URIs的简单灵活,ActiveMQ使用它们来定位不同类型的各个连接器。如果你回去看第3章,你可以看到下面的URI被用来创建一个连接器。
tcp://localhost:61616
这是一个典型的分层URI,它的含义是“在本地61616端口创建一个TCP连接。”
这类使用简单分层URI模式的连接器被叫做low-level连接器,它们被用来实现基础的网络交流协议。连接器URIs使用schema来表示当前的网络协议,path元素用来标识网络资源(通常是地址和端口),query用来指定特殊的配置参数。
图4.1显示了URI的结构。这个URI扩展了前面的例子,它还告诉所有的代理器记录所有的命令(trace=true部分)。这是TCP端口可选的一个参数。
ActiveMQ的故障转移传输机制支持自动重连。也即是说,如果一个代理器不在线,客户端可以连到另一个代理器上。ActiveMQ通过使用复合URIs满足这种需求。在图4.2,你可以看到一个这种URI。
注意在scheme部分用到了static(static协议将在本章后面讨论)并且scheme-specific部分用到了一个或多个地等级URIs。当然,整个URI或者里面的低层次URI都可以包含查询参数。
注: 因为整个URI看起来比较复杂,所以用户经常会在中间插入空格以增强可读性。这是不被允许的。因为URI规范及它的Java实现都这样要求。所以请记得不要在URI中放任何空格。
现在你已经了解了ActiveMQ URI基本知识,我们接下来可以讨论ActiveMQ支持的连接器类型。本章接下来部分将讨论传输连接器和网络连接器以及如何配置它们。
4.2传输连接器
为了交换信息,生产者和消费者必须连接到代理器。客户端到代理器的连接是通过传输连接器来实现的。ActiveMQ提供了一些客户端协议,可以用来交换信息。ActiveMQ用户对连接的要求是多种多样的。一些用户关注性能,一些用户关注安全或其它指标。ActiveMQ尝试满足所有这些要求,并对每一种使用场景提供一种连接器。
在这一节,你将学会在ActiveMQ配置文件中配置传输连接器,然后修改股票投资例子来演示这些连接器。接下来的章节,我们将讨论网络连接器可用协议,并介绍内嵌代理器和虚拟机协议。这两个概念使得代理器可以在你的应用中运行,这个主题将在第七章继续讨论。
4.2.1配置传输连接器
对于代理器来说,传输连接器是用来接受和监听客户端连接的。如果你看一看ActiveMQ演示例子的配置文件(conf/activemq-demo.xml),你会看到类似如下的配置:
<transportConnectors>
<transportConnector name="openwire" uri="tcp://localhost:61616"
discoveryUri="multicast://default"/>
<transportConnector name="ssl" uri="ssl://localhost:61617"/>
<transportConnector name="stomp" uri="stomp://localhost:61613"/>
<transportConnector name="xmpp" uri="xmpp://localhost:61222"/>
</transportConnectors>
你可以看到传输连接器定义在<transportConnectors>元素之间。你通过<transport-Connector>元素定义特定的连接器。ActiveMQ可以不同的端口上设置不同协议的连接器。一个连接器必须有自己唯一的名字和URI属性。在这个例子中,URI定义了网络协议和可选参数,通过它们,ActiveMQ将被曝露出来给客户端连接。discoveryUri属性是可选的,这个属性将在4.3.1节讲解。
上面的片段定义了4个传输连接器。当你通过使用这样的配置文件启动ActiveMQ,你将看到如下日志:
INFO TransportServerThreadSupport - Listening for connections at:
tcp://localhost:61616
INFO TransportConnector - Connector openwire Started
INFO TransportServerThreadSupport - Listening for connections at:
ssl://localhost:61617
INFO TransportConnector - Connector ssl Started
INFO TransportServerThreadSupport - Listening for connections at:
stomp://localhost:61613
INFO TransportConnector - Connector stomp Started
INFO TransportServerThreadSupport - Listening for connections at:
xmpp://localhost:61222
INFO TransportConnector - Connector xmpp Started
从客户端角度,传输连接器是一个连接,通过它可以向代理器发送和接收消息。发送和接收消息的内容放在第七章。下面的代码展示了java应用如何使用传输连接器URIs。
ActiveMQConnectionFactory factory =
new ActiveMQConnectionFactory("tcp://localhost:61616 ");
Connection connection = factory.createConnection();
connection.start();
Session session =
connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
我们可以看到,在配置文件里定义的URI被客户端用来创建连接。在这个例子中,TCP传输URI将被使用。
注:我们可以在客户端和服务器端是用URI的query部分。通常地,这些参数对于客户端和服务器端都有用,但其中的一些只能用在某一部分。所以,在使用这些特定查询参数前请先查看文档说明。
理解了基本的传输连接器配置之后,我们应该了解ActiveMQ提供了哪些类型的传输连接器。不过在我们讲解特定传输连接器之前,我们先修改股票投资例子,让它使用不同的传输连接器。
4.2.2修改股票投资例子
第三章引入了一个股票投资例子,它用ActiveMQ来发布和消费股票交易消息。当时,我们使用标准的连接器URI,因为我们想让这个例子看起来尽量简单。这一章,我们将介绍所有的协议并同意股票投资例子来使用它们。所以,我们要修改该例子,让它使用任意的协议工作。
列表4.1是main()一个修改后的版本。
Listing 4.1 Modifying stock portfolio publisher to support various connector URIs
前面的代码保证连接器URI作为第一个参数被传递,并且剩下的参数是额外的目标的名称。现在,生产者可以通过下面的命令来运行:
$ mvn exec:java -Dexec.mainClass=org.apache.activemq.book.ch4.Publisher \
-Dexec.args="tcp://localhost:61616 CSCO ORCL"
...
Sending: {price=65.713356601409, stock=JAVA, offer=65.779069958011,
up=true}
on destination: topic://STOCKS.JAVA
Sending: {price=66.071605671946, stock=JAVA, offer=66.137677277617,
up=true}
on destination: topic://STOCKS.JAVA
Sending: {price=65.929035001620, stock=JAVA, offer=65.994964036622,
up=false}
on destination: topic://STOCKS.JAVA
...
注意到现在有三个参数被传送给生产者。我们也可以用相同的方法来修改消费者。在下面的列表中,被修改后的消费者把第一个参数作为URI来使用。
Listing 4.2 Modifying stock portfolio consumer to support various connector URIs
为了达到和第三章相同的功能,你必须提供一个额外的URI参数。下面的例子展示了如何做:
$ mvn exec:java -Dexec.mainClass=org.apache.activemq.book.ch4.Consumer \
-Dexec.args="tcp://localhost:61616 CSCO ORCL"
...
ORCL 65.71 65.78 up
ORCL 66.07 66.14 up
ORCL 65.93 65.99 down
CSCO 23.30 23.33 up
...
注意,消息在生产者和消费者之间的流动是和原始例子一样。通过这些修改,现在这个例子可以使用各种协议运行了。现在我们应该深入到特定的连接器里面了。下面的部分你将看到你通过网络连接代理器有什么选择。
4.3通过网络连接ActiveMQ
ActiveMQ最常用的场景是将它作为一个Java应用来使用。这意味着客户端(生产者和消费者)必须使用一些网络协议来连接代理器目标。在这一节,我们将介绍那些可以用在客户端-代理器交互场景中的网络协议。
我们先介绍TCP连接器,它最常用并且能提供理想的性能。然后是NIO连接器,它底层使用了TCP网络协议,但因为还用到了NIO Java API所以比TCP连接器有更好的伸缩性。UDP网络协议也经常被使用,所以UDP连接器也在讨论清单里。UDP协议与TCP相比带来一些性能的提升,但也损失了一些可靠性。UDP连接器也如此。因为UDP连接器的不可靠性,所以它使用的场景较少。SSL连接器能够与代理器维持一个安全连接。最后,我们将向你展示如何使用HTTP连接代理器。当然,在每一部分我们会讨论各种连接器的利弊。所以,你也可以考虑只阅读你感兴趣的部分,然后直接跳过去阅读下一章。表4.1包含了各种连接器的一个简要描述。现在让我们开始默认的TCP协议。
4.3.1 传输控制协议(TCP)
现在对人们来说,TCP协议可能和电力一样重要。作为一个基础的因特网协议,几乎所有的在线交流都用到它。像email和web等很多服务都使用它作为底层的网络协议。
希望你己经对TCP基本信息有了了解,我们将从引述RFC793协议开始。(http://mng.bz/Bns2):
Transmission Control Protocol(TCP)是为分组交换主机及内部系统间交换提供可靠的网络而设计的。
既然代理器和客户端应用是需要通过可靠的网络来交换的,那么很容易理解为什么TCP对于JMS实现来说是一个理想的协议。所以,TCP作为ActiveMQ最常用的连接器并不让人感到意外。在通过网络交换消息前,需要先把消息序列化成合适的形式。使用wire协议,消息被序列化成字节序列在电线上发送。ActiveMQ使用的默认wire协议叫做OpenWire。该协议规范可以在ActiveMQ网站找到(http://mng.bz/u2eT).OpenWire协议不止可以用在TCP网络传输,也可以用在其它网络协议上。它的目的是高效地,并且允许在网络上快速交换数据。还有,像OpenWire这样一个标准的,开放的协议能够在各种编程环境中被使用。这个协议和其它ActiveMQ可用的wire协议将在第九章讨论。
就像我们在前面章节看到的,一个默认的代理器配置会在端口61616上监听客户端的TCP传输连接。TCP连接器URI使用下面的语法:
tcp://hostname:port ?key=value&key=value
注意黑体字部分是必需的。在问号右边的key value对是可选的,并且各组key,value间用&符号分隔。
在本节或之后,我们不会完整地讨论该传输协议的所有可选的部分。这些东西应该放到网上的参考页面。最新的TCP连接器参考页是(http://mng.bz/ngU2)。
下面的配置片段提供了一个使用TCP连接器的例子:
<transportConnectors>
<transportConnector name="tcp"
uri="tcp://localhost:61616?trace=true"/>
</transportConnectors>
注意到trace选项可以被添加到URI后面。这个选项建议代理器记录所有通过该连接器发送过来的命令,这对调试非常有帮助。
重要提示 :修改配置文件后,ActiveMQ必须重启才能生效。
上面的内容概述了客户端使用TCP连接代理器。作为参考,下面的例子演示了消费者如何使用TCP连接器。
$ mvn exec:java -Dexec.mainClass=org.apache.activemq.book.ch4.Consumer \
-Dexec.args="tcp://localhost:61616 CSCO ORCL"
ORCL 65.71 65.78 up
ORCL 66.07 66.14 up
ORCL 65.93 65.99 down
CSCO 23.30 23.33 up
...
使用TCP连接器的好处有:
· 高效----这个连接器使用OpenWire协议将消息转换成字节流,所以在网络上传输非常高效。
· 可用----TCP是使用最广的一种网络协议,而且在很久前就被Java所支持。所以,该协议几乎可以支持你选择的所有平台。
· 可靠性----TCP协议保证消息不会丢失。