Producer源码分析

引言

rocketmq支持3种发送消息方式:同步,异步,单向(oneway)
主要关注的点:

  • rocketmq消息结构
  • 生产者的启动流程
  • 消息发送过程
  • 批量消息发送过程

主要的问题是:
消息队列如何负载?
生产者发送消息时,如果本地缓存表没有路由信息,会从NameServer更新路由信息。每隔30s,会从NameServer更新路由信息表
消息发送如何实现高可用?

  • 会在超时时间范围内进行重试
  • 会在发送时,通过故障策略提供发送消息的成功率
    批量消息发送如何实现一致性?
    把批量消息封装成MessageBatch,一次性发送。

注意点

  • 一个productGroup 在一个jvm上只要有一个product实例
  • MQClientManager是单例
  • MQClientInstance是客户端与name server和broker直接沟通对象。 一个jvm内的消费者和生产者公用一个MQClientInstance。
  • 想要在运行时停mq的流程,只需调用MQProduct的shutdown方法,会移除本地的生产者列表,并在broker注销。重启只需要调用下面的封装方法。 使用JMX管理,就可以实现运行时停止和开启流量了。
public void restart(DefaultMQProducer producer){
	if (producer.getDefaultMQProducerImpl().getServiceState()
        .equals(ServiceState.SHUTDOWN_ALREADY)) {
        producer.getDefaultMQProducerImpl().setServiceState(ServiceState.CREATE_JUST);
        producer.start();
    }
}

Message

用户发送消息封装类是MessageMessageBatch,分别是普通消息和批量消息
Message源码解析

MQProducer接口

用户接口,定义了发送消息的方法
有两个实现类,DefaultMQProducer和TransactionProducer
TransactionProducer是继承DefaultMQProducer,实现了事务消息的发送

public interface MQProducer extends MQAdmin {
	
