文档不够,源码来凑,rocketMQ sql过滤,到底是怎么实现的?

tag过滤可参照:http://www.xunyajie.com/2019/03/30/RocketMQ%E6%B6%88%E6%81%AF%E8%BF%87%E6%BB%A4%E5%88%86%E6%9E%90/

本文着重补充这个博客后面未写完的内容。(sql过滤原理)

引言

RocketMQ支持表达式过滤以及类过滤两种,表达式过滤又分为TAG和SQL92。

MessageFilter类主要有两个方法:

  • isMatchedByConsumeQueue(final Long tagsCode, final ConsumeQueueExt.CqExtUnit cqExtUnit);
  • isMatchedByCommitLog(final ByteBuffer msgBuffer, final Map<String, String> properties);

RocketMQ中消息过滤是在订阅的时候做的。下面抛出问题:

1:记得在看消息消费consumer端逻辑的时候,那里面有对tag的过滤,那个过滤和这个过滤有什么区别?

ps:

Tag过滤方式:Consumer端在订阅消息时除了指定Topic还可以指定TAG,如果一个消息有多个TAG,可以用||分隔。其中,Consumer端会将这个订阅请求构建成一个 SubscriptionData,发送一个Pull消息的请求给Broker端。Broker端从RocketMQ的文件存储层—Store读取数据之前,会用这些数据先构建一个MessageFilter,然后传给Store。Store从 ConsumeQueue读取到一条记录后,会用它记录的消息tag hash值去做过滤,由于在服务端只是根据hashcode进行判断,无法精确对tag原始字符串进行过滤,故在消息消费端拉取到消息后,还需要对消息的原始tag字符串进行比对,如果不同,则丢弃该消息,不进行消息消费。

 

2:是否意味着消息消费broker端已经将过滤好的消息传给了consumer?
是的,如果是基于tag过滤,那么broker会基于tag的hashCode进行过滤

 

3:过滤表达式怎么同步到服务端?

在启动的时候会更新一次

在每次PullTaskImpl执行的时候会上传表达式,所以理论上,过滤表达式是可以实时更新的。

如果是文件形式的过滤,在每次心跳的时候会上传到服务端

 

根据源码剖析,先抛一下结论:

 

TAG/propertiesSQL过滤都是在服务端有一层过滤,客户端还有二次过滤。

服务端:

Tag 过滤使用的是 ConsumeQueue 的hashCode 与tag做对比(多个tag会挨个对比)

Properties 使用的是commitlog ,通过SqlFilter进行过滤。

 

MQ过滤原理

mq过滤总结

  1. 使用 CPU 资源来换取网卡流量资源

  2. FilterServer 与 Broker 部署在同一台机器,数据通过本地回环通信,不走网卡

  3. 一台 Broker 部署多个 FilterServer,充分利用 CPU 资源,因为单个 Jvm 难以全面利用高配的物理机 Cpu 资源

  4. 因为过滤代码使用 Java 语言来编写,应用几乎可以做任意形式的服务器端消息过滤,例如通过 Message Header

    进行过滤,甚至可以按照 Message Body 进行过滤。

  5. 使用 Java 语言进行作为过滤表达式是一个双刃剑,方便了应用的过滤操作,但是带来了服务器端的安全风险。

    需要应用来保证过滤代码安全,例如在过滤程序里尽可能不做申请大内存,创建线程等操作。避免 Broker 服

    务器发生资源泄漏。

SQL92过滤代码剖析

MQ主流程:

1:客户端启动,会在客户端缓存过滤表达式

consumer.subscribe("topic", "sql表达式");
。。。
this.rebalanceImpl.getSubscriptionInner().put(topic, subscriptionData);

2:在客户端启动后,与服务端建立心跳链接,服务端会注册该consumer的data filter如果是sql过滤,会准备好sqlFilter。对sql92的符号进行支持

 

3:客户端拉消息

 3.1:先获取客户端缓存的过滤表达式,作为pullRequest入参,想服务端请求拉数据

3.2:获取messageFilter,sql过滤是通过commitLog内容进行解析

3.3:根据properties内容进行sqlFilter.parse解析对应的逻辑表达式的 expression实例,在通过expression对sql92符号进行逻辑运算(单独解释)

3.4:返回通过filter的message

 

通过官方单测,单独看下下主逻辑:

注册filter->获取parser->根据Properties map解析表达式

 

 

逻辑运算的代码实现大致思路:

1:通过解析,把支持的 and between等表达式解析为数学表达式( parser)

2:按(&& ||)切分为左右2个表达式,,两两逻辑匹配。支持短路

 

 

 

 

主流程逻辑代码如下

SQL表达式的主接口

 

构建sql filter data

 

 

 

isMatchedByCommitLog  tag过滤会直接返回

Sql过滤会调用布尔表达式进行过滤

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值