[TOC] #### 1. 回顾一下 --- 上一讲我们聊了:异步、解耦、削峰,知道了在系统之间加一个队列,很多问题就能一起解决。 但你可能会想:队列 ?我用 Redis 的 List 也能当队列使啊,`LPUSH` 存进去,`RPOP` 取出来。 或者我建一张 MySQL 表,往里面插数据,后台定时去查,不也是队列吗? 为什么非得搞一个独立的「消息队列」组件出来 ?今天我们就来聊聊这个问题。 #### 2. 先看没有消息队列的系统 --- 假设你有三个系统:订单系统、短信系统、物流系统,订单系统需要通知短信系统和物流系统,直接调用: ```plaintext 订单系统 --- HTTP ---> 短信系统 订单系统 --- HTTP ---> 物流系统 ``` 每加一个系统,订单系统就多一个调用 订单系统变成了一个「调度中心」,什么都得管,而且任何一个下游系统挂了,订单都可能受影响。 #### 3. 加了消息队列之后 --- 在中间放一个消息队列: ```plaintext 订单系统 --- 发消息 ---> 消息队列 --- 取消息 ---> 短信系统 --- 取消息 ---> 物流系统 --- 取消息 ---> 积分系统 --- 取消息 ---> 优惠券系统 ``` 订单系统只做一件事:把消息丢进队列。 它不关心谁来取,不关心有几个消费者,不关心对方挂没挂。 以后再加新系统 ?不用改订单代码,新系统自己去队列里订阅就行。 #### 4. 消息队列到底是什么 --- 看到这里,你应该能感觉到:消息队列不是某个系统内部的功能,它是独立部署在多个系统之间的一层基础设施。 消息队列: + 生产者(订单系统)把消息丢进去 + 消费者(短信、物流、积分)从里面取出来 + 生产者和消费者之间不需要直接联系 三个角色: + 生产者:往队列里发消息的系统 + 队列:暂存消息的地方(RabbitMQ) + 消费者:从队列里取消息处理的系统 ```plaintext 生产者 --- 发消息 ---> 队列(RabbitMQ) ---> 取消息 ---> 消费者 ``` #### 5. 为什么不能用 Redis 或 MySQL 模拟 --- 你可能会想:道理我懂了,但我用 Redis List 或者 MySQL 表模拟一个队列,不也能实现吗? 小规模、简单场景下,确实能凑合用。但消息队列是专门为消息传递设计的,它做了很多 Redis 和 MySQL 不擅长的事情 + 比如消息确认:消费者取了消息,处理到一半挂了,消息队列会把这条消息重新投递给其他消费者,不会丢 + 比如消息持久化:就算 RabbitMQ 重启,消息也不会丢 + 比如多消费者协作:一条消息进去,多个消费者都能收到,天然支持 这些能力,用 Redis 或 MySQL 模拟的话,要自己写大量逻辑,而且很难写对。 就像你可以用菜刀削苹果,但水果刀削起来更顺手,专业的事情,交给专业的工具。 #### 6. 本文小结 --- 消息队列本质上是一个 “独立运行的消息中转服务”。 它不在任何一个系统内部,而是部署在系统之间,它的价值不是存数据,而是负责系统之间的消息传递。 生产者只管发,消费者只管收,中间的队列负责中转和暂存。 虽然用 Redis 或 MySQL 也能模拟队列,但在可靠性、扩展性方面,专业的消息队列做得更好。 下一讲,我们来聊聊市面上主流的消息队列:RabbitMQ、Kafka、RocketMQ,它们有什么区别,该怎么选。