    void start() ;
    void shutdown();
    List<MessageQueue> fetchPublishMessageQueues(final String topic) ;
    // 同步方法 包含重试
    SendResult send(final Message msg) ;
    // 同步方法 指定本次总体发送超时时间,超过时间会直接返回
    SendResult send(final Message msg, final long timeout) ;
    // 异步方式 包含重试
    void send(final Message msg, final SendCallback sendCallback) ;
    // 异步方式 指定本次总体发送超时时间,超过时间会直接返回
    void send(final Message msg, final SendCallback sendCallback, final long timeout)
    // 单向
    void sendOneway(final Message msg) ;
    // 同步方法 会发往指定broker的指定队列
    SendResult send(final Message msg, final MessageQueue mq) ;
    // 同步方法 会发往指定broker的指定队列 指定本次总体发送超时时间
    SendResult send(final Message msg, final MessageQueue mq, final long timeout)
    // 异步方法 会发往指定broker的指定队列
    void send(final Message msg, final MessageQueue mq, final SendCallback sendCallback)
    // 异步方法 会发往指定broker的指定队列 指定本次总体发送超时时间
    void send(final Message msg, final MessageQueue mq, final SendCallback sendCallback, long timeout)
    // 单向 会发往指定broker的指定队列
    void sendOneway(final Message msg, final MessageQueue mq) ;
    // 同步方法 由发送方实现selector选择哪个broker的哪个queue
    SendResult send(final Message msg, final MessageQueueSelector selector, final Object arg)
    // 同步方法 由发送方实现selector选择哪个broker的哪个queue 指定本次总体发送超时时间
    SendResult send(final Message msg, final MessageQueueSelector selector, final Object arg,
        final long timeout) ;
    // 异步方法 由发送方实现selector选择哪个broker的哪个queue
    void send(final Message msg, final MessageQueueSelector selector, final Object arg,
        final SendCallback sendCallback) ;
    // 异步方法 由发送方实现selector选择哪个broker的哪个queue 指定本次总体发送超时时间
    void send(final Message msg, final MessageQueueSelector selector, final Object arg,
        final SendCallback sendCallback, final long timeout) ;
    // 单向 由发送方实现selector选择哪个broker的哪个queue
    void sendOneway(final Message msg, final MessageQueueSelector selector, final Object arg)
    // DefaultMQProducer不实现此方法
    TransactionSendResult sendMessageInTransaction(final Message msg,
        final LocalTransactionExecuter tranExecuter, final Object arg) ;
    // DefaultMQProducer不实现此方法
    TransactionSendResult sendMessageInTransaction(final Message msg,
        final Object arg) ;
    //for batch
    // 同步方式 比单个消息多一个消息打包过程
    SendResult send(final Collection<Message> msgs) ;
    // 同步方式 比单个消息多一个消息打包过程 指定本次总体发送超时时间
    SendResult send(final Collection<Message> msgs, final long timeout) ;
    // 同步方式 比单个消息多一个消息打包过程 会发往指定broker的指定队列
    SendResult send(final Collection<Message> msgs, final MessageQueue mq) ;
    // 同步方式 比单个消息多一个消息打包过程 会发往指定broker的指定队列 指定本次总体发送超时时间
    SendResult send(final Collection<Message> msgs, final MessageQueue mq, final long timeout)
    //for rpc
    //同步方法 等待消费者发送ack才返回 指定本次总体发送超时时间
    Message request(final Message msg, final long timeout) ;
    //异步方法 等待消费者发送ack后执行callback 指定本次总体发送超时时间
    void request(final Message msg, final RequestCallback requestCallback, final long timeout)
    //同步方法 等待消费者发送ack才返回 由发送方实现selector选择哪个broker的哪个queue 指定本次总体发送超时时间
    Message request(final Message msg, final MessageQueueSelector selector, final Object arg,
        final long timeout) ;
    //异步方法 等待消费者发送ack后执行callback 由发送方实现selector选择哪个broker的哪个queue 指定本次总体发送超时时间
    void request(final Message msg, final MessageQueueSelector selector, final Object arg,
        final RequestCallback requestCallback,
        final long timeout) ;
    //同步方法 等待消费者发送ack才返回 会发往指定broker的指定队列 指定本次总体发送超时时间
    Message request(final Message msg, final MessageQueue mq, final long timeout)
    //异步方法 等待消费者发送ack后执行callback 会发往指定broker的指定队列 指定本次总体发送超时时间
    void request(final Message msg, final MessageQueue mq, final RequestCallback requestCallback, long timeout)
}

生产者消息发送方式

  • 消息的发送方式有三种:同步,异步,单向
  • 消息发送的条数有两种:单条消息和批量消息
  • 发送完成的时机:broker接收和consumer ack
  • 消息的类型有两种:普通消息和事务消息,事务消息需要使用TransactionMQProducer

DefaultMQProducer

  • 实现了MQProducer接口,是面向发送普通消息的用户
  • DefaultMQProducer是默认的消息生产者实现类 UML图如下
  • MQAdmin接口主要是管理员的角色:创建topic和根据offset查询消息
  • MQProducer接口定义了发送消息的几种方式
  • ClientConfig类是客户端的配置,对于rocketmq来说生产者和消费者都是客户端
  • 持有DefaultMQProducerImpl来处理具体业务逻辑

类图

在这里插入图片描述

主要属性

protected final transient DefaultMQProducerImpl defaultMQProducerImpl;
    //所有的生产者根据producerGroup认为是一个集群。主要用于发送事务消息时,消息状态的回查,调用producerGroup中的任意一个
    private String producerGroup;
    // 提供了一个测试和demo的topic
    private String createTopicKey = MixAll.AUTO_CREATE_TOPIC_KEY_TOPIC;
    // 创建默认topic的队列数量
    private volatile int defaultTopicQueueNums = 4;
	//发送消息的超时时间,3s
    private int sendMsgTimeout = 3000;
	//消息压缩的阀值,超过4kb就会压缩
    private int compressMsgBodyOverHowmuch = 1024 * 4;
	//producer发送消息给broker时会尝试多次。默认重复2次,一共三次
    private int retryTimesWhenSendFailed = 2;
	//发送异步消息的失败次数。
    private int retryTimesWhenSendAsyncFailed = 2;
	//broker消息存储失败,是否发送消息给其他broker  默认false
    private boolean retryAnotherBrokerWhenNotStoreOK = false;
	//最大的消息体,支持最大的值为2^32 -8 
    private int maxMessageSize = 1024 * 1024 * 4; // 4M
    //不知道是个啥  fixme
    private TraceDispatcher traceDispatcher = null;

