1. 什么是 MQ
1.1 概念
MQ 全拼 Message Queue 即 消息队列。是在消息的传输过程中保存消息的容器,多用于分布式系统。
1.2 MQ 带来的优势
MQ 所带来的优势即我们用 MQ 的理由,如下:
- 应用解耦:复杂系统增加消息队列中间层解耦两端逻辑。提高系统容错性和可维护性
- 异步处理:消息异步处理,加快服务响应速度。提升用户体验和系统吞吐量
- 削峰填谷,流量控制:系统从消息队列中拉取消费请求,由消息队列缓冲量并发请求。请求量大可削峰,请求量小可填谷。提高系统稳定性
实际案例场景:
秒杀、聊天、等
1.3 MQ 带来的问题
所谓 天下没有免费的午餐,有利就有弊,引入 MQ 同样也会给我们带来不少问题:
- 增加了系统复杂度和维护成本。
- 引入消息队列所带来的延迟问题。
- 可能存在的数据不一致问题。
利弊权衡间考虑你的系统是否需要引入消息队列。
2. RabbitMQ 简介
公司/社区: Rabbit
开发语言:Erlang (为高并发和分布式诞生的语言,电信领域使用广泛)
协议支持:AMQP、XMPP、SMTP、STOMP
客户端支持语言:官方支持 Erlang、Java、Ruby 等,社区提供几乎支持所有主流语言。
单机吞吐量: 万级
消息延迟: 微秒
功能特性:并发能力强,性能极好,低延迟,社区活跃,完善的管理界面。
下图是一个简单的模型,以及一些相关概念
2.1 什么是 AMQP
AMQP 全称 Advanced Message Queuing Protocol 即 高级消息队列协议,是一个应用层网络协议,专门面向消息队列的中间件进行设计的协议。基于此协议的客户端与消息中间件可以传递消息,不受不同 客户端/中间件/开发语言等条件限制。是一个通信规范。
2.2 基础架构模型
名词解释:
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 模式
这个模式简单理解就是 一对一的消费模式,一个生产者对应一个消费者,消息仅消费一次。
2. Work queues 工作队列模式
工作队列模式,与上面的简单模式区别是 可以多个生产者,然后由多个消费者一起消费消息,消息仅消费一次,对应的可以提高消息的处理速度。
3. Publish/Subscribe 发布订阅模式
到这里,发布订阅模式,路由模式,主题模式 其实结构上大同小异,区别仅仅是 交换机 Exchange 的绑定路由规则不同罢了。
同时在该模式下,一份消息会分发给符合条件的多个队列使用,且比上面的模式多了交换机的概念。
交换机 顾名思义 作用就是将生产者生产的消息,根据一定的规则分发到对应的队列中。
发布订阅模式的 Exchange 交换机是 Fanout 广播模式,即:将消息交给所有绑定到交换机的队列
4. Routing 路由模式
路由模式的 Exchange 交换机是 Direct 定向模式,即:把消息交给 routing key 路由对应的队列
5. Topics 主题模式
主题模式的 Exchange 交换机是 Topic 通配符模式,即:把消息交给 routing pattern 路由匹配的队列
6. RPC 远程调用模式
RPC 不是消息队列的重点,这里不做过多解释。RPC 有更多成熟的框架实现,个人不建议使用消息队列来实现。
消息的可靠性
消息生产端的可靠投递
在使用 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() 方法设置,这种模式下,发送错误的消息可以恢复。