生产者详解-启动流程

本文详细解析RocketMQ生产者的工作原理,包括生产者概述、高可用机制(客户端与Broker端保证)、以及生产者类和启动流程。重点介绍了DefaultMQProducer的配置与启动流程,涉及客户端容错、Broker端数据同步以及生产者实例的创建和注册。
摘要由CSDN通过智能技术生成

生产者详解

生产者概述

发送消息的一方被称作生产者

RocketMQ客户端中的生产者有两个独立的实现类:org.apache.rocketmq.client.producer.DefaultMQProducer(用于生产普通消息、顺序消息、单向消息、批量消息、延迟消息)和org.apache.rocketmq.client.producer.TransactionMQProducer(用于生产事务消息)

生产者高可用

RocketMQ通过以下机制保证Producer高可用

客户端保证
  • 重试机制:支持RocketMQ同步、异步发送消息失败后选择其他Broker进行重试保证消息正常发送
    通过配置 retryTimesWhenSendFailed 表示同步重试次数,默认2次(加上正常发送的1次,总计三次)
  • 客户端容错:RocketMQ Client会维护一个“Broker-发送延迟”关系,根据这个关系选择一个发送延迟级别较低的Broker来发送消息,尽量保证消息的正常发送。通过配置 sendLatencyFaultEnable 设置是否开启延迟容错,默认为false(即关闭)
Broker端保证
  • 数据同步方式保证:通过Broker的主从复制(同步复制、异步复制),保证Broker数据一致性和Broker端高可用,从而使Producer高可用

生产者源码解析

生产者类

DefaultMQProducer是RocketMQ中默认的生产者实现,继承了 ClientConfig,实现了 MQProducer(继承了 MQAdmin),如下图:

在这里插入图片描述

ClientConfig是记录客户端公共配置类,保存管理些公共属性配置,如上图所示:

  • nameservAddr:RocketMQ集群的NameSrv地址,如果是多个用,隔开,通过配置rocketmq.namesrv.addr获取,如果没配置,则获取配置NAMESRV_ADDR的值

  • clientIP:使用的客户端程序所在机器的IP地址,支持IPV4、IPV6(如果客户端在容器内,则获取的是容器所在的IP地址),优先IPV4地址

  • instanceName:唯一实例名,通过rocketmq.client.name配置,默认值为 DEFAULT

  • clientCallbackExecutorThreads:客户端回调线程数,表示Netty通信层回调线程的个数(默认使用当前CPU的有效个数)

  • namespace:命名空间

  • accessChannel:访问通道,如果需要将rocketmq服务迁移到云端,建议设置为“CLOUD”。 否则设置为“LOCAL”,特别是使用消息跟踪功能

  • pollNameServerInterval:从NameServ拉取topic信息的间隔时长,默认30s

  • heartbeatBrokerInterval:与Broker的心跳间隔,默认30s

  • persistConsumerOffsetInterval:持久化消费者的Offset间隔,默认5s

  • pullTimeDelayMillsWhenException:拉取消息发生异常时时间延迟,默认1s

  • vipChannelEnabled:是否开启VIP通道,VIP通道和非VIP通道的区别在于通信过程中使用的端口号不同,VIP的端口在非VIP的端口下-2,默认不开启

  • useTLS:判断客户端是否使用SSL,默认不开启,用于在两个通信应用程序之间提供保密性和数据完整性

DefaultMQProducer是默认的生产者类,其包含的属性有:

  • defaultMQProducerImpl:生产者真正的实现类,DefaultMQProducer的方法实现都是通过调用这个实现类对应的方法实现的

  • producerGroup:生产者组,聚合有相同角色的所有生产者实例,在事务消息时尤为重要

  • createTopicKey:默认值为 TBW102

  • defaultTopicQueueNums:每个topic队列数,默认值为4个

  • sendMsgTimeout:发送消息超时时间,默认3s

  • compressMsgBodyOverHowmuch:消息体的容量最大上限,默认4MB,超出之后会通过ZIP进行压缩

  • retryTimesWhenSendFailed:同步发送消息失败的重试次数,默认两次,加上正常的1次,总共发送消息3次

  • retryTimesWhenSendAsyncFailed:异步发送消息失败的重试次数,默认两次,加上正常的1次,总共发送消息3次

  • retryAnotherBrokerWhenNotStoreOK:是否在发送失败时重试时选择另一个broker,默认为false

  • maxMessageSize:默认消息的最大大小:4M

  • traceDispatcher:异步传输数据接口