启动流程

主要是启动defaultMQProducerImpl
defaultMQProducerImpl

public void start() throws MQClientException {
        this.setProducerGroup(withNamespace(this.producerGroup));
        this.defaultMQProducerImpl.start();
        if (null != traceDispatcher) {
            try {
                traceDispatcher.start(this.getNamesrvAddr(), this.getAccessChannel());
            } catch (MQClientException e) {
                log.warn("trace dispatcher start failed ", e);
            }
        }
    }

同步消息发送流程图

在这里插入图片描述

普通消息

自动选择消息队列的三种消息发送方式

DefaultMQProducer

// 同步发送
public SendResult send(
        Message msg) throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
        // 校验消息
        // msg不能空 body不能为0 且要符合生产者配置的最大消息大小。 默认是4m
        // topic 不能空 不能大于127个字符 符合正则"^[%|a-zA-Z0-9_-]+$" 不能是“TBW102”
        Validators.checkMessage(msg, this);
        // 业务topic withNamespace方法无用
        msg.setTopic(withNamespace(msg.getTopic()));
        return this.defaultMQProducerImpl.send(msg);
    }
// 异步
public void send(Message msg, SendCallback sendCallback, long timeout)
        throws MQClientException, RemotingException, InterruptedException {
        msg.setTopic(withNamespace(msg.getTopic()));
        this.defaultMQProducerImpl.send(msg, sendCallback, timeout);
    }
// oneway
public void sendOneway(Message msg) throws MQClientException, RemotingException, InterruptedException {
        msg.setTopic(withNamespace(msg.getTopic()));
        this.defaultMQProducerImpl.sendOneway(msg);
    }
// 同步异步和oneway都是调用的sendDefaultImpl

DefaultMQProducerImpl源码分析

指定消息队列发送消息

由用户指定发送broker的哪个queueId

// sync
public SendResult send(Message msg, MessageQueue mq)
        throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
        msg.setTopic(withNamespace(msg.getTopic()));
        return this.defaultMQProducerImpl.send(msg, queueWithNamespace(mq));
    }
// async
public void send(Message msg, MessageQueue mq, SendCallback sendCallback)
        throws MQClientException, RemotingException, InterruptedException {
        msg.setTopic(withNamespace(msg.getTopic()));
        this.defaultMQProducerImpl.send(msg, queueWithNamespace(mq), sendCallback);
    }
// oneway
public void sendOneway(Message msg,
        MessageQueue mq) throws MQClientException, RemotingException, InterruptedException {
        msg.setTopic(withNamespace(msg.getTopic()));
        this.defaultMQProducerImpl.sendOneway(msg, queueWithNamespace(mq));
    }

提供消息队列选择器发送消息

提供消息队列选择器发送消息

消息队列选择器

public interface MessageQueueSelector {
    MessageQueue select(final List<MessageQueue> mqs, final Message msg, final Object arg);
}
// 同步
public SendResult send(Message msg, MessageQueueSelector selector, Object arg, long timeout)
        throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
        msg.setTopic(withNamespace(msg.getTopic()));
        return this.defaultMQProducerImpl.send(msg, selector, arg, timeout);
    }
// 异步
public void send(Message msg, MessageQueueSelector selector, Object arg, SendCallback sendCallback, long timeout)
        throws MQClientException, RemotingException, InterruptedException {
        msg.setTopic(withNamespace(msg.getTopic()));
        this.defaultMQProducerImpl.send(msg, selector, arg, sendCallback, timeout);
    }
