源码分析RocketMQ之Producer-消息的发送
消息发送类型分为
同步(Sync)发送
同步发送是指发送者向MQ执行发送消息API时,同步等待,直到消息服务器返回发送结果。
如:重要通知邮件、报名短信通知、营销短信
异步(Async)发送
发送者向MQ执行发送消息API时,指定消息发送成功后的回掉函数,然后调用消息发送API后,立即返回,消息发送者线程不阻塞,
直到运行结束,消息发送成功或失败的回调任务在一个新的线程中执行
用于链路耗时较长,对响应时间较为敏感的业务场景,视频上传后通知
单向(Oneway)发送
消息发送者向 MQ 执行发送消息 API 时,直接返回,不等待消息服务器的结果。
耗时非常短,但对可靠性要求并不高的场景,例如日志收集
消息发送大致的步骤可以分为
1、消息头解析,消息验证
2、路由查询
3、选择消息队列
4、消息组装
5、消息发送
6、消息结果处理
7、异常处理
入口方法:DefaultMQProducerImpl#sendDefaultImpl
消息入参
1、msg 消息内容
2、communicationMode 通信模式
3、sendCallback 发送回调
4、timeout 发送消息请求超时时间
消息发送流程
1、消息发送前检查
1、校验Producer 处于运行状态
2、校验消息格式,消息内容不能为空,topic不能为空,主题名称字母数字,最多长度127,是否与自动主题重复
2、获取Topic 路由信息 tryToFindTopicPublishInfo
3、选择要发送到的消息队列,通过selectOneMessageQueue方法 确定发送消息队列
1、判断是否开启延迟容错机制,默认关闭
2、如果开启,通过路由信息获取循环所有MessageQueue
3、获取 index,选择消息队列的index自增,最大max时,赋值0,第一次发送随机一个数字,存入threadLocalIndex
4、如果没有匹配的MessageQueue,latencyFaultTolerance.pickOneAtLeast选择一个相对较好的broker,并获得其对于的一个消息队列,
按照可用性>延迟>开始可用时间选择
5、如果写的队列数大于0,设置新的brokerName,与queueId,返回消息队列
6、如果写队列数为0 latencyFaultTolerance 移除此brokerName
7、如果都没有时,不考虑队列的可用性,选择一个消息队列
4、执行消息发送核心方法
1、默认同步调用3次机会,存储每次发送消息选择的broker名,开始发送时间,结束发送时间,差值判断超时时间
2、当 lastBrokerName == null 时,获取第一个可用的MessageQueue
3、当 lastBrokerName != null 时, 获取 brokerName=lastBrokerName && 可用的MessageQueue
4、调用sendKernelImpl方法发送消息远程请求
1、通过breakerName获取brokerAddr,为空,重新根据topic从Nameserver获取,vip 端口改变
2、消息发送前的检查,信息组装
1、设置批量消息唯一id
2、是否设置Namespace
3、是否压缩,内容超过4k进行压缩
4、检查属性TRAN_MSG,如果存在并且值为true,则通过设置消息系统标记的方式设置消息为MessageSysFlag.TRANSACTION_PREPARED_TYPE
5、设置hook
3、组装消息发送header
生成者组、topic、默认topic、默认队列数、发送消息队列的queueId、是否压缩是否、是否批量消息、重试消费次数
4、判断消息模式异步、同步、单向(Oneway)发送
1、超时判断
2、 this.mQClientFactory.getMQClientAPIImpl().sendMessage 方法发送消息
3、异步发送MQClientAPIImpl.sendMessageAsync 里面封装了一个远程客户端NettyRemotingClient
这个远程客户端使用netty作为通讯
4、NettyRemotingClient.invokeAsync方法 发送消息
1、根据addr获取netty channel
2、如果管道不为空,且可用
3、doBeforeRpcHooks 前置回调
4、超时判断
5、内部调用invokeAsyncImpl
1、获取requestId
2、超时时间信号量获取默认 65535个
3、判断超时,释放令牌
4、组装ResponseFuture 异步带返回值
5、将ResponseFuture 放入responseTable Map 键requestId 值ResponseFuture
6、通过hannel.writeAndFlush(request)请求
7、添加监听器异步监听结果设置responseFuture
8、processSendResponse处理 返回结果
1、判断状态码
2、请求头反序列化SendMessageResponseHeader
3、创建一个MessageQueue
4、封装SendResult 返回
5、发送更新可用性信息,发送时间超过550ms后会有不可用时长,至少30S 一行代码来收集这些延迟,注意它的isolation 参数,也就是隔离 是false
6、异常处理
RemotingException异常 MQClientException InterruptedException
MQBrokerException 如果是 TOPIC_NOT_EXIST、SERVICE_NOT_AVAILABLE、SYSTEM_ERROR、NO_PERMISSION、NO_BUYER_ID
NOT_IN_CURRENT_UNIT 进行消息重试发送
源码分析RocketMQ之Producer-消息的发送
于 2022-06-18 16:02:23 首次发布