🚀 RocketMQ 消息过滤详解
Tag 过滤(Broker 端)|SQL92 属性过滤(Broker 端)|Filter Server(已不推荐)
在 RocketMQ 中,消息过滤是消费者只接收感兴趣消息的关键机制。它允许消费者在订阅时指定条件,避免接收大量无关消息,减轻网络和处理压力。
RocketMQ 提供了多种消息过滤方式,主要包括:
- Tag 过滤(轻量级,推荐)
- SQL92 属性过滤(灵活,推荐)
- Filter Server(旧版,已不推荐)
本文将深入解析这三种过滤机制的原理、使用方式、性能影响及最佳实践。
一、1. Tag 过滤(Broker 端)—— 轻量级标签过滤
✅ 定义:
Tag 是消息的子分类标签,消费者可以在订阅时通过 Tag 表达式只接收特定类型的消息。
🔧 使用方式:
// 发送消息时指定 Tag
Message msg = new Message("ORDER_TOPIC", "CREATE", "创建订单".getBytes());
producer.send(msg);
// 消费者只订阅 CREATE 类型的消息
consumer.subscribe("ORDER_TOPIC", "CREATE");
// 或订阅多个 Tag
consumer.subscribe("ORDER_TOPIC", "CREATE || PAY || CANCEL");
// 订阅所有 Tag
consumer.subscribe("ORDER_TOPIC", "*");
📌 支持的语法:
| 表达式 | 说明 |
|---|---|
"CREATE" | 精确匹配 |
| `"CREATE | |
"*" | 通配,订阅所有 Tag |
⚠️ 注意:Tag 是字符串匹配,不支持正则。
✅ 工作机制:
- Broker 端过滤:在
ConsumeQueue构建时,将tagsCode(Tag 的哈希值)写入 - 消费者拉取时,Broker 根据
tagsCode快速过滤,只返回匹配的消息
✅ 优点:
| 优势 | 说明 |
|---|---|
| 高性能 | 基于哈希值过滤,速度快 |
| 低开销 | 不需要额外计算 |
| 简单易用 | 开发者熟悉,语义清晰 |
❌ 限制:
| 问题 | 说明 |
|---|---|
只能基于 tags 字段 | 无法根据消息体或其他属性过滤 |
| 不支持复杂条件 | 如 age > 18 |
🎯 适用场景:
- 按业务类型过滤(如
CREATE,PAY,REFUND) - 简单的分类订阅
二、2. SQL92 属性过滤(Broker 端)—— 灵活的表达式过滤
✅ 定义:
基于 SQL92 标准子集,消费者可以使用 SQL 表达式对消息的 用户属性(User Properties) 进行过滤。
🔧 使用方式:
(1)发送消息时设置属性
Message msg = new Message("ORDER_TOPIC", "TAGA", "订单数据".getBytes());
msg.putUserProperty("orderType", "VIP");
msg.putUserProperty("amount", "500");
msg.putUserProperty("city", "beijing");
producer.send(msg);
(2)消费者使用 SQL 表达式订阅
// 只消费 VIP 且金额大于 100 的订单
consumer.subscribe("ORDER_TOPIC",
MessageSelector.bySql("orderType = 'VIP' AND amount > 100"));
// 支持 OR、IN、BETWEEN、>、<、= 等
consumer.subscribe("ORDER_TOPIC",
MessageSelector.bySql("city IN ('beijing', 'shanghai')"));
✅ 工作机制:
- Broker 端执行 SQL 过滤
- 消息的
UserProperty被提取并参与计算 - 只将满足条件的消息返回给消费者
✅ 优点:
| 优势 | 说明 |
|---|---|
| 灵活强大 | 支持复杂条件组合 |
| 基于属性 | 可根据业务字段动态过滤 |
| Broker 端执行 | 减少网络传输和消费者压力 |
⚠️ 注意事项:
| 问题 | 说明 |
|---|---|
| 性能低于 Tag 过滤 | 需要解析 SQL 和计算表达式 |
只能使用 putUserProperty 设置的属性 | 不能过滤 Body 内容 |
需要开启 broker 配置 | enablePropertyFilter=true |
🛠️ Broker 配置(broker.conf):
# 开启 SQL 属性过滤功能
enablePropertyFilter=true
⚠️ 默认关闭,生产环境需手动开启。
🎯 适用场景:
- 动态路由(如按用户等级、地区、金额)
- A/B 测试消息分发
- 灰度发布
三、3. Filter Server(已不推荐)—— 旧版客户端过滤
✅ 历史背景:
在早期版本中,RocketMQ 支持通过 Filter Server 实现复杂的过滤逻辑(如基于消息体的过滤)。
🔧 工作机制:
Producer → 发送消息到 Broker
↓
Consumer → 向 Filter Server 注册过滤逻辑(Java Class)
↓
Filter Server 从 Broker 拉取消息
↓
执行过滤逻辑(如解析 JSON 判断字段)
↓
将匹配的消息推送给 Consumer
❌ 为什么被废弃?
| 问题 | 说明 |
|---|---|
| 安全风险 | 需上传 Java 类,存在代码注入风险 |
| 运维复杂 | 需独立部署 Filter Server 集群 |
| 性能差 | 多跳传输,延迟高 |
| 不支持容器化 | 难以在 Kubernetes 等环境部署 |
🚫 Filter Server 已从 4.0 版本起被标记为“不推荐”,官方建议使用 SQL92 替代。
✅ 现代替代方案:
- SQL92 属性过滤:推荐用于大多数场景
- 消费者端过滤:在
MessageListener中手动判断(适合简单逻辑) - 外部流处理引擎:如 Flink + RocketMQ,实现复杂规则引擎
四、三种过滤方式对比总结
| 特性 | Tag 过滤 | SQL92 属性过滤 | Filter Server |
|---|---|---|---|
| 过滤位置 | Broker 端 | Broker 端 | Filter Server |
| 性能 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐ |
| 灵活性 | 低(仅 Tag) | 高(SQL 表达式) | 极高(任意逻辑) |
| 安全性 | 高 | 高 | 低(代码注入) |
| 是否推荐 | ✅ 强烈推荐 | ✅ 推荐 | ❌ 已废弃 |
| 配置要求 | 无 | enablePropertyFilter=true | 需部署 Filter Server |
| 适用场景 | 简单分类 | 动态条件 | 已淘汰 |
五、最佳实践建议
| 实践 | 说明 |
|---|---|
| ✅ 优先使用 Tag 过滤 | 简单、高效、安全 |
| ✅ 复杂条件使用 SQL92 属性过滤 | 开启 enablePropertyFilter |
✅ 发送消息时合理设置 putUserProperty | 为过滤提供数据支持 |
| ❌ 避免使用 Filter Server | 已过时,有安全风险 |
| ✅ 消费者端可做二次过滤 | 如幂等判断、业务校验 |
| ✅ 避免在 SQL 中使用复杂函数 | 影响 Broker 性能 |
| ✅ 监控过滤后的消费量 | 确保逻辑正确 |
六、常见问题排查
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| SQL 过滤无效 | enablePropertyFilter=false | 在 broker.conf 中开启 |
| Tag 过滤不生效 | 表达式错误(如空格) | 使用 ` |
| 消费者收不到消息 | 过滤条件太严格 | 检查 SQL 或 Tag 配置 |
| Broker CPU 高 | 大量 SQL 过滤 | 优化条件或改用 Tag |
| 消息体无法过滤 | SQL92 不支持 Body | 将关键字段放入 UserProperty |
✅ 总结
| 过滤方式 | 核心思想 | 一句话总结 |
|---|---|---|
| Tag 过滤 | 轻量标签,快速匹配 | “按标签分类,简单高效” |
| SQL92 属性过滤 | 灵活表达式,动态路由 | “像查数据库一样过滤消息” |
| Filter Server | 旧版复杂过滤 | “已被淘汰,切勿使用” |
🚀 最终建议:
- 80% 场景用 Tag 过滤
- 20% 复杂场景用 SQL92 属性过滤
- 永远不要用 Filter Server
掌握这两种现代过滤机制,你就能在性能、灵活性、安全性之间取得最佳平衡,构建高效的消息订阅系统。
1789

被折叠的 条评论
为什么被折叠?



