一、消息队列
1.1、消息队列概述
消息队列,简而言之就是 消息 + 队列 (MessageQueue,简称MQ)
本质上是一种异步通信协议或中间件 ,其核心数据结构是队列,遵循先进先出(FIFO)原则,内容为消息
1.2、消息队列的用途
- 进程间通信
- 不同服务间通信
1.3、消息队列的应用场景
- 异步处理
- 流量控制
- 服务解耦
- 发布订阅
- 流量削峰/控制
1.4、为什么会有消息队列
在早期应用以及分布式系统架构中,各个服务之间调用,都是直接调用 ,或者通过RPC调用,服务之间耦合度太高,如果某个服务出现故障,整个系统都会受到影响。
比如用户的注册,注册服务需要调用到邮件服务,短信服务,支付服务等。

这种模式,会将所有服务都强耦合 在一起,如果某个服务出现故障,整个系统都会受到影响。
- 系统脆弱,容错率低:
- 如果邮件服务突然宕机 ,那么注册服务也会失败或者宕机,导致整个系统受到影响。
- 也称为雪崩效应 :一个非关键的服务故障,通过直接调用链扩散,导致整个关键业务不可用。注意和数据库的数据雪崩区分开来
- 系统性能瓶颈:
- 注册服务必须同步等待所有下游的服务全部完成之后,才能给用户反馈"注册成功"。整个过程耗时是所有服务耗时的总和,用户体验差。
- 系统扩展性差:
- 如果碰见大型活动,注册量突然暴增,邮件服务和短信服务可能无法承载这么大的流量,导致注册服务也跟着受影响,无法承载这么大的流量。
1.5、消息队列的引入
正是因为上述的痛点,所以需要引入一个中间人或公告栏 ,将各个服务进行解耦,从之前直接的、实时的调用,变为间接的,异步的调用。

- 解决性能瓶颈:
- 注册服务只需要将"用户已注册"这个消息快速写入到消息队列中,然后给用户反馈"注册成功",后续的邮件服务和短信服务等,通过异步的方式,从消息队列中获取到"用户已注册"这个消息,然后进行处理。
- 解决系统脆弱:
- 解耦:注册服务只依赖于消息队列,而不依赖邮件服务和短信服务等,即使邮件服务和短信服务等出现故障,也不会影响到注册服务。
- 削峰填谷:消息队列可以起到一个缓冲的作用,当流量暴增时,消息队列可以将这些请求缓存起来,然后慢慢处理,避免系统崩溃。高峰期的流量被削平 ,低峰期慢慢处理,这叫流量削峰。
- 解决系统扩展性差:
- 如果碰见大型活动,注册量突然暴增,可以根据每个服务的实际压力来进行动态扩容,比如注册服务扩容2倍,邮件服务扩容3倍,短信服务保持不变。
二、核心术语和概念
2.1、生产者/发布者:
产生和发送消息的一方
2.2、消费者/订阅者:
接收和消费消息的一方
2.3、(Broker)代理:
接收生产者发送的消息,并将消息传递给消费者,简而言之就是消息队列的服务器; 主要具备以下职责:
- 接收生产者发送的消息
- 存储消息(内存/磁盘)
- 路由消息(根据规则决定消息传递给哪个消费者)
- 投递消息(将消息投递给消费者)
2.4、主题/Topic:
消息队列的分类,生产者发送消息到主题,所有订阅了该主题的消费者都会收到该消息的副本。

(发布/订阅模型示意图)
生产者产生消息,发送给Broker,Broker根据消息的主题,将消息投递给订阅了该主题的消费者。
2.5、消费者组
消费者组(Consumer Group)是由多个消费者组成的集合,同一个消费者组内的消费者共享 一个消费队列,消费组内的消费者竞争 消费消息,从而实现消息的负载均衡;
一个主题可以被多个消费者组订阅,实现真正的广播(发布/订阅)。
三、消息队列的架构模式
消息队列主要通过两种基本模型来组织消息的传递,分别是点对点模型 和发布订阅模型。
3.1、点对点模型
- 核心关系 : 一对一,即一个生产者发送的消息,只能被一个消费者消费。
- 类比 :任务队列 ,比如之前的单机无锁队列以及线程池当中的任务队列,一个任务只能被一个线程执行。
- 工作流程:
- 生产者产生消息,发送给Broker
- Broker将消息存储到队列中,多个消费者监听队列
- 队列中的每条消息,在任意时刻只能被其中一个消费者取走
- 消费者处理完消息后,会告诉Broker该消息已经被处理,Broker会将该消息从队列中删除
- 关键特性 :
- 负载均衡:多个消费者共同消费一个队列中的消息,队列中的消息会被平均分配给多个消费者,提高处理能力
- 消息独占性:保证一个任务只被执行一次
- 产品代表:
- ActiveMQ
- RabbitMQ
3.2、发布订阅模型
-
核心关系 :一对多。一个消息会被所有订阅了该主题的消费者都收到一份副本。
-
类比:新闻广播或杂志订阅。出版社(生产者)发行一期杂志(消息),所有订阅了该杂志(主题)的读者(消费者)都会收到一本。
-
工作流程:
- 生产者将消息发布到某个主题。
- 多个消费者可以订阅自己感兴趣的主题。
- 消息到达主题后,会复制成多份,分别传递给所有活跃的订阅者。
-
关键特性:
- 广播与解耦:生产者完全不知道有多少个、是哪些订阅者。新加入的订阅者可以收到之后的新消息。
- 扇出处理:一个事件可以触发多个下游系统的并行动作。
-
产品代表:
- Kafka(核心模型)
- Redis的Pub/Sub
- RabbitMQ的Fanout Exchange
| 维度 | 点对点 | 发布订阅 |
|---|---|---|
| 核心目的 | 分发任务,实现负载均衡 | 广播事件,实现系统解耦与扇出 |
| 消息流向 | 一个队列,多个消费者竞争 | 一个主题,多个订阅者各得一份 |
| 消费者关系 | 竞争关系,瓜分任务 | 互不干扰 |
四、消息队列的主流产品
| 特性 | RabbitMQ | RocketMQ | Kafka | ZeroMQ | Redis |
|---|---|---|---|---|---|
| 核心定位 | 功能丰富、可靠的企业级消息代理 | 低延迟、高可靠、功能全面的金融级消息队列 | 高吞吐、持久化的分布式事件流平台 | 高性能、异步、轻量级的消息传递库 | 内存型、极高性能的数据结构服务器 |
| 吞吐量 | 十万级QPS | 十万级QPS | 百万级QPS | 百万级QPS | 极高(内存操作) |
| 延迟 | 微秒级 | 毫秒级 | 毫秒级 | 毫秒级 | 微秒级 |
| 可靠性 | 高,基于主从架构实现高可用 | 非常高,分布式架构 | 非常高,分布式架构,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用 | 不是一个独立的服务,要嵌套到自己的程序里面去 | 依赖配置,RDB/AOF持久化会丢部分数据 |
| 数据模型 | Queue + Exchange | Queue + Topic | 持久化日志,按主题-分区存储 | Socket | 多种数据结构,List/Stream/PubSub |
| 顺序性 | 单个队列保证FIFO | 分区内严格有序 | 分区内严格有序 | 不完全保证全局消息顺序 | 不保证 |