携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第10天,点击查看活动详情
1 初衷
RocketMQ设计了消息过滤来解决消费者的定制化消费,当消费者需要某一种消息时,Broker就会剔除不不需要的消息,并只将这类消息传输给客户端,以免浪费带宽。
2 Tag过滤
步骤:
- 用户发送一个带Tag的消息
- 用户订阅一个Topic的Tag,Broker会保存这个订阅关系。
- 在Broker端做Tag过滤。当消费者在Pull消息的时候,Broker会根据Tag的HashCode进行对比。若是不满足条件,则不会将消息发送给消费者。
- 客户端进行Tag过滤,进行字符串比对来做第二次Tag过滤。
这里由于HashCode比对存在哈希碰撞的缘故,所以需要在客户端再进行一次过滤。以确定处理的消息均为需要的消息
订阅topic的时候可以指定tag名字
//订阅topic
consumer.subscribe("topic_luke","tag");
为*时不过滤任何消息,需要订阅多个tag用||隔开,例如tag_a||tag_b
在org.apache.rocketmq.client.impl.consumer.PullAPIWrapper#processPullResult中有过滤tag的逻辑。
if (!subscriptionData.getTagsSet().isEmpty() && !subscriptionData.isClassFilterMode()) {
msgListFilterAgain = new ArrayList<MessageExt>(msgList.size());
for (MessageExt msg : msgList) {
if (msg.getTags() != null) {
if (subscriptionData.getTagsSet().contains(msg.getTags())) {
msgListFilterAgain.add(msg);
}
}
}
}
3 SQL过滤
步骤:
- 消费者订阅Topic,上传SQL过滤语句。Broker会编译SQL并保存。
- 消费者Pull消息
- 第一次过滤,使用Bloom过滤器的isHit()方法做第一次过滤,这个和HashCode作比较一样,会过滤大部分不需要的消息,过滤之后的消息也不全是需要的
- 第二次过滤,执行编译之后SQL方法的evaluate()即可得到需要的消息。
使用SQL过滤的时候,在Broker配置中需要加入如下参数:
enableConsumeQueueExt = true;
filterSupportRetry = true;
enablePropertyFilter = true;
enableCalcFilterBitMap = true;
订阅Topic的时候可以指定SQL语句
consumer.subscribe("topic_luke","sex IS NOT NULL and sex = 1");
这里的语法支持为:
- 数值比较,比如:
>,>=,<,<=,BETWEEN,=; - 字符比较,比如:
=,<>,IN; IS NULL或者IS NOT NULL;- 逻辑符号
AND,OR,NOT;
常量支持类型为:
- 数值,比如:
123,3.1415; - 字符,比如:
'abc',必须用单引号包裹起来; NULL,特殊的常量;- 布尔值,
TRUE或FALSE