1. 什么是 MQ

1.1 概念

MQ 全拼 Message Queue 即 消息队列。是在消息的传输过程中保存消息的容器,多用于分布式系统。

MQ 消息队列 取消消息_消息队列


MQ 消息队列 取消消息_Java_02

1.2 MQ 带来的优势

MQ 所带来的优势即我们用 MQ 的理由,如下:

  1. 应用解耦:复杂系统增加消息队列中间层解耦两端逻辑。提高系统容错性和可维护性
  2. 异步处理:消息异步处理,加快服务响应速度。提升用户体验和系统吞吐量
  3. 削峰填谷,流量控制:系统从消息队列中拉取消费请求,由消息队列缓冲量并发请求。请求量大可削峰,请求量小可填谷。提高系统稳定性

实际案例场景:

秒杀、聊天、等

1.3 MQ 带来的问题

所谓 天下没有免费的午餐,有利就有弊,引入 MQ 同样也会给我们带来不少问题:

  1. 增加了系统复杂度和维护成本。
  2. 引入消息队列所带来的延迟问题。
  3. 可能存在的数据不一致问题。

利弊权衡间考虑你的系统是否需要引入消息队列。

2. RabbitMQ 简介

公司/社区: Rabbit
开发语言:Erlang (为高并发和分布式诞生的语言,电信领域使用广泛)
协议支持:AMQP、XMPP、SMTP、STOMP
客户端支持语言:官方支持 Erlang、Java、Ruby 等,社区提供几乎支持所有主流语言。
单机吞吐量: 万级
消息延迟: 微秒
功能特性:并发能力强,性能极好,低延迟,社区活跃,完善的管理界面。

下图是一个简单的模型,以及一些相关概念

MQ 消息队列 取消消息_消息队列_03

2.1 什么是 AMQP

AMQP 全称 Advanced Message Queuing Protocol高级消息队列协议,是一个应用层网络协议,专门面向消息队列的中间件进行设计的协议。基于此协议的客户端与消息中间件可以传递消息,不受不同 客户端/中间件/开发语言等条件限制。是一个通信规范。

2.2 基础架构模型

MQ 消息队列 取消消息_消息队列_04


名词解释:

Broker: 中间件,接收和分发消息的应用,如 RabbitMQ Server 就是 Message Broker (消息中间件)

Virtual host:虚拟主机,出于多租户和安全的考虑,把 AMQP 的基本组件划分到一个虚拟的分组中,类似于网络中 namespace 命名空间的概念。当多个用户使用同一个 RabbitMQ server 所提供的服务时,可以划分出多个 virtual host ,每个用户在自己的 virtual host 进行 exchange 以及 queue 等,互不干扰。

Connection 链接,publisher 发布者 、consumer 订阅者 与 broker 之间的 TCP 链接。

Channel:通道,管道。 channel 是在 connection 内部建立的逻辑链接,为了避免程序多线程而创建多个 connection 做的优化。 如果应用程序支持多线程,通常每个 thread 会创建单独的 channel 进行通讯, AMQP Method 包含了 channelId 帮助客户端和 message broker 识别 channel ,每个 channel 相互隔离。这个概念有点类似 进行和线程的对应关系,正好一个进程对应一个 connection ,一个线程对应一个 channel 这样的感觉。

Exchange:交换机,message 到达 broker 会先进过 交换机 ,根据分发规则,查表匹配 routing key ,将消息分发到对应的 queue。常用的类型: direct (point-to-point),topic(publish-subscribe)、fanout (multicast)后文会详细说明。

Queue:队列,消息最终存储位置,等待 consumer 消费。

Binding: exchange 与 queue 之间的虚拟链接,binding 中可以包含 routing key。binding 信息被保存到 exchange 的查询表中,用于消息的分发。

RabbitMQ 6 种工作模式

1. Hello World 模式

这个模式简单理解就是 一对一的消费模式,一个生产者对应一个消费者,消息仅消费一次。

MQ 消息队列 取消消息_客户端_05

2. Work queues 工作队列模式

工作队列模式,与上面的简单模式区别是 可以多个生产者,然后由多个消费者一起消费消息,消息仅消费一次,对应的可以提高消息的处理速度。

MQ 消息队列 取消消息_MQ 消息队列 取消消息_06

3. Publish/Subscribe 发布订阅模式

到这里,发布订阅模式,路由模式,主题模式 其实结构上大同小异,区别仅仅是 交换机 Exchange 的绑定路由规则不同罢了。
同时在该模式下,一份消息会分发给符合条件的多个队列使用,且比上面的模式多了交换机的概念
交换机 顾名思义 作用就是将生产者生产的消息,根据一定的规则分发到对应的队列中。

发布订阅模式的 Exchange 交换机是 Fanout 广播模式,即:将消息交给所有绑定到交换机的队列

MQ 消息队列 取消消息_rabbitmq_07

4. Routing 路由模式

路由模式的 Exchange 交换机是 Direct 定向模式,即:把消息交给 routing key 路由对应的队列

MQ 消息队列 取消消息_Java_08

5. Topics 主题模式

主题模式的 Exchange 交换机是 Topic 通配符模式,即:把消息交给 routing pattern 路由匹配的队列

MQ 消息队列 取消消息_Java_09

6. RPC 远程调用模式

RPC 不是消息队列的重点,这里不做过多解释。RPC 有更多成熟的框架实现,个人不建议使用消息队列来实现。

MQ 消息队列 取消消息_MQ 消息队列 取消消息_10

消息的可靠性

消息生产端的可靠投递

在使用 RabbitMQ 的时候,作为消息发送方希望杜绝任何消息丢失或者投递失败场景。RabbitMQ 为我们提供了两种方式用来控制消息的投递可靠性模式。

confirm 确认模式
return 退回模式

rabbitmq 整个消息投递的路径为:

producer—>rabbitmq broker—>exchange—>queue—>consumer

消息从 producer 到 exchange 投递失败会返回一个 confirmCallback 。
消息从 exchange–>queue 投递失败会返回一个 returnCallback 。

我们将利用这两个 callback 控制消息的可靠性投递

注意这两个模式需要进行配置开启。如:

publisher-confirms=“true” 确认模式开启
publisher-returns=“true” 回退模式开启

消费端的确认消费 ACK

RabbitMQ 在消费端提供了 3 种确认机制

无需确认 acknowledge = "none" 该模式下无需手动编写代码 ack 。RabbitMQ 默认 consumer 正确处理所有请求。

手动确认 acknowledge="manual" 该模式下需要手动编写代码进行消息确认 如正常收到消息 channel.basicAck() 消息异常 channel.basicNack() 等。

自动确认 acknowledge="auto" consumer 自动应答,处理成功(即没有发生异常)发出 ack,处理失败发出 nack。queue 发出消息后会等待 consumer 端应答,只有收到 ack 确定信息后才会将消息在 queue 中清除掉。收到 nack 异常信息的处理方法由setDefaultRequeueReject() 方法设置,这种模式下,发送错误的消息可以恢复。