RocketMQ支持表达式过滤与类过滤两种模式,其中表达式又分为TAG和SQL92。类过滤模式允许提交一个过滤类到FilterServer,消息消费者从FilterServer拉取消息,消息经过FilterServer时会执行过滤逻辑。

基于表达式的消息过滤

  消息发送者在消息发送时如果设置了消息的tags属性,存储在消息属性中,先存储在CommitLog文件中,然后转发到消息消费队列,消息消费队列会用8个字节存储消息tag的hashcode,之所以不直接存储tag字符串,是因为将ConumeQueue设计为定长结构,加快消息消费的加载性能。
  RocketMQ基于表达式的消息过滤是在订阅时做过滤。在Broker端拉取消息时,遍历ConsumeQueue,只对比消息tag的hashcode,如果匹配则返回,否则忽略该消息。Consume在收到消息后,同样需要先对消息进行过滤,只是此时比较的是消息tag的值而不再是hashcode

Step1:消费者订阅消息主题与消息过滤表达式。构建订阅信息subscriptionData并加入到RebalanceImpl进行消息队列负载。
  subscriptionData的核心属性:
  1)String SUB_ALL:过滤模式,默认为全匹配。
  2)boolean classFilterMode:是否是类过滤模式,默认为false。
  3)String topic:消息主题名称。
  4)String subString:消息过滤表达式,多个用双竖线隔开,例如“TAGA||TAGB”。
  5)Set<String> tagsSet:消息过滤tag集合,消费端过滤时进行消息过滤的依据。
  6)Set<String> codeSet:消息过滤tag hashcode集合。
  7)String expressionType:过滤类型,TAG或SQL92。
Step2:根据订阅消息构建消息拉取标记。根据主题、消息过滤表达式构建订阅消息实体。构建消息过滤对象。
Step3:根据偏移量拉取消息后,首先根据ConsumeQueue条目进行消息过滤,如果不匹配则直接跳过该条消息,继续拉取下一条消息。
Step4:如果消息根据ConsumeQueue条目通过过滤,则需要从CommitLog文件中加载整个消息体,然后根据属性进行过滤。基于TAG模式,根据ConsumeQueue进行消息过滤时只对比tag的hashcode,所以基于TAG模式消息过滤,还需要在消息消费端对消息tag进行精确匹配。

  从消息拉取流程知道,消息拉取线程PullMessageService默认会使用异步方式从服务器拉取消息,如果消息过滤模式为TAG模式,并且订阅TAG集合不为空,则对消息的tag进行判断,如果集合中包含消息的TAG则返回给消费者消费,否则跳过。

 

消息过滤FilterServer

ClassFilter运行机制

  基于类模式过滤是指在 Broker 端运行1个或多个消息过滤服务器(FilterServer), RocketMQ 允许消息消费者自定义消息过滤实现类并将其代码上传到 FilterServer 上,消息消费者向 FilterServer 拉取消息,FilterServer将消息消费者的拉取命令转发到 Broker,然后对返回的消息执行消息过滤逻辑,最终将消息返回给消费端。

RocketMQ:(5) 消息过滤机制_sql

1)Broker 进程所在的服务器会启动多个 FilterServer 进程。
2)消费者在订阅消息主题时会上传一个自定义的消息过滤实现类,FilterServer 加载并实例化
3)消息消费者(Consume)向 FilterServer 发送消息拉取请求,FilterServer 接收到消息消费者消息拉取请求后,FilterServer 将消息拉取请求转发给 Broker,Broker 返回消息后在 FilterServer 端执行消息过滤逻辑,然后返回符合订阅信息的消息给消息消费者进行消费。

FilterServer 注册

  FilterServer在启动时会创建一个定时调度任务,每隔10s向Broker注册自己。
Step1:FilterServer从配置文件中获取Broker地址,然后将FilterServer所在机器的IP与监听端口发送到Broker服务器。
Step2:FilterServer与Broker通过心跳维持FilterServer在Broker端的注册,同样在Broker每隔10s扫描一下该注册表,如果30s内未收到FilterServer的注册信息,将关闭Broker与FilterServer的连接。Broker为了避免Broker端FilterServer的异常退出导致FilterServer进程越来越少,同样提供一个定时任务每30s检测一下当前存活的FilterServer进程个数。
  经过上面的步骤,Broker上已经保存了FilterServer的信息。那么NameServer中关于Broker的filterServer信息是如何从消息服务器(Broker)传输到NameServer的呢?Broker通过与所有NameServer的心跳包向NameServer注册Broker上存储的FilterServer列表,指引消息消费者正确从FilterServer上拉取消息。Brokers每30s向所有NameServer发送心跳包,心跳包中包含了集群名称、Broker名称、Broker地址、BrokerId、haServer地址、topic配置、过滤服务器列表等。