MQProducer 定义了producer一系列必须的启动、关闭、发送消息等接口定义

MQAdmin 定义了MQ的基础接口:createTopic、searchOffset、maxOffset、minOffset、earliestMsgStoreTime、viewMessage、queryMessage

生产者启动流程

生产者启动流程时序图如下:

在这里插入图片描述

用户创建DefaultProducer实例对象,设置唯一的ProducerGroupName,nameservAddr等参数,然后调用**DefaultProducer#start()**方法,启动生产者。

ProducerGroup这个概念发送普通的消息时,作用不大,但是发送分布式事务消息时,比较关键,因为服务器会回查这个Group下的任意一个Producer

DefaultProducer#start()源码解析:

    @Override
    public void start() throws MQClientException {
   
        // 设置生产者producerGroup
        this.setProducerGroup(withNamespace(this.producerGroup));
      	// 调用真正的DefaultMQProducer启动接口
        this.defaultMQProducerImpl.start();
        if (null != traceDispatcher) {
   
            try {
   
              	// 启动消息轨迹服务
                traceDispatcher.start(this.getNamesrvAddr(), this.getAccessChannel());
            } catch (MQClientException e) {
   
                log.warn("trace dispatcher start failed ", e);
            }
        }
    }

消息轨迹服务具体解析请看《消息轨道》----消息轨迹

ClientConfig#withNamespace(String resource)源码解析:

    public String withNamespace(String resource) {
   
        return NamespaceUtil.wrapNamespace(this.getNamespace(), resource);
    }

    public String getNamespace() {
   
        if (StringUtils.isNotEmpty(namespace)) {
   
            return namespace;
        }

        if (StringUtils.isNotEmpty(this.namesrvAddr)) {
   
          	// 判断nameservAddr是否匹配 ^(\w+://|)MQ_INST_\w+_\w+\..*
            if (NameServerAddressUtils.validateInstanceEndpoint(namesrvAddr)) {
   
              	// 返回nameservAddr的uri
                return NameServerAddressUtils.parseInstanceIdFromEndpoint(namesrvAddr);
            }
        }
        return namespace;
    }

NamespaceUtil#wrapNamespace(String namespace, String resourceWithOutNamespace)源码解析:

public static String wrapNamespace(String namespace, String resourceWithOutNamespace) {
   
        if (StringUtils.isEmpty(namespace) || StringUtils.isEmpty(resourceWithOutNamespace)) {
   
            return resourceWithOutNamespace;
        }
        // 如果resourceWithOutNamespace是系统定义的topic或者系统内部的消费者组,或者 resourceWithOutNamespace已经是以namespace开头,直接返回resourceWithOutNamespace
        if (isSystemResource(resourceWithOutNamespace) || isAlreadyWithNamespace(resourceWithOutNamespace, namespace)) {
   
            return resourceWithOutNamespace;
        }
        // 否则返回一个新的 以 {%RETRY%} + {%DLQ%} + namespace + % + 原resourceWithOutNamespace去除掉%RETRY%和%DLQ%的字符串
        String resourceWithoutRetryAndDLQ = withOutRetryAndDLQ(resourceWithOutNamespace);
        StringBuilder stringBuilder = new StringBuilder();
        // {%RETRY%} 和 {%DLQ%} 需要判断原resourceWithOutNamespace是否存在这两个前缀
        if (isRetryTopic(resourceWithOutNamespace)) {
   
            stringBuilder.append(MixAll.RETRY_GROUP_TOPIC_PREFIX);
        }

        if (isDLQTopic(resourceWithOutNamespace)) {
   
            stringBuilder.append(MixAll.DLQ_GROUP_TOPIC_PREFIX);
        }

        return
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值