「日拱一卒」带你探索RocketMQ消息发送(四)

82 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,点击查看活动详情

前言

通过上一篇文章「日拱一卒」带你探索RocketMQ消息发送(三),我们主要学了 RocketMQ 发送消息的 Demo、简要了解了 DefaultMQProducer 的属性和方法以及在源码的基础上分析了 RocketMQ 生产者的启动流程。今天,我们来承接上一篇文章,来开始学习下 RocketMQ 消息发送的基本流程吧!

消息发送流程概览

当 RocketMQ 的生产者对象 DefaultMQProducer 成功初始化完成后,会调用 send() 方法进行消息的发送。由于在实际项目中,我们通常会关注消息是否发送成功,因此,同步发送的方式是应用得比较多的。我们本篇文章,还是着眼于同步发送方法来研究原理。

对于单个消息的发送,主要有两个同步发送的方法:

  • 发送消息 image.png

  • 发送消息时,带上超时时间

    image.png

它们底层调用的方法都是 defaultMQProducerImpl 类的 send 方法。接下来,我们以第一个发送消息的方法为例,来一起探索消息发送的流程吧!

验证消息长度是否合理

在消息发送之前,首先要校验一把消息的大小是否超出了限制或者不合法:

  • Message 对象的 body 属性 byte[] 数组若为null,抛出异常
  • Message 对象的 body 属性 byte[] 数组的长度若为0,抛出异常
  • Message 对象的 body 属性 byte[] 数组的长度若大于 102410244 = 4M,抛出异常

查找主题

校验完消息后,开始对 Message 的 Topic 属性进行查询,只有查询到了 Topic 的路由信息,生产者才知道消息应该发送到哪个 Broker 节点上:

image.png

  • 如果生产者的 topicPublishInfoTable (ConcurrentHashMap)中,缓存了 Topic 对应的路由信息 TopicPublishInfo,并且 TopicPublishInfo 中包含消息队列,则返回该路由信息。

  • 如果缓存了 TopicPublishInfo,但是没有路由信息,也没有消息队列,则向 NameServer 查询该 Topic 的路由信息,并更新到 TopicPublishInfo 中

  • 如果没有缓存,或者没有包含消息队列,则向 NameServer 查询该 Topic 的路由信息

  • 如果最终未查询到路由信息,则返回报错

TopicPublishInfo 具体长啥样,我们来看一下:

image.png

  • boolean orderTopic :是否是顺序消息
  • boolean haveTopicRouterInfo: 是否有 Topic 路由信息
  • List messageQueueList :该 Topic 的消息队列
  • ThreadLocalIndex sendWhichQueue :每选择一次消息队列,该值会自增1
  • TopicRouteData 中的 queueDatas:Topic 队列元数据
  • TopicRouteData 中的 brokerDatas:Topic 分布的Broker元数据
  • TopicRouteData 中的 filterServerTable:Broker 上过滤服务器的地址列表

小结

今天我们暂时了解了消息发送流程概览,看了下查找主题的代码,明天将会有更详细的解析,大家多多关注与支持!