RabbitMQ是什么
RabbitMQ 是基于 高级消息队列协议(AMQP)、Erlang 开发的开源消息中间件,优势在于消息路由灵活、投递可靠性高,适合业务告警、事件通知这类对消息可靠度要求高的场景。
核心组件
-
Producer(生产者):发送消息,消息先发给交换机 Exchange,不直接发给队列
-
Exchange(交换机):路由核心,本身不存消息;根据 routingKey 和绑定关系,把消息路由到队列
-
Binding(绑定):交换机和队列之间的绑定规则,包含 bindingKey
-
Queue(队列):存储消息,FIFO 先进先出,等待消费者消费
-
Consumer(消费者):监听队列,处理消息
-
Vhost(虚拟主机):资源逻辑隔离,多项目共用一套 RabbitMQ 时做权限隔离,类似命名空间
-
Channel(信道):TCP 连接上的轻量逻辑通道,一条 TCP 连接可复用多个 Channel,减少 TCP 连接开销
4 种交换机类型
-
Direct 直连交换机: 精确匹配 Routing Key 。routingKey 和 bindingKey 完全匹配;点对点通知,如指定设备告警推送
-
Fanout 扇出交换机:忽略 routingKey,消息广播到所有绑定队列;适合平台全局通知
-
Topic 主题交换机: 根据 routing key 模式匹配 进行路由,*匹配 1 个单词,#匹配 0 或多个单词,项目最常用,例如 iot.alarm.* 匹配 IoT 告警消息
-
Headers 头交换机:依靠消息 header 匹配,业务很少使用
四大经典问题
1. 消息丢失(三层保障)
-
生产者:开启 Publisher Confirm 确认机制 + Return 回退机制。Broker 收到消息返回 ACK;路由失败则退回生产者。
-
Broker:交换机持久化、队列持久化、消息持久化;集群采用仲裁队列(新版推荐)/ 镜像队列保证高可用。
-
消费者:手动 ACK,业务处理完成后再发送 ACK;自动 ACK 容易出现业务失败,消息却被删除,造成丢失。
2. 重复消费
场景:业务处理完毕、ACK 还没发送,服务宕机,重启后消息重新投递。 解决方案:业务幂等,用唯一业务标识(设备 ID + 消息时间戳),重复消息直接跳过,不重复执行业务。
3. 死信队列 DLQ
消息成为死信的 3 个条件: ① 消息被 reject/nack,并且不重新入队 ② 消息 TTL 超时 ③ 队列达到最大长度
用途:存放处理失败的异常消息;TTL + 死信交换机实现延迟队列(设备离线超时告警、订单超时关闭)
什么是死信队列
假设一条消息一直失败:
Message
↓
失败
↓
Retry
↓
失败
↓
Retry
↓
失败
如果无限重试:会造成消息积压。所以可以:
正常 Queue
↓
消费失败
↓
重试 N 次
↓
Dead Letter Queue
即:死信队列。之后由人工或者专门程序处理。
4. 消息堆积
生产速率大于消费速率。 优化手段:
-
优化消费业务逻辑,提升消费速度
-
增加消费者;设置 prefetch 预取值,控制单次推送给消费者的消息数量,避免一次性大量消息压垮消费者
-
海量堆积场景开启惰性队列 Lazy Queue,消息直接落盘,降低内存占用
消息确认机制(可靠性)
1 生产者确认(Publisher Confirm)
-
默认情况下,生产者发送消息到交换机后,Broker 不会通知是否成功。
-
开启发布确认模式后,Broker 会异步发送确认(Confirm)或未确认(Nack)信号。
-
生产者可据此重试发送未确认消息,避免消息丢失。
2 消费者确认(Consumer Ack)
-
默认自动确认(autoAck),消息从队列投递给消费者后立即删除。
-
改为手动确认(manual ack)后,消费者处理成功后发送 basicAck,处理失败可发送 basicNack 或 basicReject 将消息重新入队或丢弃。
-
结合 预取数量(Prefetch) 可控制每个消费者未确认消息的数量,实现公平分发。
3 持久化
-
队列持久化:声明队列时设置 durable=true,队列元数据存盘,Broker 重启队列不丢失。
-
消息持久化:发送消息时设置 delivery_mode=2,消息写入磁盘。
-
交换机持久化:声明交换机时设置 durable=true。
-
三者同时设置才能保证消息在 Broker 重启后不丢失,但仍有极小概率因刷盘时机问题丢失。
RabbitMQ 如何控制消费者速度?
RabbitMQ 可以通过:Prefetch Count
控制消费者一次预取多少消息。
prefetch = 10
prefetch 预取是什么?
prefetch 用来限制 MQ 一次性推送给消费者的消息条数,防止单个消费者一次性接收大量消息,引发堆积、内存溢出
RabbitMQ vs Kafka
-
RabbitMQ:AMQP 协议,路由能力强、可靠性高;吞吐量中等;适合业务告警、事件通知、延迟消息;消息堆积能力偏弱
-
Kafka:日志流模型,超高吞吐;适合海量设备上报、日志采集;路由能力弱,原生不擅长延迟消息
|--------|-----------------|----------------|
| 对比 | Kafka | RabbitMQ |
| 核心定位 | 高吞吐事件流 | 消息队列 |
| 吞吐量 | 很高 | 较高 |
| 消息模型 | Topic/Partition | Exchange/Queue |
| 消费模型 | Consumer Group | Consumer |
| 消息存储 | 日志 | Queue |
| 消费后消息 | 不立即删除 | 通常 ACK 后移除 |
| 顺序 | Partition 内有序 | Queue 内可保证一定顺序 |
| 扩展 | Partition 水平扩展 | Queue/集群扩展 |
| 历史消息 | 很强 | 相对弱 |
| 流式处理 | 非常适合 | 一般 |
| IoT数据流 | 很适合 | 可以 |