AMQP,即 高级消息队列协议(Advanced Message Queuing Protocol),是一个消息中间件应用层协议,用于组件之间的解耦,来提供 统一消息服务。主要功能是 排序消息,路由消息(包括点对点和订阅-发布),保证消息的可靠性和安全性。
遵循AMPQ协议的客户端,都能通过 消息中间件 相互通信。这样 客户端 就可以采用不同的开发语言实现,彼此无强依赖关系,降低客户端复杂性,提高开发效率也利于后期维护。
AMQP 的模型架构如下:
- 最左端和最右端,publisher(消息生产者),consumer(消息消费者) 都是客户端
- 左上方灰色方框为 message消息结构(交换器名exchange_name,路由键rountingKey)
- 中间红色方框为 message broker(消息中间件),如 rabbitMQ,kafka
- 客户端通过 tcp连接,建立 connection 来进行通信
下面介绍AMQP模型的概念:
1.'pubilsher':消息生产者,生产消息并投送到指定的交换器上。
2.'consumer':消息消费者,从对应的队列中取出消息消费。
1)当 autoAck 为 true 时,消息发送出去后就认为消费成功,而不管消费者是
否真正消费到这些消息。当channel因意外而关闭,或者消费者在消费过程之
中意外宕机时,会丢失对应的消息。因此这种模式可以提高吞吐量,但存
在数据丢失的风险。
2)当 autoAck 为 false 时,consumer在数据处理完成后需要返回确认信息,
只有broker收到确认消费信息后,才认为这条消息已经被成功处理。
这可以保证数据的可靠性投递,但会降低系统的吞吐量。
3.'message':消息,由消息头和消息体组成。消息头存储与消息相关的元数据,
如交换器名字(exchange_name),路由键(rountingKey)和可选配置(properties),
消息体为实际需要传递的数据。
4.'message_broker':消息中间件,如rabbitMQ,kafka。
5.'virtual_host':虚拟主机,类似于linux的namespace,实现用户资源的隔离
当 broker 有多个用户时,可以划分出多个 vhost,每个vhost类似于小型的broker,
拥有独立的交换器,队列和绑定关系。用户根据不同的应用场景选择vhost。
6.'exchange':交换器,message到达 broker 的第一站。
负责接收publisher的消息并根据绑定关系,将消息路由到到一个或多个queue中
1)当mandatory为true时,如果根据分发规则找不到符合条件的queue,会将消息返回给publisher
2)当mandatory为false时,如果根据绑定关系找不到符合条件的queue,会直接丢弃该message
7.'bindingKey':绑定键,exchange和queue通过bindingKey建立绑定关系。
另外还有 'rountingKey'。当publisher将message发送给exchange时,一般会
指定一个 rountingKey,用来指定这个message的路由规则。当rountingKey和
bindingKey基于规则匹配时,消息被路由响应的queue中
8.'queue':消息队列。存储路由过来的message,一个queue可以被多个
consumer订阅,此时queue会通过轮询(round-robin)方式分发message,即
每条message只会发送给一个consumer,不会出现同一个message被多个
consumer重复消费的情况。
9.'connection':用来传递消息的tcp连接
10.'channel':信道。是在connection内部采用 IO多路复用建立的逻辑连接,
每个chanel拥有独立的channelID,保证channel之间的隔离性,类似于在同一个
tcp连接中建立更小的tcp独立连接,每次断开连接,断开的是channel连接,
最外层的tcp连接并不会断开,一直在被复用,极大减少了tcp连接的开销。
基于AMPQ协议实现的rabbitMQ
rabbitMQ是AMQP协议的一个开源实现。架构模型同样可以用以下的图来表示:
rabbitMQ具有以下特点:
1. 可靠性,使用一些机制,如持久化,发布确认,传输确认等保持可靠性
2. 灵活的路由,提供了多种6工作模式满足各种业务需求
3. 集群性,多个 rabbitMQ 服务器可以组成一个集群,形成一个逻辑 broker
4. 高可用,queue可以在集群上进行镜像,使得部分节点出问题仍能保持可用
5. 多种协议,支持多种消息队列协议,如stomp,mqtt等等
6. 多语言客户端,几乎支持所有常用语言,如java,ruby,golang等等
7. 管理界面,提供了一个易用的用户界面,方便监控和管理
8. 跟踪机制,如果消息异常,使用者可以找出发生了什么问题
9. 插件机制,提供了许多插件来扩展,也可以编写自己的插件
下面主要介绍rabbitMQ 6种工作方式:
1. simple模式,如下图示:
如上图,simple模式,单个publisher,单个queue,单个consumer
2. work模式,如下图示:
如上图,work模式
多个consumer共用一个queue的message
此种模式下,rabbitMQ会自动做负载均衡,将消息轮询发送给各个消费者,即一个消息只能被一个消费者获取
3. publish / subscribe 发布订阅模式(广播模式),如下图示:
如上图,publish / subscribe 发布订阅模式(广播模式)
相对前2种模式,多了一个exchange (type为fanout),message先发送到exchange,exchange再分别发送到对应的所有queue。而consumer订阅自己的queue,在自己订阅的queue上消费message。
示例应用场景,如下图示:
比如 网上购物,下单支付成功后,通知用户的方式有许多种,app推送,短信,email 等等。
message到来后被exchange发送到3个queue(app推送q,短信q,email_q)
之后 app推送服务,短信通知服务,email通知服务 从各自订阅的queue获取消息,通知用户支付成功
4. routing 路由模式,如下图示:
如上图示,exchange类型设定为direct
此时 message中的rountingKey 和 exchange中的bindingKey匹配,两者相等则发送对应的queue中,如果匹配不到bindingKey,则丢弃该message。
示例应用场景,如下图示:
比如服务产生的日志,日志有许多类型,error,info,debuf等类型的日志,而我们的需求只想要将 error 类型的日志写入磁盘,就可以用routing模式,将error日志路由到error queue,再由相应的 写入磁盘服务获取message,写入磁盘
5. topic 主题模式,如下图示:
'*' 和 '#' 代表通配符
'*' 代表匹配 1个单词(如 "a","abc")
'#' 代表匹配 0个或多个单词(如 "","a","abc","abc.def.ddd")
exchange 根据 key 模糊匹配到对应的queue
路由键为 lazy.orange.hello 的消息会发送给所有队列;
路由键为 quick.orange.fox 的消息只会发送给 Q1 队列;
路由键为 lazy.brown.fox 的消息只会发送给 Q2 队列;
路由键为 lazy.pink.rabbit 的消息只会发送给 Q2 队列;
路由键为 quick.brown.fox 的消息与任何绑定都不匹配;
路由键为 orange 或 quick.orange.hello.rabbit 的消息也与任何绑定都不匹配
如上图示,exchange类型为topic,相对于第4种模式,相同点是都根据 rountingKey 匹配,不同点是 topic 模式支持模糊匹配。
应用场景,比如不同运营商的手机号码处理不同,可以根据手机号码的前几位去做区分,如'185','139'等等