RocketMQ 消息发送

本文详细介绍了RocketMQ消息发送的三种方式:可靠同步、可靠异步和单向发送。内容涵盖消息的组成,生产者的启动流程,消息发送基本流程,包括函数调用栈、异步发送和获取主题路由信息的步骤。还讨论了批量消息发送的实现及RemotingCommand的数据结构。此外,解答了关于路由信息加载、消息发送高可用性和批量消息一致性的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

消息发送的三种方式

1.可靠同步发送
2.可靠异步发送
3.单向发送

消息的组成

RocketMQ 中消息的基础属性包括:主题 topic、消息 flag、扩展属性 properties和消息体 body。其中拓展属性包含以下几个:tag(消息 tag,用于消息过滤)、keys(消息索引建,用多个空格隔开,RocketMQ 可以根据这些 key 快速检索到消息)、waitStoreMsgOK(消息发送时是否等消息存储完成后再返回)、delayTimeLevel(消息延迟级别,用于定时消息或消息重试)

生产者的启动

生产者的主要功能

生产者负责按不同的方式发送消息、根据特定的条件查询消息(key、msgId、timestamp)、查询某个消息队列的物理偏移、批量发送等功能。

生产者的启动流程

1.检查 producer group 是否符合要求;改变生产者的 instanceName 为进程 ID
2.创建一个 MQClientInstance 实例。同一个 clientId(clinetId 为客户端 IP+instance+(unitname 可选)) 只会创建一个 MQClientInstance。由于 clientId 根据 instanceName 创建,所以多生产者的情况下会共用同一个 MQClientInstance。

单例模式的应用 MQClientManager
整个JVM 实例中只存在一个 MQClientManager 实例,维护一个 MQClientInstance 缓存表。

3.向MQClientInstance 注册,将当前生产者加入到 MQClientInstance 管理中,方便后续调用网络请求、进行心跳检测等。
4.启动MQClientInstance。

消息发送基本流程

消息发送的基本流程包括:验证消息、查找路由、消息发送 (包含异常处理机制)

函数调用栈

DefaultMQProducerImpl.sendDefaultImpl -> sendKernelImpl -> MQClientAPIImpl.sendMessage

异步发送消息流程

当用户创建DefaultMQProducer调用send()发送消息时,具体流程如下:
1.在DefaultMQProducer中的send()方法调用Validators 检测 message 的合法性,包括:是否有主题名称、消息体不能为空、消息长度不能等于 0且默认不能超过消息最大长度限制。之后设置带有命名空间的 topic。
2.调用DefaultMQProducerImpl中的sendDefaultImpl(),查找主题路由信息,并选择了消息队列后,调用sendKernelImpl()
3.在sendKernelImpl()中,首先根据消息队列获取对应 broker 的地址,然后为消息分配全局 id,判断是否可以压缩以及是否是事务消息。如果注册了钩子函数,则在发送消息前调用执行。
4.构建requestHeader,包含生产者组、主题名称、默认创建主题 key、该主题在单个broker 中的默认队列数、队列 id、消息系统标记、消息发送时间、消息标记 flag、消息扩展属性、消息重试次数、是否是批量消息等。
5.选择异步方式进行发送,调用MQClientAPIImpl中的sendMessage(),构建RemotingCommand,将 body 和 header 放入 request 中。根据communicationMode调用sendMessageAsync()异步发送消息。该方法直接调用了remotingClient中的invokeAsync方法,并传入回调。回调函数会调用注册的钩子函数对返回的response进行处理,并更新故障延迟项。在出现异常时,会调用onexceptionImpl进行异常处理并重发消息。

获取主题路由信息

第一次发送消息时,本地没有换成 topic 的路由信息,查询 NameServer 尝试获取,如果路由消息未找到,再次尝试使用默认主题去查询。如果 BrokerConfig#autoCreateTopicEnable 为 true 时,NameServer 将返回路由信息,如果为 false 将抛出无法找到 topic 路由异常。
路由换成由 MQClientInstance 负责维护。

选择消息队列

选择消息队列有两种方式,一种是默认的机制,一种是故障延迟机制。
默认的机制在每次重试的时候,会自动选择下一个非lastBroker的消息队列。
故障延迟机制则是每次发送失败时,会根据响应的时延来决定该 broker 不可用的时间,每次选择消息队列时,除了要排除lastBroker外,还会排除当前不可用的 broker。这样就能避免默认机制下选择故障的 broker。
因为路由消息是 30s从 NameServer 处更新一次,所以在这段时间内自行将不可用的 broker 隔离以保证消息发送的高可用

批量消息发送

批量消息发送是指把多条同一主题的消息一起打包发送到服务端,减少网络调用次数,提高网络传输效率。RocketMQ 将消息同一封装在RemotingCommand这个数据结构中。

RemotingCommand

RemotingCommand的属性如下:
1.code:请求命令编码,请求命令类型
2.version:版本号
3.opaque:客户端请求序号
4.flag:标记。倒数第一位表示请求类型,0:请求;1:返回。倒数第二位,1:表示 oneway。
5.remark:描述
6.extFields:扩展属性
7customeHeader:每个请求对应的请求头信息
8.body:消息体内容

批量发送流程

RocketMQ 将多条消息体的内容存储在 body 中并使用固定格式进行存储,方便服务端解析。
首先在消息发送端,调用 batch 方法,将一批消息封装成 MessageBatch 对象。MessageBatch 继承自 Message 对象,持有一个List<Message> messages。然后将每条消息编码成一个byte[],作为聚合消息的消息体,在服务端就能正确解析了。在对每条消息进行编码时,只编码flag、body 和 properties。

Q & A

1.路由信息如何加载到本地
消息生产者在发送信息时,如果本地路由表中未缓存 topic 的路由信息,向 NameServer 发送获取路由信息请求,更新本地路由表,并且消息生产者每隔 30s 从 NameServer 更新路由表
2.消息发送如何实现高可用
(1)重试
(2)在一次消息发送过程中发现错误,在某一段时间内不会选择该 Broker 上的消息队列,提高发送消息的成功率
3.批量消息发送如何实现一致性
使用规定的编码方式对单条消息进行编码,编码成一个byte[],统一放在聚合消息的body里。在服务端再用相同的协议解码即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值