目录
前言
Broker端过滤
定义与概述
消息过滤分类
原理机制
使用场景
优缺点
Java代码示例 - Tag过滤
Java代码示例 - SQL92过滤
客户端过滤
定义与概述
原理机制
使用场景
优缺点
Java代码示例
总结
前言
消息过滤是RocketMQ的一项高级特性,它允许消费者根据特定的条件来筛选感兴趣的消息,从而避免无关消息的处理,提升消费效率和性能。RocketMQ支持两种主要的消息过滤方式:Broker端过滤和客户端过滤。注:文章中部分内容来源于Apache RocketMQ官网
Broker端过滤
定义与概述
Broker端过滤是指在Broker接收到消息后,基于消息的标签(Tag)或用户自定义属性进行过滤。只有满足过滤条件的消息才会被推送给消费者,从而减少消费者端的处理压力。
消息过滤分类
对比项 | Tag标签过滤 | SQL属性过滤 |
---|---|---|
过滤目标 | 消息的Tag标签。 | 消息的属性,包括用户自定义属性以及系统属性(Tag是一种系统属性)。 |
过滤能力 | 精准匹配。 | SQL语法匹配。 |
适用场景 | 简单过滤场景、计算逻辑简单轻量。 | 复杂过滤场景、计算逻辑较复杂。 |
原理机制
-
Tag过滤:每条消息可以带有一个或多个标签(Tag),消费者在订阅时可以指定感兴趣的标签,Broker只会将带有匹配标签的消息发送给消费者。这种方式过滤效率高,因为过滤逻辑是在Broker端实现的。
例如,如果某条消息的标签是
"TagA"
,消费者在订阅时指定只接收"TagA"
的消息,那么只有这些消息会被推送到消费者。
-
SQL92过滤:RocketMQ支持使用SQL92标准的语法对消息属性进行过滤。开发者可以在消息发送时设置自定义属性,消费者在订阅时使用SQL92表达式进行筛选。此方式更灵活,可以基于多种条件进行复杂的过滤。
例如,假设消息包含一个名为
"age"
的属性,消费者可以使用age > 30
这样的SQL语句进行过滤。
使用场景
- 高效消息消费:适用于有大量不同类型消息的场景,消费者只需处理特定类型的消息。例如,在订单系统中,不同的消费者可能只关注某些特定类型的订单消息。
- 复杂过滤需求:在需要基于多条件组合进行消息筛选时,SQL92过滤提供了很大的灵活性。
优缺点
-
优点:
- 减少网络流量:通过Broker端过滤,可以减少不必要的消息传输,降低网络带宽消耗。
- 提高消费效率:消费者只需处理满足过滤条件的消息,减少了处理无关消息的开销。
-
缺点:
- 处理复杂性增加:SQL92过滤需要消息带有自定义属性,增加了消息发送时的复杂性。
- 配置管理复杂:需要在消费者订阅时配置过滤规则,且过滤规则复杂度较高时可能增加运维管理的难度。
Java代码示例 - Tag过滤
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.message.MessageExt;public class TagFilterConsumer {public static void main(String[] args) throws MQClientException {DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("ConsumerGroupName");consumer.setNamesrvAddr("localhost:9876");consumer.subscribe("TopicTest", "TagA || TagB"); // 只订阅TagA或TagB的消息consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> {for (MessageExt msg : msgs) {System.out.printf("Received Message: %s%n", new String(msg.getBody()));}return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;});consumer.start();}
}
Java代码示例 - SQL92过滤
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.message.MessageExt;public class SQLFilterConsumer {public static void main(String[] args) throws MQClientException {DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("ConsumerGroupName");consumer.setNamesrvAddr("localhost:9876");consumer.subscribe("TopicTest", MessageSelector.bySql("age > 30"));consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> {for (MessageExt msg : msgs) {System.out.printf("Received Message: %s%n", new String(msg.getBody()));}return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;});consumer.start();}
}
客户端过滤
定义与概述
客户端过滤是指消息被发送到消费者后,由消费者在本地进行过滤。与Broker端过滤相比,客户端过滤的灵活性更高,因为消费者可以根据实际业务需求实现自定义的过滤逻辑。
原理机制
-
消息接收后过滤:消费者接收到消息后,在处理逻辑中根据业务需求进行过滤。此种方式不依赖于Broker的过滤机制,而是在消费者端实现特定逻辑。
例如,消费者可以在接收到消息后检查消息体的内容,决定是否处理该消息。
使用场景
- 个性化过滤需求:适用于需要根据复杂业务逻辑进行过滤的场景。例如,根据消息体内容进行复杂的判断,而不是简单的标签或属性匹配。
- 实时调整过滤规则:消费者可以在运行时动态调整过滤逻辑,适应变化的业务需求。
优缺点
-
优点:
- 高度灵活:可以实现任何复杂的过滤逻辑,完全由消费者自行控制。
- 动态调整:无需修改Broker配置,消费者可以随时根据业务需要调整过滤逻辑。
-
缺点:
- 增加网络负载:所有消息都会被传输到消费者,增加了网络带宽的占用。
- 效率较低:需要在客户端进行二次过滤,可能导致性能下降。
Java代码示例
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.message.MessageExt;public class ClientFilterConsumer {public static void main(String[] args) throws MQClientException {DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("ConsumerGroupName");consumer.setNamesrvAddr("localhost:9876");consumer.subscribe("TopicTest", "*"); // 订阅所有消息consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> {for (MessageExt msg : msgs) {// 自定义过滤逻辑if (new String(msg.getBody()).contains("specificWord")) {System.out.printf("Processing Message: %s%n", new String(msg.getBody()));// 处理消息}}return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;});consumer.start();}
}
总结
RocketMQ的消息过滤机制为开发者提供了多种选择:
- Broker端过滤适合需要高效过滤消息的场景,通过Tag或SQL92进行过滤,减少无关消息的传输和处理。
- 客户端过滤适用于需要灵活、自定义过滤逻辑的场景,虽然增加了网络负载,但提供了更大的灵活性。
选择合适的过滤方式取决于具体的业务需求和系统架构,在实际应用中可以结合使用,以达到最佳的性能和功能平衡。