今天彻底谈谈rabbitMQ消息中间件

前言(何为AMQP?)

一个提供统一消息服务的应用层标准高级消息队列协议,是一个通用的应用层协议

消息发送与接受的双方遵守这个协议可以实现异步通讯。这个协议约定了消息的格式和工作方式。

何为RabbitMq?

RabbitMQ是一个实现了AMQP(Advanced Message Queuing Protocol)高级消息队列协议的消息队列服务,用Erlang语言。

rabbitmq原理

今天彻底谈谈rabbitMQ消息中间件

  • Producer:即数据的发送方

Create messages and publish (send) them to a Broker Server

一般一个Message有两个部分:payload(有效载荷)和label(标签),payload顾名思义就是传输的数据,label是exchange的名字或者说是一个tag,它描述了payload,而且RabbitMQ也是通过这个label来决定把这个Message发给哪个Consumer

  • Exchange:即rabbitmq内的消息交换器

Exchanges are message routing agents, An exchange accepts messages
from the producer application and routes them to message queues with
help of header attributes, bindings, and routing keys.

exchange从生产者那收到消息后,一般会指定一个Routing Key,来指定这个消息的路由规则,当然Routing Key需要与Exchange Type及Binding key联合使用才能最终生效,根据路由规则,匹配查询表中的routing key,分发消息到queue中。

  • binding:即绑定

A binding is a “link” that you set up to bind a queue to an exchange

在绑定(Binding)Exchange与Queue的同时,一般会指定一个Binding key;但Binding key并不是在所有情况下都生效,它依赖于Exchange Type

  • Queue:即队列

是rabbitmq内部对象,用于存储消息;

消息最终被送到这里等待consumer取走。一个message可以被同时拷贝到多个queue中。

那么谁应该负责创建这个queue呢?是Consumer,还是Producer?

如果queue不存在,当然Consumer不会得到任何的Message。那么Producer
Publish的Message会被丢弃。所以,还是为了数据不丢失,Consumer和Producer都try to create the queue!反正不管怎么样,这个接口都不会出问题。 queue对load balance的处理是完美的。对于多个Consumer来说,RabbitMQ 使用循环的方式(round-robin)的方式均衡的发送给不同的Consumer。

  • Connection与Channel:两者都是RabbitMQ对外提供的API中最基本的对象

A Connection represents a real TCP connection to the message broker,
whereas a Channel is a virtual connection (AMPQ connection) inside it

Connection就是一个TCP的连接,Producer和Consumer都是通过TCP连接到RabbitMQ Server的

Channel是建立在上述的TCP连接中,因为建立TCP Connection的开销将是巨大的,所以是节省开销;

Channel是我们与RabbitMQ打交道的最重要的一个接口,我们大部分的业务操作是在Channel这个接口中完成的,包括定义Queue、定义Exchange、绑定Queue与Exchange、发布消息等

  • Consumer:即数据的接收方

Consumers attach to a Broker Server (RabbitMQ) and subscribe to a queue。

如果有多个消费者同时订阅同一个Queue中的消息,Queue中的消息会被平摊给多个消费者

  • Broker: 即RabbitMQ Server

RabbitMQ isn’t a food truck, it’s a delivery service

其作用是维护一条从Producer到Consumer的路线,保证数据能够按照指定的方式进行传输

  • Virtual host:即虚拟主机

当多个不同的用户使用同一个RabbitMQ server提供的服务时,可以划分出多个vhost,每个用户在自己的vhost创建exchange/queue

rabbitmq 消息转发流程

今天彻底谈谈rabbitMQ消息中间件

The producer publishes a message to the exchange. The exchange
receives the message and is now responsible for the routing of the
message. A binding has to be set up between the queue and the
exchange. In this case, we have bindings to two different queues from
the exchange. The exchange routes the message in to the queues. The
messages stay in the queue until they are handled by a consumer The
consumer handles the message.

ps:重点说下路由转发。生产者Producer在发送消息时,都需要指定一个RoutingKey和Exchange,Exchange收到消息后可以看到消息中指定的RoutingKey,再根据当前Exchange的ExchangeType,按一定的规则将消息转发到相应的queue中去。

有兴趣的可以用rabbitmq模拟器体验下,模拟器使用方法:

今天彻底谈谈rabbitMQ消息中间件
rabbitmq中exchange type

Direct exchange 直接转发路由
原理是通过消息中的routing key,与binding 中的binding-key 进行比对,若二者匹配,则将消息发送到这个消息队列。

如下图:消息生成者生成一个message(payload是1,routing key为苹果),两个binding(binding key分别为苹果、香蕉);exchange比对消息的routing key和binding key后,将消息发给了queue1,消息消费者1获得queue1的消息,got msg: 1

今天彻底谈谈rabbitMQ消息中间件

Fanout exchange 复制分发路由
原理是不需要routkey,当exchange收到消息后,将消息复制多份转发给与自己绑定的消息队列

如下图:消息生成者生成一个message(payload是1,routing key为苹果),两个binding(binding key分别为苹果、香蕉);exchange将消息分发给两个queue,两个消费者获得queue的消息,got msg: 1

今天彻底谈谈rabbitMQ消息中间件
topic exchange 通配路由
是direct exchange的通配符模式

如下图:消息生成者生成一个message(payload是1,routing key为quick.orange.rabbit),两个binding(binding key分别为*.orange.、..rabbit);exchange比对消息的routing key和binding key后,exchange将消息分发给两个queue,两个消费者获得queue的消息,got msg: 1

今天彻底谈谈rabbitMQ消息中间件
再如下图:消息生成者生成一个message(payload是1,routing key为lazy.pink.rabbit),两个binding(binding key分别为*.orange.、..rabbit);exchange比对消息的routing key和binding key后,exchange将消息分发给queue2,消费者2获得queue的消息,got msg: 1

今天彻底谈谈rabbitMQ消息中间件

写在最后

最后,我们谈谈rabbitmq消息的可靠性

1、Message durability

将保存在内存中的数据都写入磁盘,防止服务器重启后数据丢失;有哪些数据需要持久化保存呢?

元数据、消息需要持久化到磁盘;

磁盘节点:持久化的消息在到达队列时就被写入到磁盘,并且如果可以,持久化的消息也会在内存中保存一份备份,这样可以提高一定的性能,只有在内存吃紧的时候才会从内存中清除;

内存节点:非持久化的消息一般只保存在内存中,在内存吃紧的时候会被换入到磁盘中,以节省内存空间;

2、Message acknowledgment

在实际应用中,可能会发生消费者收到Queue中的消息,但没有处理完成就宕机(或出现其他意外)的情况,这种情况下就可能会导致消息丢失。为了避免这种情况发生,我们可以要求消费者在消费完消息后发送一个回执给RabbitMQ,RabbitMQ收到消息回执(Message acknowledgment)后才将该消息从Queue中移除。

如果一个Queue没被任何的Consumer Subscribe(订阅),当有数据到达时,这个数据会被cache,不会被丢弃。当有Consumer时,这个数据会被立即发送到这个Consumer。这个数据被Consumer正确收到时,这个数据就被从Queue中删除。

那么什么是正确收到呢?通过ACK。每个Message都要被acknowledged(确认,ACK)。我们可以显示的在程序中去ACK,也可以自动的ACK。如果有数据没有被ACK,那么RabbitMQ Server会把这个信息发送到下一个Consumer。