参考资料:
《JMS与AMQP简述以及比较》
《AMQP协议详解》
《MQ消息队列的JMS规范和AMQP协议的区别》
《消息队列之JMS和AMQP对比》
写在开头:本文为学习后的总结,可能有不到位的地方,错误的地方,欢迎各位指正。
一般情况下MQ的实现是要遵循一些常规性协议的,本文介绍一下其中的JMS与AMQP。
一、JMS
1、定义
JMS(JAVA Message Service,Java 消息服务)是一个Java平台中关于面向消息中间件的API,由Sun公司早期提出,旨在为java应用提供统一的消息操作。
JMS允许应用程序组件基于 JavaEE 平台创建、发送、接收和读取消息,即JMS 的客户端之间可以通过 JMS 服务进行异步的消息传输。它使分布式通信耦合度更低,消息服务更加可靠以及异步性。
ActiveMQ 就是基于 JMS 规范实现的。
2、消息模型
2.1、队列(点对点)模式(Point to Point)
使用JMS队列(Queue)作为消息通信载体;满足生产者与消费者模式,一个queue可以有很多消费者,但一条消息只能被一个消费者使用,未被消费的消息在队列中保留直到被消费或超时。比如:我们生产者发送100条消息的话,两个消费者来消费一般情况下两个消费者会按照消息发送的顺序各自消费一半(也就是你一个我一个的消费)。
每个消息只有一个消费者(Consumer)(即一旦被消费,消息就不再在消息队列中);
发送者和接收者之间在时间上没有依赖性,也就是说当发送者发送了消息之后,不管接收者有没有正在运行,它不会影响到消息被发送到队列;
接收者在成功接收消息之后需向队列应答成功。
2.2、主题模式模式(Publish/Subscribe)
发布订阅模型(Pub/Sub) 使用主题(Topic)作为消息通信载体,类似于广播模式;发布者发布一条消息,该消息通过主题传递给所有的订阅者,在一条消息广播之后才订阅的用户则是收不到该条消息的。
一个消息可以传递个多个订阅者(即:一个消息可以有多个接受方)
发布者与订阅者具有时间约束,针对某个主题(Topic)的订阅者,它必须创建一个订阅者之后,才能消费发布者的消息,而且为了消费消息,订阅者必须保持运行的状态。
为了缓和这样严格的时间相关性,JMS允许订阅者创建一个可持久化的订阅。这样,即使订阅者没有被激活(运行),它也能接收到发布者的消息。
3、消息类型
JMS 定义了五种不同的消息正文格式以及调用的消息类型,允许你发送并接收以一些不同形式的数据:
StreamMessage:Java 原始值的数据流
MapMessage:一套名称-值对
TextMessage:一个字符串对象
ObjectMessage:一个序列化的 Java 对象
BytesMessage:一个字节的数据流
二、AMQP
1、定义
AMQP(Advanced Message Queuing Protocol)高级消息队列协议,一个提供统一消息服务的应用层标准协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同开发语言等条件的限制。
AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。AMQP在消息提供者和客户端的行为进行了强制规定,使得不同卖商之间真正实现了互操作能力
RabbitMQ 就是基于 AMQP 协议实现的。
2、消息模型
AMQP在消息的生产者以及传递信息的队列之间引入了一种间接的机制:Exchange,实现了生产者和队列的解耦。
网络连接(Connection):例如TCP连接。
信道(Channel):是建立在Connection连接之上的一种轻量级的连接,如果把Connection比作一条光纤电缆的话,那么Channel信道就比作成光纤电缆中的其中一束光纤。一个Connection上可以创建任意数量的Channel。
交换器(Exchange):接受消息并根据路由键发送消息到绑定的队列(不具备消息存储的能力)。交换机是用来发送消息的 AMQP 实体。交换机拿到一个消息之后将它路由给一个或零个队列。它使用哪种路由算法是由交换机类型和绑定(Bindings)规则所决定的。
消息队列(Queue):用来保存消息直到发送给消费者。它是消息的容器,也是消息的终点。一个消息可投入一个或者多个队列、消息一致在队列里面,等待消费者连接到这个队列将其取走。
绑定(Binding):于消息队列和交换器之间的关联。一个绑定就是基于路由键将交换器和消息队列连接起来的路由规则,所以可以将路由器理解成一个由绑定构成的路由表。Exchange和Queue的绑定可以是多对多的关系。
路由(Routing):路由规则,虚拟机可以用它来确定如何路由一个特定消息。
虚拟主机(Virtual Host):表示一批交换器、消息队列和相关的对象。
实体(Broker):表示消息队列服务器实体。
Binding Key与Routing Key的关系:
Binding Key是队列和交换机之间的绑定key;
Routing Key是生产者发给交换机的一个信息;
当Binding Key和Routing Key能对应上时,将该消息放到相应的队列中。Message首先到达Exchange,随后Exchange根据分发规则,匹配查询表中的Routing key,当满足路由规则是,会将分发消息到对应的Queue中去。
3、Exchange模型
3.1、Direct
单播,消息中的路由键(routing-key) 如果和Binding中的Binding key一致,交换器就发到对应的队列中。
3.2、Fanout
广播,每个发到fanout类型交换器的消息都会分到所有绑定队列上去。fanout交换器不处理路由键,只是简单的将队列绑定到交换器上,每个发送到交换器的消息都会被转发到与该交换器绑定的所有队列上。很像子网广播,每台子网内的主机都获得了一份复制的消息。fanout类型转发消息是最快的。
3.3、Topic
有选择的广播,topic交换器通过模式匹配分配消息的路由键属性,将路由键和某个模式进行匹配,此时队列需要绑定到一个模式上。它将路由键和绑定键的字符串分成单词,这些单词用点隔开(a.b)。它同样也会识别两个通配符:符号:# 匹配0或者多个单词,*匹配一个单词。
JMS与AMQP的比较
多个角度的比较
JMS | AMQP | |
定义 | Java api | Wire-protocol |
跨语言 | 否 | 是 |
跨平台 | 否 | 是 |
Model | 提供两种消息模型: (1)、Peer-2-Peer (2)、Pub/sub | 提供了五种消息模型: (1)、direct exchange (2)、fanout exchange (3)、topic change (4)、headers exchange (5)、system exchange 本质来讲,后四种和JMS的pub/sub模型没有太大差别,仅是在路由机制上做了更详细的划分; |
支持消息类型 | 多种消息类型: TextMessage MapMessage BytesMessage StreamMessage ObjectMessage Message (只有消息头和属性) | byte[] 当实际应用时,有复杂的消息,可以将消息序列化后发送。 |
总结:
AMQP 为消息定义了线路层(wire-level protocol)的协议,而 JMS 所定义的是 API 规范。在 Java 体系中,多个 client 均可以通过 JMS 进行交互,不需要应用修改代码,但是其对跨平台的支持较差。而 AMQP 天然具有跨平台、跨语言特性。
JMS 支持 TextMessage、MapMessage 等复杂的消息类型;而 AMQP 仅支持 byte[] 消息类型(复杂的类型可序列化后发送)。
由于 Exchange 提供的路由算法,AMQP 可以提供多样化的路由方式来传递消息到消息队列,而 JMS 仅支持 队列 和 主题/订阅 方式两种。