1 背景
消息队列作为发布订阅模型的消息中间件广泛应用于上下游业务集成场景。在实际业务场景中,同一个主题下的消息往往会被多个不同的下游业务方处理,各下游的处理逻辑不同,只需要关注自身逻辑需要的消息子集。所以在 消息中心和消费者之间,需要有一种消息过滤功能,可以帮助消费者更高效地过滤自己需要的消息集合,避免大量无效消息投递给消费者,降低下游系统处理压力。
Apache RocketMQ 很好的支持了这一能力,它解决了单个业务域即同一个主题内不同消息子集的过滤问题。
2 关于消息过滤
2.1 概念
在消费者订阅了某个主题后,Apache RocketMQ 会将该主题中的所有消息投递给消费者。若消费者只需要关注部分消息,可通过设置过滤条件在 Apache RocketMQ 服务端进行过滤,只获取到需要关注的消息子集,避免接收到大量无效的消息。所以,过滤的本质就是将符合条件的消息投递给消费者,而不是将匹配到的消息过滤掉。
Apache RocketMQ 的消息过滤功能通过生产者和消费者对消息的属性、标签进行定义,并在 Apache RocketMQ 服务端根据过滤条件进行筛选匹配,将符合条件的消息投递给消费者进行消费。
2.2 消息过滤说明
2.2.1 原理介绍
备注:图片直接使用官网提供的
消息过滤主要通过以下几个关键流程实现:
- 生产者:生产者在初始化消息时预先为消息设置一些属性和标签,用于后续消费时指定过滤目标。
- 消费者:消费者在初始化及后续消费流程中通过调用订阅关系注册接口,向服务端上报需要订阅指定主题的哪些消息,即过滤条件。
- 服务端:消费者获取消息时会触发服务端的动态过滤计算,Apache RocketMQ 服务端根据消费者上报的过滤条件的表达式进行匹配,并将符合条件的消息投递给消费者。
2.2.2 消息过滤分类
Apache RocketMQ 支持Tag标签过滤和SQL属性过滤,这两种过滤方式对比如下:
对比项 | Tag标签过滤 | SQL属性过滤 |
---|---|---|
过滤目标 | 消息的Tag标签。 | 消息的属性,包括用户自定义属性以及系统属性(Tag是一种系统属性)。 |
过滤能力 | 精准匹配。 | SQL语法匹配。 |
适用场景 | 简单过滤场景、计算逻辑简单轻量。 | 复杂过滤场景、计算逻辑较复杂。 |
2.3 Tag标签过滤
Tag标签过滤方式是 Apache RocketMQ 提供的基础消息过滤能力,基于生产者为消息设置的Tag标签进行匹配。生产者在发送消息时,设置消息的Tag标签,消费者需指定已有的Tag标签来进行匹配订阅。
Tag标签设置规则:
- Tag由生产者发送消息时设置,每条消息允许设置一个Tag标签。
- Tag使用可见字符,建议长度不超过128字符。
生产消息:发送的时候,需要设置Tag标签
Message message = messageBuilder.setTopic("topicTest")
//设置消息索引键,可根据关键字精确查找某条消息
.setKeys("msgKey")
//设置消息Tag,这样消费端可以根据Tag过滤消息
//该语句表示消息的Tag设置为"TagTest1"
.setTag("TagTest1")
// 设置消息体
.setBody("hello world!".getBytes())
.build();
订阅消息:匹配单个或者多个Tag标签。
String topic = "topicTest";
//1、第一种情况,只订阅消息标签为"TagTest1"的消息。
FilterExpression filterExpression = new FilterExpression("TagTest1", FilterExpressionType.TAG);
//2、第二种情况,订阅消息标签为"TagTest1"、"TagTest2"或"TagTest3"的消息。
FilterExpression filterExpression = new FilterExpression("TagTest1||TagTest2||TagTest3", FilterExpressionType.TAG);
pushConsumer.subscribe(topic, filterExpression);
如上,消费者可以限制接收包含 TagTest1 或 TagTest2 或 TagTest3 的消息,但是限制是一个消息只能有一个标签,这无法应对互联网复杂的应用场景。在这种情况下,可以在消息中设置一些属性,再使用SQL表达式通过筛选属性来筛选消息。下面我们看看怎么实现。
2.4 SQL属性过滤
SQL属性过滤是 RocketMQ 提供的高级消息过滤方式,通过生产者为消息设置的属性(Key)及属性值(Value)进行匹配。生产者在发送消息时可设置多个属性,消费者订阅时可设置SQL语法的过滤表达式过滤多个属性。
2.4.1 基本语法
RocketMQ只定义了一些基本语法来支持这个特性。你也可以很容易地扩展它。
- 数值比较,比如:>,>=,<,<=,BETWEEN,=;
- 字符比较,比如:=,<>,IN;
- IS NULL 或者 IS NOT NULL;
- 逻辑符号 AND,OR,NOT;
常量支持类型为:
- 数值,比如:123,3.1415;
- 字符,比如:‘abc’,必须用单引号包裹起来;
- NULL,特殊的常量
- 布尔值,TRUE 或 FALSE
只有使用push模式的消费者才能用使用SQL92标准的sql语句,接口如下:
public void subscribe(finalString topic, final MessageSelector messageSelector)
2.4.2 消息生产者
发送消息时,设置了消息Tag标签并定义了属性,用于做消息过滤
Message message = messageBuilder.setTopic("topicTest")
//设置消息索引键,可根据关键字精确查找某条消息
.setKeys("msgKey")
//设置消息Tag,这样消费端可以根据Tag过滤消息
//该语句表示消息的Tag设置为"TagTest1"
.setTag("TagTest1")
//消息也可以设置自定义的分类属性,比如下面这句话表示为消息自定义一个属性,该属性为性别,属性值为1(男)或者0(女)。
.addProperty("Sex", 1)
// 设置消息体
.setBody("hello world!".getBytes())
.build();
2.4.3 消息消费者
使用过滤表达式进行消息筛选,如下:
String topic = "topic";
//只订阅性别为1(男)的消息。
FilterExpression filterExpression = new FilterExpression("Sex IS NOT NULL AND Sex=1", FilterExpressionType.SQL92);
simpleConsumer.subscribe(topic, filterExpression);
//只订阅性别为1(男)且年龄大于18的消息。
FilterExpression filterExpression = new FilterExpression("Sex IS NOT NULL AND Age IS NOT NULL AND Sex = 1 AND Age > 18", FilterExpressionType.SQL92);
simpleConsumer.subscribe(topic, filterExpression);
//订阅所有消息
FilterExpression filterExpression = new FilterExpression("True", FilterExpressionType.SQL92);
simpleConsumer.subscribe(topic, filterExpression);
3 总结
Rocket MQ的消息过滤功能是在服务端进行的,可以根据消息的标签、属性等进行过滤。具体来说,Rocket MQ主要支持以下两种过滤方式:
TAG过滤:TAG是消息的业务标识,可以通过设置Tag表达式,判断消息是否包含指定的Tag,从而进行过滤。这种过滤方式简单直观,适用于基于Tag进行消息分类的场景。
SQL92过滤:可以使用SQL92表达式来灵活地过滤消息的Tag和属性。这种方式提供了更强大的过滤能力,可以根据复杂的条件进行消息筛选。
需要注意的是,Rocket MQ的消息过滤功能虽然强大,但是也会增加服务端的处理负担。因此,在使用时需要根据实际情况进行权衡,避免过度依赖消息过滤功能导致系统性能下降。
Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。
它的内容包括:
- 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
- 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
- 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
- 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
- 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
- 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
- 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
- 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw
目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:
想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询
同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。