// oneway
public void sendOneway(Message msg, MessageQueueSelector selector, Object arg)
        throws MQClientException, RemotingException, InterruptedException {
        msg.setTopic(withNamespace(msg.getTopic()));
        this.defaultMQProducerImpl.sendOneway(msg, selector, arg);
    }

批量消息

发送批量消息只支持同步模式
提供自动选择队列和提供消息队列两种队列选择模式

// 自动选择队列
public SendResult send(Collection<Message> msgs,
        long timeout) throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
        return this.defaultMQProducerImpl.send(batch(msgs), timeout);
    }
// 提供队列模式
public SendResult send(Collection<Message> msgs, MessageQueue messageQueue,
        long timeout) throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
        return this.defaultMQProducerImpl.send(batch(msgs), messageQueue, timeout);
    }

封装批量消息
MessageBatch源码解析

private MessageBatch batch(Collection<Message> msgs) throws MQClientException {
        MessageBatch msgBatch;
        try {
            msgBatch = MessageBatch.generateFromList(msgs);
            for (Message message : msgBatch) {
                Validators.checkMessage(message, this);
                // fixme
                MessageClientIDSetter.setUniqID(message);
                message.setTopic(withNamespace(message.getTopic()));
            }
            msgBatch.setBody(msgBatch.encode());
        } catch (Exception e) {
            throw new MQClientException("Failed to initiate the MessageBatch", e);
        }
        msgBatch.setTopic(withNamespace(msgBatch.getTopic()));
        return msgBatch;
    }

RPC消息

先来讲讲为啥叫rpc消息呢?

  • 可以去看MQProducer接口对于request方法发现消息的分类

rpc消息和普通消息的区别:

  • 普通消息是等待broker接收消息(或者store ok)后返回结果
  • (同步模式下)rpc消息是等待broker接收后,consumer消费后返回Message给到producer才算结束。
  • 一个是发送完成就ok 一个是等待consumer消费完成并返回结果才ok

支持同步和异步,因为oneway对于rpc无意义
支持三种队列选择模式

自动选择队列

// 同步
public Message request(final Message msg, final long timeout) throws RequestTimeoutException, MQClientException,
        RemotingException, MQBrokerException, InterruptedException {
        msg.setTopic(withNamespace(msg.getTopic()));
        return this.defaultMQProducerImpl.request(msg, timeout);
    }
// 异步
public void request(final Message msg, final RequestCallback requestCallback, final long timeout)
        throws MQClientException, RemotingException, InterruptedException, MQBrokerException {
        msg.setTopic(withNamespace(msg.getTopic()));
        this.defaultMQProducerImpl.request(msg, requestCallback, timeout);
    }

队列选择器模式

public Message request(final Message msg, final MessageQueueSelector selector, final Object arg,
        final long timeout) throws MQClientException, RemotingException, MQBrokerException,
        InterruptedException, RequestTimeoutException {
        msg.setTopic(withNamespace(msg.getTopic()));
        return this.defaultMQProducerImpl.request(msg, selector, arg, timeout);
    }

public void request(final Message msg, final MessageQueueSelector selector, final Object arg,
        final RequestCallback requestCallback, final long timeout) throws MQClientException, RemotingException,
        InterruptedException, MQBrokerException {
        msg.setTopic(withNamespace(msg.getTopic()));
        this.defaultMQProducerImpl.request(msg, selector, arg, requestCallback, timeout);
    }

指定消息队列

public Message request(final Message msg, final MessageQueue mq, final long timeout)
        throws MQClientException, RemotingException, MQBrokerException, InterruptedException, RequestTimeoutException {
        msg.setTopic(withNamespace(msg.getTopic()));
        return this.defaultMQProducerImpl.request(msg, mq, timeout);
    }
public void request(final Message msg, final MessageQueue mq, final RequestCallback requestCallback, long timeout)
        throws MQClientException, RemotingException, InterruptedException, MQBrokerException {
        msg.setTopic(withNamespace(msg.getTopic()));
        this.defaultMQProducerImpl.request(msg, mq, requestCallback, timeout);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值