介绍
面向消息的中间件产品(MOM)是许多SOA集成和ESB框架的核心,它们提供了应用程序之间可靠,可伸缩且强大的异步通信方式。
消息排队(以下称为“ MQ”)有两个基本部分:
- 消息 :对参与程序具有一定意义的二进制或字符(例如ASCII或EBCDIC)数据的集合。 与其他通信协议一样,在传输之前将存储,路由和传递信息添加到消息中,并在传递给接收应用程序之前将其从消息中剥离。
- 消息队列 :将消息存储在应用程序中的对象。 队列顺序通常是先进先出(FIFO),并且是根据本地队列中的接收顺序而不是来自发送方的消息提交顺序进行排序。 MOM系统通常支持某种形式的优先级划分,因此默认情况下,队列以优先顺序(到达顺序)保存。
该技术具有两个主要优势:
- 消息不依赖于基于纯数据包的传输,例如TCP / IP。 这允许发送和接收端分离,并可能异步运行。
- 无论是否出现错误(包括系统故障和网络问题),都保证消息一次只能发送一次。
从广义上讲,MOM系统支持两种常见模型:
- 点对点模型 : 发送者将消息发布到特定队列, 接收者从队列中读取消息。 在这里,发送者知道消息的目的地,并将消息直接发布到接收者的队列中。 它类似于电子邮件系统或语音邮件。 它具有以下特点:
- 只有一位消费者收到此消息。
- 生产者不必在使用者消费消息时就在运行,也不必在消费者发送消息时就在运行。
- 消费者可以确认成功处理的每个消息。
- 发布/订阅模型 (通常缩写为pub / sub)类似于匿名公告板。 将消息发布到特定的消息主题,并且订户可以注册对接收特定消息主题的消息的兴趣。 发布者和订阅者都不相互了解。 以下是此模型的特征:
- 多个使用者(或没有)将收到此消息。
- 发布者和订阅者之间存在时间依赖性。 发布者必须创建一个客户端可以订阅的订阅。 订户必须保持连续的活动状态才能接收消息,除非它已建立了持久的订户。 在这种情况下,订户未连接时发布的消息将在每次重新连接时重新分配。
IBM的MQSeries(现为WebSphere MQ )是1993年推出的首批商业MOM产品之一。它仍然是市场的领导者,市场份额通常估计在30-40%左右。 MQSeries最初基于点对点消息传递模型,但现在也支持发布/订阅。 另一款早期产品Tibco的Rendezvous普及了发布/订阅模型,尽管现在它也支持点对点。
还存在许多替代产品,包括Microsoft的MQ,以及开源选项,例如RabbitMQ和Progress Software的SonicMQ 。
Java消息服务和AMQP
考虑到中间件消息传递产品的众多选择,Java EE定义了一种通用的API,用于以Java消息服务(JMS)的形式与消息传递产品进行通信,从而抽象了对MOM的访问。 在Sun的领导下,JMS的创建是行业的努力,它使Sun在整个过程中与消息传递供应商紧密合作。
JMS还有一个更广泛的目标,即与基于CORBA和EJB的基于远程过程调用的系统一样,将消息作为一流的Java分布式计算范例来支持。 O'Reilly Java Message Service一书中引用了规范负责人Mark Hapner的话 :
有许多MOM供应商都参与了JMS的创建。 这是行业的努力,而不是Sun的努力。 Sun是技术规范的负责人,并且确实领导了这项工作,但如果没有消息传递厂商的直接参与,它就不会成功。 尽管我们最初的目标是提供一个用于连接MOM系统的Java API,但在整个工作过程中,这一目标已转变为更广泛的目标,即与RPC平等地支持将消息作为一流的Java分布式计算范例。
JMS的作用与JDBC相似。 它允许从通用API使用许多不同的面向消息的中间件提供程序。 它已经非常成功,但是确实有局限性。 特别是消息格式本身仍然是专有的。 换句话说,虽然一个供应商产品可以切换为另一种,但一个MOM产品无法读取以另一MOM产品使用的格式发送的消息。 另外,由于它是纯Java的API,因此使用其他语言(例如C ++)的开发人员无法使用它。
高级消息队列协议 ( AMQP )旨在解决此问题。 该计划由摩根大通发起,他意识到他们将很大一部分IT预算用于集成。 然后,该公司采取了非同寻常的步骤,创建了一组公司来研究新模型AMQP,该模型于2006年夏天推出。然后,主要的业务推动因素是降低集成成本。
该规范目前处于草拟阶段,两个主要版本为0.9和0.10。
AMQP与JMS的不同之处在于,它定义了线路级别的详细信息以及通用的API。 Spring Integration团队的负责人和Spring AMQP项目的共同负责人Mark Fisher描述如下:
像TCP和HTTP一样,AMQP的目标是通信互操作性。 AMQP定义了一条消息“在线”的规范,无论您使用哪种语言或库来产生和使用消息。 它还定义了一个用于消息传递的域模型,其中包括Exchange(用于路由和pub / sub)和Queue(用于缓冲和传递)以及生产者和使用者的基本行为(事务,确认)。
AMQP与XMPP计划类似, 后者是用于即时消息传递的另一种有线协议。 费舍尔认为:
对于不同的消息传递用例,需要几种模型。 例如,XMPP是用于Web规模即时消息传递的开放协议。 XMPP强调身份,状态和文本流; AMQP通过灵活的路由,传送和对二进制流的支持来补充这一点 。
推动采用的动力是逐渐脱离数据库,将其作为应用程序的唯一设计中心。 随着通信和应用程序接近Internet规模,在多个地方都需要数据。 消息传递与“动态数据”有关,消息传递系统提供了一种抽象的通信模型。 这与数据库有关,后者与静态数据有关,并提供抽象的存储模型。 两种模式的使用对于许多现代系统都是必不可少的。
消息产品在15年前就开始流行。 它们在金融服务中用于广播市场价格更新和集成支付系统。 如今,消息传递现在被视为对更多系统必不可少的。 最佳点与以下三种情况有关:
- 通过解耦组件来扩展应用程序以使用异步消息传递进行通信
- 跨多种语言编写的多个应用程序之间的安全集成
- 分布式,互联网规模的系统,尤其是“云计算”
消息传递还用于IPC的数据路由和传递,日志记录和社交活动流,事务,Web推送,社交网络集成,警报,监视,调度,工作分配,系统管理,流控制,流量管理。 一些消息传递系统还提供“ ESB”类型的功能,例如转换,过滤和业务流程编排。
由于AMQP旨在降低成本,因此它旨在成为一种破坏性技术,其中包括扩展到ESB产品和消息代理更常见的领域。 费舍尔告诉我们
对于云和互联网计算,有线互操作性非常重要。 诸如HTTP和XMPP之类的协议用于云服务API,因为客户端无需安装服务提供商的代码即可访问服务。 J,对于JMS,情况并非如此。 多家公司拥有包括StormMQ在内的云AMQP API。
AMQP与XMPP一样,是可以启用代理联合的有线协议。 联合需要跨实现的线级互操作性,因此JMS无法跨供应商提供此功能。 因此,重要的Web规模案例(例如可靠的跨数据中心集成)是完全专有的,这迫使公司仅对一个供应商进行标准化,从而增加了锁定。 AMQP尚未以标准方式定义联盟,但是可以添加它。
从开发人员的角度来看,JMS和AMQP之间存在一些关键区别。 特别地,JMS具有两种类型的目的地-用于发布/预订模型的主题,和用于点对点模型的队列。 Fisher解释说,AMQP将队列和主题的路由和传递功能分为“路由”层(称为交换)和缓冲和传递层(称为队列)。 队列代表消费者。 这意味着一个JMS主题可以通过一个交换为每个订户与队列进行建模。
SpringSource的AMQP项目和RabbitMQ
VMware的SpringSource是AMQP的坚定支持者。 SpringSource在今年4月收购了最近推出的RabbitMQ 2.0.0,它支持AMQP 0.9。 另外,SpringSource有一个独立的Spring AMQP项目,在主要的Spring框架之外运行。 Mark Pollack博士告诉我们:
我们认为,这个项目必须按自己的条件发展,并且不受Spring Framework或任何其他项目的发布时间表的影响,这一点很重要。 尽管尚未做出最终决定,但[Spring项目的共同创始人] Juergen Holler不反对在成熟后将其包含在Spring Framework中。 这样会有很多好处,例如,将可以在Spring的JMS和AMQP支持之间共享的通用代码和接口排除在外。
Spring AMQP项目与SpringSource的JMS模板具有相似的目标和相似的方法。 费舍尔告诉我们
我们确实提供了一个与Spring的JMS模板非常相似的AmqpTemplate,它甚至委托了许多相同类型的策略,例如MessageConverter。 在堆栈上,我们还将重点放在Spring Integration中的一致方法上,这意味着我们将提供与JMS同类产品非常相似的Channel Adapters和Gateways。
对于许多应用程序,消息传递的高级抽象将它们与供应商锁定隔离开来,从而可以在现有系统(例如IBM MQ和Tibco)与现代消息传递系统之间进行更改和集成。 在Spring适应变化的传统中,实际上是“只是配置”,而不是在应用程序内切换或组合JMS和AMQP适配器时会有所不同的代码。
除了标准的AmqpTemplate之外,SpringSource还为RabbitMQ提供了特定的RabbitTemplate。 费舍尔继续
对于所有典型操作,AmqpTemplate操作就足够了。 如果您觉得抽象妨碍您,可以访问基础实现。 例如,在RabbitTemplate中,我们有一个回调,它提供对Rabbit Channel实例的直接访问。
这是Spring中的另一个常见习语:不仅仅是“最低公分母”的高级抽象。 以JdbcTemplate为例; 大多数时候,高级查询和更新方法就足够了,但是如果需要,您可以访问原始的JDBC连接。 我们在这里遵循相同的方法。
Spring的AMQP和JMS支持都突出了MessageConverter的思想,该思想支持在JSON,Java序列化等之间来回编组。 费舍尔告诉我们:
在AmqpTemplate中,我们的操作采用了我们已定义为Spring AMQP核心域模型的一部分的通用AMQP Message对象的实例,但是我们还提供了可直接与任何AMQP一起使用的操作 Java对象。 在后一种情况下,MessageConverter策略扮演着在这些对象和Messages之间转换的重要角色,其中Message包含一个字节数组作为其主体以及属性。
顺便说一下,这与Spring的MessageConverter策略接口在Spring的JMS支持中提供的角色完全相同。 在Spring 3.0中,我们引入了针对JMS的XML编组MessageConverter实现,而在Spring AMQP中我们实现的非常相似。 AMQP的一个重要区别是,与JMS不同,您显然不能假定您在另一侧拥有Java。
因此,不建议依赖现成的Java序列化。 实际上,通常甚至不建议将其用于JMS,因为它会增加生产者和消费者之间的耦合,但是,可以说,它甚至不建议用于AMQP。 因此,通用序列化很重要,最常见的两种格式是XML和JSON。 我们希望在这个领域看到很多未来的发展,因此请留意将来提供更多的序列化支持。
SpringSource还将在将来努力支持其他代理,例如Qpid。 波拉克博士告诉我们:
在Java方面,情况更为复杂。 Qpid的Java客户端API是JMS API的实现。 在该API之上放置一个AMQP层是没有任何意义的。 用于实现JMS API的Qpid Java客户端API非常低级,处理AMQP命令帧,因此要提供Java Qpid支持,将花费更多的工作。 在这个领域为该项目做出一些贡献将是很棒的,请随时与我们联系。
有趣的是,SpringSource的AMQP产品包括Erlang通信支持。 波拉克博士告诉我们:
Erlang通信支持基于Jinterface,它提供了一种从Java应用程序与Erlang进程进行通信的方法。 Erlang.NET项目对.NET应用程序起着相同的作用。 使用这些库,您可以调用RPC到Erlang函数,并且还可以将Java或.NET进程本身显示为Erlang节点。
Spring的Erlang通信支持建立在Jinterface和Erlang.NET之上,以提供更易于使用的API进行RPC调用。 基本API将Erlang数据类型建模为类。 例如,类OtpErlangFloat表示Java float基本类型。 结果,要编写大量的样板代码来处理本机语言类型和Erlang数据类型之间的转换。 另外,在Jinterace中使用检查异常会增加执行最简单的RPC调用的冗长性。
使用帮助程序类ErlangTemplate,您可以使用“一个班轮”方法进行以原始类型作为参数的RPC调用,例如
long number = (Long) erlangTemplate.executeAndConvertRpc("erlang", "abs", -161803399);
如果需要在更复杂的数据类型之间进行转换,则可以注册Spring的ErlangConverter类的实例以封装并更好地构造该转换逻辑。
对AMQP的批评
AMQP并非没有批评者。 一方面,尽管它确实获得了包括Microsoft,Red Hat,Progress,Cisco,Novell以及VMware在内的著名成员的行业支持 ,但IBM和Tibco均未参与其中。
其次,在规范的公共工作开始四年之后,它还没有达到1.0的状态,而规范的0.10草案因过于冗长和复杂而受到攻击。 iMatix的Pieter Hintjens认为,应将简短的(40页)0-9SP1(现称为AMQP 0-9-1)提升为1.0状态。 Hintjens告诉我们0-9-1“尽管有缺陷,但它是一个很好的协议。缺陷可以全部解决。”
Hintjens的观点很重要,因为他与JPMorgan Chase的John O'Hara及其同事以及iMatix的Martin Sustrik密切合作,参与了AMQP的原始技术设计。 iMatix显然对规范制定的方向不满意,并已辞职。 我们联系了Hintjens,以获取更多有关其决定原因的背景信息:
我们非常努力地解决了这个问题(围绕AMQP创建了一个贡献者社区,并将整体协议变成了较小标准的生态系统),但我们失败了。 到目前为止,我们不是唯一精疲力尽并放弃工作组的团队。 思科就是一个很好的例子,他们显然比iMatix大得多,如果协议运行良好,iMatix将永远不会停止开发AMQP产品。 多年来,我们以文字和书面形式反复提出了提高开放性和透明度的要求。 将其表示为iMatix与其他供应商之间的一系列对抗,是事实的歪曲,事实已经很好地记录在电子邮件列表档案中。
RabbitMQ承担了所有这一切,可以在这里找到。
第三个问题与专利有关,特别是Red Hat正在为AMQP的基于XML的路由申请专利。 Hintjens自2005年以来一直在欧洲从事软件专利的研究,并认为这些专利对创新有不利影响。 如您所料,他强烈批评Red Hat,称其行为“令人震惊”。 他接着说
我们至少有一个大客户对该专利表示非常真实的关注,尽管噪音有所减轻,但它并没有解决任何问题。 人们只是不想公开辩论。 私下里,在AMQP附近的任何地方申请专利都是一种敌对行为,但与Red Hat对该技术的一般方法一致。
Pollack博士对此的看法如下
许多评论员没有意识到AMQP防止专利滥用的实力。 澄清:
AMQP具有强大的法律基础,可以以多种方式保护实施者。 AMQP基于成员公司提供的知识产权,其方式类似于W3C的IPR模型。 同样,所有规范文档都可以在类似于IETF许可证的开放许可证下获得。
尽管AMQP贡献者协议尚未公开,但可以将其描述为“专利条约”的一种形式。 没有与AMQP相关的专利使用费,所有成员公司均已书面承诺不起诉AMQP的任何实施者或用户针对与AMQP相关的任何专利的专利侵权。 红帽是该协议的签署人之一。
其他公共实施方案和替代方案
除SpringSource之外,目前还存在少量AMQP的其他公共实现。 这些包括
- Apache Qpid ,Apache Foundation中的一个项目。
- 红帽企业MRG实现了最新版本的AMQP 0-10。 还可以在Fedora的最新3个版本中作为AMQP基础结构使用 。
- StormMQ :作为托管服务提供。
还有iMatix用C编写的OpenAMQ (一种AMQP的开源实现),但由于iMatix将注意力转移到了ZeroMQ产品上而终止。
Hintjens告诉我们ZeroMQ是基于以下模型
...不是强制单个经纪人,而是连接一组智能客户端的设备网络(队列,转发器,代理)。 这是一种反映互联网的交流模型,而AMQP可能代表Facebook或Google。 当然,任何网络都需要中介,问题是您是否要信任单个主导中介,还是更喜欢在各地创建自己的中介。
RabbitMQ和Spring AMQP与ZeroMQ一起使用 。 Pollack博士解释说,此集成代码由RabbitMQ团队与Martin Sustrik合作开发,Martin Sustrik是ZeroMQ社区的成员,也是ZeroMQ的代码主要贡献者。
他接着说
从RabbitMQ的角度来看,ZeroMQ是一个消息传递客户端,它提供有用的网络抽象。 从ZeroMQ的角度来看,RabbitMQ是当您需要强大的消息传递中介时的嵌入式消息传递设备。
Zyre经纪人也将ZeroMQ与本机AMQP集成在一起。