RocketMq4.7源码解析之八(消息过滤)

消息过滤

RocketMQ 支持

  1. 表达式过滤
    TAG:消息定义标签,根据消息属性tag 进行匹配。
    SQL92:消息属性过滤上下文, 实现SQL 条件过滤表达式
  2. 类过滤
    消费者自定义消息过滤实现类并将其代码上传到FilterServer 上,消息消费者向FilterServer 拉取消息, FilterServer 将消息消费者的拉取命令转发到Broker ,然后对返回的消息执行消息过滤逻辑,最终将消息返回给消费端,

TAG过滤

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

注册主题到rebalance
DefaultMQPushConsumerImpl
在这里插入图片描述
根据订阅消息构建消息拉取标记,设置subExpression 、classFilter 消息过滤信息。
DefaultMQPushConsumerImpl#pullMessage
在这里插入图片描述
broker端会根据解析标志
PullMessageProcessor#processRequest在这里插入图片描述
然后根据消息过滤机制是否为表达式进行相应的处理
在这里插入图片描述
紧接着构建消息过滤对象,随后查找消息
在这里插入图片描述
根据ConsumeQueue 条目进行消息过滤
DefaultMessageStore#getMessage
在这里插入图片描述
ExpressionMessageFilter

public boolean isMatchedByConsumeQueue(Long tagsCode, ConsumeQueueExt.CqExtUnit cqExtUnit) {
        //如果订阅消息为空,
        if (null == subscriptionData) {
            //表示不过滤
            return true;
        }
        //如果是类过滤模式
        if (subscriptionData.isClassFilterMode()) {
            return true;
        }

        // by tags code.
        //tag过滤模式处理
        if (ExpressionType.isTagType(subscriptionData.getExpressionType())) {

            //如果tagsCode为空或tagsCode小于0 ,返回true
            //说明消息在发送时没有设置tag
            if (tagsCode == null) {
                return true;
            }

            //全匹配,直接true
            if (subscriptionData.getSubString().equals(SubscriptionData.SUB_ALL)) {
                return true;
            }
            //订阅消息的TAG hashcodes 集合中包含消息的tagsCode,返回true
            return subscriptionData.getCodeSet().contains(tagsCode.intValue());
        } else {
            // no expression or no bloom
            if (consumerFilterData == null || consumerFilterData.getExpression() == null
                || consumerFilterData.getCompiledExpression() == null || consumerFilterData.getBloomFilterData() == null) {
                return true;
            }

            // message is before consumer
            if (cqExtUnit == null || !consumerFilterData.isMsgInLive(cqExtUnit.getMsgStoreTime())) {
                log.debug("Pull matched because not in live: {}, {}", consumerFilterData, cqExtUnit);
                return true;
            }

            byte[] filterBitMap = cqExtUnit.getFilterBitMap();
            BloomFilter bloomFilter = this.consumerFilterManager.getBloomFilter();
            if (filterBitMap == null || !this.bloomDataValid
                || filterBitMap.length * Byte.SIZE != consumerFilterData.getBloomFilterData().getBitNum()) {
                return true;
            }

            BitsArray bitsArray = null;
            try {
                bitsArray = BitsArray.create(filterBitMap);
                boolean ret = bloomFilter.isHit(consumerFilterData.getBloomFilterData(), bitsArray);
                log.debug("Pull {} by bit map:{}, {}, {}", ret, consumerFilterData, bitsArray, cqExtUnit);
                return ret;
            } catch (Throwable e) {
                log.error("bloom filter error, sub=" + subscriptionData
                    + ", filter=" + consumerFilterData + ", bitMap=" + bitsArray, e);
            }
        }

        return true;
    }

