1. 概述
FilterServer 是 RocketMQ 的服务端消息过滤机制,允许在 Broker 端进行消息过滤,减少网络传输和客户端处理压力。
2. Filter Server架构

3. FilterServer 使用方式
3.1 基于 Tag 的简单过滤(常用)
// Producer - 发送带 Tag 的消息
Message msg = new Message("TopicTest", "TagA", "Hello Filter".getBytes());
SendResult sendResult = producer.send(msg);
// Consumer - 订阅时指定 Tag
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("consumer_group");
// 只消费 TagA 的消息
consumer.subscribe("TopicTest", "TagA");
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
ConsumeConcurrentlyContext context) {
// 这里只会收到 TagA 的消息
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
3.2 基于 SQL92 的复杂过滤
发送时指定properties,消费时根据properties的属性进行sql过滤
注意⚠️: 设置如下broker配置,默认为false
enablePropertyFilter=true
3.2.1 Producer 发送带属性的消息
public class SQLFilterProducer {
public static void main(String[] args) throws Exception {
DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");
producer.start();
// 发送带属性的消息
for (int i = 0; i < 10; i++) {
Message msg = new Message("TopicTest",
"TagA",
("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));
// 设置消息属性
msg.putUserProperty("a", String.valueOf(i));
msg.putUserProperty("b", "hello");
msg.putUserProperty("c", "world");
msg.putUserProperty("price", String.valueOf(100 + i));
msg.putUserProperty("region", i % 2 == 0 ? "Beijing" : "Shanghai");
SendResult sendResult = producer.send(msg);
System.out.printf("%s%n", sendResult);
}
producer.shutdown();
}
}
3.2.2 Consumer 使用 SQL 过滤
public class SQLFilterConsumer {
public static void main(String[] args) throws Exception {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name");
// 使用 SQL92 语法进行消息过滤
// 只消费 a between 0 and 3 的消息
consumer.subscribe("TopicTest",
MessageSelector.bySql("a between 0 and 3"));
// 或者使用多个条件
// consumer.subscribe("TopicTest",
// MessageSelector.bySql("a > 2 AND b = 'hello' AND region = 'Beijing'"));
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
ConsumeConcurrentlyContext context) {
for (MessageExt msg : msgs) {
System.out.printf("Receive message: %s, Properties: %s%n",
new String(msg.getBody()),
msg.getProperties());
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();
System.out.printf("SQL Filter Consumer Started.%n");
}
}
3.3 自定义类过滤(高级用法)
3.3.1 创建自定义过滤类
// 自定义过滤类
public class MyMessageFilter implements MessageFilter {
@Override
public boolean match(MessageExt msg, FilterContext context) {
// 自定义过滤逻辑
String body = new String(msg.getBody());
String region = msg.getProperty("region");
// 示例:只接受北京地区且包含"important"的消息
return "Beijing".equals(region) && body.contains("important");
}
}
3.3.2 Consumer 使用 Class Filter
// Consumer - 订阅时指定 fullClassName
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("consumer_group");
consumer.subscribe("TopicTest", "full class name", "class source code");
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
ConsumeConcurrentlyContext context) {
// 这里只会收到 TagA 的消息
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
/**
* Subscribe a topic to consuming subscription.
*
* @param topic topic to consume.
* @param fullClassName full class name,must extend org.apache.rocketmq.common.filter.MessageFilter
* @param filterClassSource class source code,used UTF-8 file encoding,must be responsible for your code safety
*/
@Override
public void subscribe(String topic, String fullClassName, String filterClassSource) throws MQClientException {
this.defaultMQPushConsumerImpl.subscribe(withNamespace(topic), fullClassName, filterClassSource);
}
4. SQL92 语法支持
4.1 支持的运算符
-- 数值比较
a > 10
a <= 100
a BETWEEN 0 AND 100
-- 字符串比较
b = 'hello'
b IS NOT NULL
b IN ('hello', 'world')
-- 逻辑运算符
a > 10 AND b = 'hello'
a < 5 OR b = 'world'
NOT (a > 10)
-- 空值判断
c IS NULL
c IS NOT NULL
4.2 实际使用示例
// 价格在100-200之间的北京订单
consumer.subscribe("OrderTopic",
MessageSelector.bySql("price BETWEEN 100 AND 200 AND region = 'Beijing'"));
// 特定用户ID的消息
consumer.subscribe("UserTopic",
MessageSelector.bySql("userId IN (1001, 1002, 1003)"));
// 排除测试消息
consumer.subscribe("LogTopic",
MessageSelector.bySql("env != 'test' AND level = 'ERROR'"));
5. 过滤方式对比

总结
FilterServer 最适合的场景:
- 需要服务端过滤减少网络传输
- 过滤条件相对固定且简单
- 不同消费者需要不同数据视图
- 消息量较大,客户端处理压力大
简单过滤用 Tag,复杂过滤用 SQL92,特殊需求用自定义过滤类。
550

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



