RabbitMQ消费者如何实现过滤不读取自身生产的消息?
实现方案整理
以下方案按架构改动成本从低到高排序,可根据自身业务场景选择:
方案1:消费端本地过滤(改动最小,无需调整现有队列架构)
- 核心思路:所有消息发送时携带全局唯一的生产者标识,消费者收到消息后先匹配标识,过滤掉自身生产的消息再处理
- 实现步骤:
- 每个客户端启动时生成/配置全局唯一的
client_id,必须保证不同客户端的id不重复,否则会出现消息误过滤 - 生产者发送消息时,将自身
client_id作为消息的固定字段一起写入队列 - 消费者拉取/收到消息后,先判断消息携带的生产者id是否和自身id一致,一致则直接丢弃该消息,不一致才进入业务处理逻辑
- 每个客户端启动时生成/配置全局唯一的
- 代码示例(伪代码):
// 客户端初始化时生成唯一ID const MY_CLIENT_ID = generateGlobalUniqueId() // 生产者逻辑 function publishMessage(content) { const message = { data: content, producer_id: MY_CLIENT_ID } queue.send(message) } // 消费者逻辑 function handleMessage(message) { if (message.producer_id === MY_CLIENT_ID) { return // 跳过自身生产的消息 } // 正常业务处理 processMessageData(message.data) }
- 优缺点:
- 优点:开发成本极低,完全不用调整现有队列架构,兼容任意消息队列组件
- 缺点:无效消息仍然会传输到消费端,消息量级极大时会浪费少量带宽和消费端算力
方案2:服务端属性过滤(中等改动,性能更高)
- 核心思路:利用主流消息队列自带的服务端过滤能力,直接在队列服务侧过滤掉自身生产的消息,无效消息不会传输到消费端
- 实现步骤:
- 同方案1,每个客户端生成全局唯一的
client_id,发送消息时将producer_id作为消息属性/标签携带 - 消费者订阅队列时,向消息队列服务端注册过滤规则:
producer_id != 自身的client_id - 队列服务端仅会将符合过滤规则的消息推送给消费者,自身生产的消息直接在服务端被过滤
- 同方案1,每个客户端生成全局唯一的
- 适用场景:
目前Kafka、RocketMQ、RabbitMQ、Pulsar等主流消息队列均支持该类属性过滤规则,适合消息量级大、客户端数量较多的场景,兼顾改造成本和性能
方案3:多队列路由分发(架构调整,无性能损耗)
- 核心思路:为每个客户端分配专属的消费队列,生产者发送消息时,直接将消息路由到除自身专属队列之外的所有其他客户端队列,消费者仅监听自己的专属队列
- 实现示例:
假设存在A、B、C三个客户端,分别对应专属队列qA、qB、qC:- A生产消息时,仅发送到
qB和qC - B生产消息时,仅发送到
qA和qC - C生产消息时,仅发送到
qA和qB
每个客户端仅消费自己对应的专属队列,自然不会收到自身生产的消息
- A生产消息时,仅发送到
- 优缺点:
- 优点:完全没有无效消息的传输和过滤逻辑,性能最高
- 缺点:队列数量会随客户端数量线性增长,仅适合客户端数量固定且规模不大(通常<50)的场景
选型建议
- 快速落地、客户端数量少:优先选方案1
- 消息量大、客户端数量多:优先选方案2
- 客户端数量固定、对性能要求极致:优先选方案3
内容的提问来源于stack exchange,提问作者ZedZip
相关产品推荐
相关产品推荐