这里说明broker比较的是tagCode,所以在client还需要比较tag
在这里插入图片描述
如果消息根据ConsumeQueue 条目通过过滤,则需要从CommitLog 文件中加载整个消息体,然后根据属性进行过滤
在这里插入图片描述
ExpressionMessageFilter

  @Override
    public boolean isMatchedByCommitLog(ByteBuffer msgBuffer, Map<String, String> properties) {
        //订阅信息为空,返回true
        if (subscriptionData == null) {
            return true;
        }

        //如果是类过滤模式,返回true
        if (subscriptionData.isClassFilterMode()) {
            return true;
        }

        //如果是TAG 模式,返回true
        if (ExpressionType.isTagType(subscriptionData.getExpressionType())) {
            return true;
        }

        ConsumerFilterData realFilterData = this.consumerFilterData;
        Map<String, String> tempProperties = properties;

        // no expression
        if (realFilterData == null || realFilterData.getExpression() == null
            || realFilterData.getCompiledExpression() == null) {
            return true;
        }

        if (tempProperties == null && msgBuffer != null) {
            tempProperties = MessageDecoder.decodeProperties(msgBuffer);
        }

        Object ret = null;
        try {
            MessageEvaluationContext context = new MessageEvaluationContext(tempProperties);

            //该方法主要是为表达式模式SQL92 服务的,根据消息属性实现类似于数据库SQLwhere 条件过滤方式
            ret = realFilterData.getCompiledExpression().evaluate(context);
        } catch (Throwable e) {
            log.error("Message Filter error, " + realFilterData + ", " + tempProperties, e);
        }

        log.debug("Pull eval result: {}, {}, {}", ret, realFilterData, tempProperties);

        if (ret == null || !(ret instanceof Boolean)) {
            return false;
        }

        return (Boolean) ret;
    }

消费者收到broker返回消息后
将消息字节数组解码成消息列表填充msgFoundList ,井对消息进行消息过滤( TAG )模式
DefaultMQPushConsumerImpl#pullMessage
在这里插入图片描述
比较TAG字符串是否包含,包含的话,就记录消息.
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好!要进行Zabbix 4.7源码安装,您可以按照以下步骤进行操作: 1. 下载Zabbix源码包: 您可以前往Zabbix官方网站(https://www.zabbix.com/)下载Zabbix 4.7源码包,选择合适的版本进行下载。 2. 安装编译工具和依赖项: 在进行源码安装之前,需要确保系统已经安装了必要的编译工具和依赖项。具体依赖项的安装方法会根据您所使用的Linux发行版而有所不同。 在Ubuntu/Debian系统中,您可以使用以下命令安装所需的依赖项: ``` sudo apt-get update sudo apt-get install -y build-essential libpcre3-dev libssl-dev libmysqlclient-dev libsnmp-dev libevent-dev libopenipmi-dev libcurl4-openssl-dev ``` 在CentOS/RHEL系统中,您可以使用以下命令安装所需的依赖项: ``` sudo yum groupinstall -y "Development Tools" sudo yum install -y epel-release sudo yum install -y pcre-devel openssl-devel mysql-devel net-snmp-devel libevent-devel OpenIPMI-devel curl-devel ``` 3. 解压源码包: 使用以下命令解压Zabbix源码包: ``` tar xvfz zabbix-4.7.x.tar.gz cd zabbix-4.7.x ``` 4. 配置和编译: 在源码目录中,执行以下命令进行配置和编译: ``` ./configure --prefix=/usr/local/zabbix --enable-server --enable-agent --with-mysql --with-net-snmp --with-libcurl --with-openipmi make sudo make install ``` 请注意,您可以根据需要修改`--prefix`参数来指定Zabbix的安装目录。 5. 数据库初始化: 使用以下命令初始化Zabbix数据库: ``` cd database/mysql mysql -u root -p < schema.sql mysql -u root -p < images.sql mysql -u root -p < data.sql ``` 如果需要,您可以使用其他数据库(例如PostgreSQL)进行初始化。相关脚本位于`database/postgresql`目录下。 6. 配置Zabbix服务器和代理: 在安装目录下的`conf`目录中,复制`zabbix_server.conf.example`和`zabbix_agentd.conf.example`文件,并分别重命名为`zabbix_server.conf`和`zabbix_agentd.conf`。然后根据需要进行配置。 7. 启动Zabbix服务器和代理: 使用以下命令启动Zabbix服务器和代理: ``` /usr/local/zabbix/sbin/zabbix_server /usr/local/zabbix/sbin/zabbix_agentd ``` 您可以根据需要将这些命令配置为系统服务,以便系统启动时自动启动。 这些步骤应该能够帮助您完成Zabbix 4.7源码安装。如果您有任何问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值