【MQ】RabbitMQ:架构、工作模式、高可用与流程解析
【MQ】RabbitMQ:架构、工作模式、高可用与流程解析
- 一、RabbitMQ 整体结构
- 二、RabbitMQ 的 4 种工作模式
- 1. Fanout 交换机:广播模式
- 2. Direct 交换机:点对点模式
- 3. Topic 交换机:通配符匹配模式
- 4. Headers 交换机:基于消息头匹配
- 三、RabbitMQ 的高可用
- 1. 普通集群
- 2. 镜像集群
- 四、RabbitMQ 的数据分片
- 五、RabbitMQ 的工作流程
一、RabbitMQ 整体结构
-
生产者:发消息,把业务数据包成消息,通过网络发给 RabbitMQ 服务端(也就是 Broker)。
-
消费者:收消息,和 Broker 连起来,订阅指定的队列,拿到消息后就去执行业务逻辑,比如处理订单、发通知。
-
Broker:可以理解成 RabbitMQ 本身 —— 负责接生产者发的消息,把消息存到磁盘(可选),管着队列和交换机的关系,处理消费者要消息的请求。
二、RabbitMQ 的 4 种工作模式
Kafka也好,RocketMQ也好,他们都抽象出了一个Topic的概念,消息需要被发送到某个Topic下面,然后实际存储到某个队列里面,但是队列这个概念实际上是对用户屏蔽的,用户实际感知的其实是消息和Topic,但RabbitMQ的设计是完全不一样的。
RabbitMQ为了消息的灵活路由,设计了一个交换机,交换机通过绑定关系去和队列绑定,然后把消息转发到对应的队列,然后消费者去监听队列获取消息。
1. Fanout 交换机:广播模式
Fanout交换机把消息路由到这个交换机绑定的所有队列里面。
比如系统通知、日志同步,像把操作日志同时发到 “日志存储队列” 和 “日志告警队列”,就适合用这个。
2. Direct 交换机:点对点模式
Direct交换机呢,就根据你发消息时的Routing Key,然后把消息路由到对应的Binding Key绑定的队列里面,这两个Key只要是一样的,它就给你路由到对应的队列里面,这个就是点对点的方式了。
比如用户下单后,“订单支付消息” 只发给 “订单处理队列”,这种点对点的场景就用它。
3. Topic 交换机:通配符匹配模式
Topic交换机和Direct交换机差不多,但是绑定队列的时候可以用通配符,就更加灵活一点。
Binding Key 可以用两种通配符:
-
:匹配一个单词,比如 “order.” 能匹配 “order.pay”“order.refund”,但匹配不了 “order.pay.success”;
-
#:匹配零个或多个单词,比如 “order.#” 能匹配 “order.pay”“order.pay.success”。
像按地区分的订单消息,把 “北京的订单” 转到 “order.beijing” 队列,“上海的订单” 转到 “order.shanghai” 队列,就适合用这个,灵活度高。
4. Headers 交换机:基于消息头匹配
Headers交换机它不靠 Routing Key 的匹配规则来路由消息,而是看消息头(Header)里的键值对 —— 绑队列时定一组 Header 规则,只有消息头满足规则,才会转到这个队列。
但它用起来麻烦,性能还不好,实际开发里很少用,能被 Topic 替代。
三、RabbitMQ 的高可用
单节点的 RabbitMQ 有单点故障风险,一旦节点挂了,消息服务就断了。RabbitMQ 有两种集群模式,能解决高可用问题:
1. 普通集群
集群里所有节点会同步 “元数据”,比如队列名、交换机类型、绑定关系这些,但消息只存在 “创建队列的节点” 上(叫 “队列主节点”)。其他节点只存 “指向主节点的引用”,不存消息本身。
优点是省存储空间,元数据同步不重;但缺点很明显 —— 要是主节点挂了,这个队列的消息就没法用了,就算其他节点活着也没用,没法实现真的高可用。适合只需要分担连接压力,对消息可用性要求不高的场景。
2. 镜像集群
镜像集群就是说集群里面的每个节点,都会有这个队列的完整镜像。
就是可以部署一个主节点,然后部署几个镜像节点作为备份,读写都是主节点来处理,然后主节点同步给镜像节点。
这和Kafka的多副本机制基本上是类似的,相当于对队列做多个副本,你写消息到某个队列的时候,它就可以把这个消息自动同步到其他节点的队列上,其实就是一种多副本的机制,你也可以理解为是一种主从或者主备的机制。
优点是容灾能力强,能实现真高可用;但缺点是消息同步会增加网络开销,节点越多,同步压力越大。适合支付、订单这种对消息可用性要求高的核心业务。
四、RabbitMQ 的数据分片
如果业务数据量特别大,单节点存不下全量数据,就需要数据分片 —— 把数据分到多个节点存。但 RabbitMQ原生不支持数据分片,得用官方提供的rabbit_sharding
插件实现:
-
创建 “分片交换机”(插件提供的)和多个 “物理分片队列”,这些物理队列会分到集群的不同节点;
-
配置分片策略,比如按 Routing Key 哈希、轮询;
-
生产者把消息发到分片交换机,插件按策略自动把消息转到不同节点的物理分片队列;
-
消费者订阅分片交换机,插件会协调消费者从不同物理队列拿消息。
数据分片的思路就是:一个节点存不了全量数据,那就让集群的每个节点只保存部分数据,然后通过负载均衡算法让请求路由到对应的节点。这和 MongoDB 的分片集群、Redis 的分片集群思路差不多。
五、RabbitMQ 的工作流程
RabbitMQ 的消息流转流程:
-
准备工作:先在 Broker 里创建交换机和队列,再用绑定键(Binding Key)把它们绑好;
-
生产者连 Broker:生产者通过 TCP 和 Broker 建立连接,创建信道(Channel)—— 复用连接能减少网络开销;
-
生产者发消息:指定交换机名称和 Routing Key,把消息发给交换机;
-
交换机路由消息:交换机按自己的类型(比如 Direct/Topic)和绑定规则,匹配 Routing Key 和 Binding Key,把消息转到对应的队列;
-
消息持久化:要是队列开了持久化,Broker 会把消息写到磁盘,防止节点挂了丢消息;
-
消费者消费消息:消费者和 Broker 连起来,订阅目标队列,拿到消息后执行业务逻辑,执行完给 Broker 发 “确认信号(Ack)”,Broker 收到 Ack 就把队列里的这条消息删了。