RocketMQ - 生产者启动流程
生产者启动流程

DefaultMQProducer是RocketMQ中默认的生产者实现
核心属性:
namesrvAddr: 继承自 ClientConfig,表示 RocketMQ 集群的Namesrv 地址,如果是多个则用分号分开。比如:127.0.0.1:9876;127.0.0.2:9876。
clientIP: 使用的客户端程序所在机器的 IP地址。支持 IPv4和IPv6,IPv4 排除了本地的环回地址(127.0.xxx.xxx)和私有内网地址(192.168.xxx.xxx)。这里需要注意的是,如果 Client 运行在Docker 容器中,获取的 IP 地址是容器所在的 IP 地址,而非宿主机的IP地址。
instanceName: 实例名,每个实例都需要取唯一的名字,因为有时我们会在同一个机器上部署多个程序进程,如果名字有重复就会导致启动失败。
vipChannelEnabled: 这是一个 boolean 值,表示是否开启 VIP通道。VIP 通道和非VIP通道的区别是:在通信过程中使用的端口号不同。
clientCallbackExecutorThreads: 客户端回调线程数。该参数表示 Netty 通信层回调线程的个数 ,默认值 Runtime.getRuntime().availableProcessors()表示当前CPU的有效个数。
pollNameServerInterval: 获取 Topic 路由信息的间隔时长,单位为 ms,默认为30 000ms。
heartbeatBrokerInterval: 与Broker心跳间隔的时长,单位为 ms,默认为30 000ms。
defaultMQProducerImpl: 默认生产者的实现类,其中封装了Broker的各种API(启动及关闭生产者的接口)。如果你想自己实现一个生产者,可以添加一个新的实现,保持DefaultMQProducer对外接口不变,用户完全没有感知。
producerGroup: 生产者组名,这是一个必须传递的参数。RocketMQ-way表示同一个生产者组中的生产者实例行为需要一致。
sendMsgTimeout: 发送超时时间,单位为ms。
compressMsgBodyOverHowmuch: 消息体的容量上限,超过该上限时消息体会通过ZIP进行压缩,该值默认为4MB。
retryTimesWhenSendFailed: 同步发送失败后重试的次数。默认为2次,也就是说,一共有3次发送机会。
retryTimesWhenSendAsyncFailed: 异步发送失败后重试的次数。默认为2次。异步重试是有条件的重试,并不是每次发送失败后都重试 。 源代码可以查看 org.apache.rocketmq.client.impl.MQClientAPIImpl.sendMessageAsync()方法 。 每次发送失败抛出异常后 , 通过执行onExceptionImpl()方法来决定什么场景进行重试
核心方法
start():这是启动整个生产者实例的入口,主要负责校验生产者的配置参数是否正确,并启动通信通道、各种定时计划任务、Pull服务、Rebalance服务、注册生产者到Broker等操作。
shutdown(): 关闭本地已注册的生产者,关闭已注册到Broker的客户端。
fetchPublishMessageQueues(Topic): 获取一个Topic有哪些Queue。在发送消息、Pull消息时都需要调用。
send(Message msg): 同步发送普通消息。
send(Message msg,long timeout): 同步发送普通消息(超时设置)。
send(Message msg,SendCallback sendCallback): 异步发送普通消息。
send(Message msg , SendCallback sendCallback , long timeout): 异步发送普通消息(超时设置)。
sendOneway(Message msg): 发送单向消息。只负责发送消息,不管发送结果。
send(Message msg,MessageQueue mq): 同步向指定队列发送消息。
send(Message msg,MessageQueue mq,long timeout): 同步向指定队列发送消息(超时设置)。同步向指定队列发送消息时,如果只有一个发送线程,在发送到某个指定队列中时,这个指定队列中的消息是有顺序的,那么就按照发送
时间排序;如果某个Topic的队列都是这种情况,那么我们称该Topic的全部消息是分区有序的。
send(Message msg , MessageQueue mq , SendCallback sendCallback): 异步发送消息到指定队列。
send(Message msg , MessageQueue mq , SendCallback sendCallback,long timeout): 异步发送消息到指定队列(超时设置)。
send(Message msg,MessageQueueSelector selector,Object arg,SendCallback sendCallback): 自定义消息发送到指定队列。通过实现MessageQueueSelector接口来选择将消息发送到哪个队列。
send(Collection<Message>msgs): 批量发送消息。
核心管理接口
createTopic(String key , String newTopic , int queueNum): 创建Topic。
viewMessage(String offsetMsgId): 根据消息id查询消息内容。
启动流程
生产者启动的流程比消费者启动的流程更加简单,一般用户使用DefaultMQProducer的构造函数构造一个生产者实例,并设置各种参数。比如Namesrv地址、生产者组名等,调用start()方法启动生产者实例,start()方法调用了生产者默认实现类的start()方法启动,这里我们主要讲实现类的start()方法内部是怎么实现的,

第一步: 通过 switch-case 判断当前生产者的服务状态,创建时默认状态是CREATE_JUST。设置默认启动状态为启动失败。
第二步: 执行 DefaultMQProducerImpl.checkConfig()方法。校验生产者实例设置的各种参数。比如生产者组名是否为空、是否满足命名规则、长度是否满足等。
第三步: 执行 DefaultMQProducer.changeInstanceNameToPID()方法。校验instancename,如果是默认名字则将其修改为进程id。
第四步: 执行 MQClientManager.getOrCreateMQClientInstance()方法。根据生产者组名获取或者初始化一个
MQClientInstance实例与 clientId是一一对应的,而clientId是由clientIP、instanceName 及 unitName 构成的。因此,为了减少客户端的使用资源,如果将所有的 instanceName和 unitName设置为同样的值,就会只创建一个 MQClientInstance实例
ClientConfig.java
public String buildMQClientId() {
StringBuilder sb = new StringBuilder();
sb.append(this.getClientIP());
sb.append("@");
sb.append(this.getInstanceName());
if (!UtilAll.isBlank(this.unitName)) {
sb.append("@");
sb.append(this.unitName);
}
if (enableStreamRequestType) {
sb.append("@");
sb.append(RequestType.STREAM);
}
return sb.toString();
}
MQClientInstance 实例的功能是管理本实例中全部生产者与消费者的生产和消费行为 。
org.apache.rocketmq.client.impl.factory.MQClientInstance
类的核心属性
public class MQClientInstance {
...
private final ClientConfig clientConfig;
private final int instanceIndex;
private final String clientId;
private final long bootTimestamp = System.currentTimeMillis();
//当前client实例的全部生产者的内部实例。
private final ConcurrentMap<String/* group */, MQProducerInner> producerTable = new ConcurrentHashMap<String, MQProducerInner>();
//当前client实例的全部消费者的内部实例。
private final ConcurrentMap<String/* group */, MQConsumerInner> consumerTable = new ConcurrentHashMap<String, MQConsumerInner>();
//当前client实例的全部管理实例。
private final ConcurrentMap<String/* group */, MQAdminExtInner> adminExtTable = new ConcurrentHashMap<String, MQAdminExtInner>();
private final NettyClientConfig nettyClientConfig;
//其实每个client也是一个Netty Server,也会支持Broker访问,这里实现了全部client支持的接口
private final MQClientAPIImpl mQClientAPIImpl;
//管理接口的本地实现类
private final MQAdminImpl mQAdminImpl;
//当前生产者、消费者中全部Topic的本地缓存路由信息
private final ConcurrentMap<String/* Topic */, TopicRouteData> topicRouteTable = new ConcurrentHashMap<String, TopicRouteData>();
private final Lock lockNamesrv = new ReentrantLock();
private final Lock lockHeartbeat = new ReentrantLock();
private final ConcurrentMap<String/* Broker Name */, HashMap<Long/* brokerId */, String/* address */>> brokerAddrTable =
new ConcurrentHashMap<String, HashMap<Long, String>>();
private final ConcurrentMap<String/* Broker Name */, HashMap<String/* address */, Integer>> brokerVersionTable =
new ConcurrentHashMap<String, HashMap<String, Integer>>();
//本地定时任务,比如定期获取当前 Namesrv 地址、定期同步Namesrv信息、定期更新Topic路由信息、定期发送心跳信息给Broker、定期清理已下线的Broker、
//定期持久化消费位点、定期调整消费线程数(这部分源代码被官方删除了)
private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "MQClientFactoryScheduledThread");
}
});
//请求的处理器,从处理方法 processRequest() 中我们可以知道目前支持哪些功能接口
private final ClientRemotingProcessor clientRemotingProcessor;
//Pull服务
private final PullMessageService pullMessageService;
//重新平衡服务。定期执行重新平衡方法this.mqClientFactory.doRebalance()。
//这里的 mqClientFactory 就是 MQClientInstance 实例,通过依次调用MQClientInstance中保存
//的消费者实例的doRebalance()方法,来感知订阅关系的变化、集群变化等,以达到重新平衡。
private final RebalanceService rebalanceService;
private final DefaultMQProducer defaultMQProducer;
//消费监控 。 比如拉取 RT(Response Time,响应时间)、拉取TPS(Transactions Per Second,每秒处理消息数)、消费RT等都可以统计。
private final ConsumerStatsManager consumerStatsManager;
}
类的核心方法
public class MQClientInstance {
//从多个Namesrv中获取最新Topic路由信息,更新本地缓存
public void updateTopicRouteInfoFromNameServer(){}
//清理已经下线的Broker
private void cleanOfflineBroker(){}
//检查Client是否在Broker中有效
private void checkClientInBroker(){}
//发送客户端的心跳信息给所有的Broker。
public void sendHeartbeatToAllBrokerWithLock() {}
//在本地注册一个消费者。
public synchronized boolean registerConsumer(final String group, final MQConsumerInner consumer) {}
//取消本地注册的消费者。
public synchronized void unregisterConsumer(final String group) {}
//在本地注册一个生产者。
public synchronized boolean registerProducer(final String group, final DefaultMQProducerImpl producer) {}
//取消本地注册的生产者。
public synchronized void unregisterProducer(final String group){}
//注册一个管理实例。
public boolean registerAdminExt(final String group, final MQAdminExtInner admin)
//立即执行一次 Rebalance。该操作是通过 RocketMQ 的一个CountDownLatch2锁来实现的。
public void rebalanceImmediately(){}
//对于所有已经注册的消费者实例 ,执行一次Rebalance。
public void doRebalance(){}
//在本地缓存中查找Slave Broker信息
public FindBrokerResult findBrokerAddressInSubscribe(
final String brokerName,
final long brokerId,
final boolean onlyThisBroker
){}
//在本地缓存中查找Master Broker地址。
public String findBrokerAddressInPublish(final String brokerName){}
//查找消费者id列表。
public List<String> findConsumerIdList(final String topic, final String group) {}
//通过Topic名字查找Broker地址。
public String findBrokerAddrByTopic(final String topic) {}
//重置消费位点。
public synchronized void resetOffset(String topic, String group, Map<MessageQueue, Long> offsetTable){}
//获取一个订阅关系中每个队列的消费进度。
public Map<MessageQueue, Long> getConsumerStatus(String topic, String group){}
//获取本地缓存Topic路由。
public ConcurrentMap<String, TopicRouteData> getTopicRouteTable(){}
//直接将消息发送给指定的消费者消费,和正常投递不同的是,指定了已经订阅的消费者组中的一个,
//而不是全部已经订阅的消费者。一般适用于在消费消息后,某一个消费者组想再消费一次的场景。
public ConsumeMessageDirectlyResult consumeMessageDirectly(final MessageExt msg,
final String consumerGroup,
final String brokerName) {}
//获取消费者的消费统计信息。包含消费RT、消费TPS等。
public ConsumerRunningInfo consumerRunningInfo(final String consumerGroup){}
}
RocketMQ - 生产者启动流程的更多相关文章
- RocketMQ生产者消息篇
系列文章 RocketMQ入门篇 RocketMQ生产者流程篇 RocketMQ生产者消息篇 前言 上文RocketMQ生产者流程篇中详细介绍了生产者发送消息的流程,本文将重点介绍发送消息的通信模式以 ...
- RocketMQ之九:RocketMQ消息发送流程解读
在讨论这个问题之前,我们先看一下Client的整体架构. Producer与Consumer类体系 从下图可以看出以下几点:(1)Producer与Consumer的共同逻辑,封装在MQClientI ...
- Flume-ng源码解析之启动流程
今天我们通过阅读Flume-NG的源码来看看Flume的整个启动流程,废话不多说,翠花,上源码!! 1 主类也是启动类 在这里我贴出Application中跟启动有关的方法,其他你们可以自己看源码,毕 ...
- rocketmq生产者代码分析
rocketmq生产者代码分析 环境安装 参考http://rocketmq.apache.org/docs/quick-start/ ,配置环境变量 export NAMESRV_ADDR=loca ...
- Flink 源码解析 —— Standalone Session Cluster 启动流程深度分析之 Job Manager 启动
Job Manager 启动 https://t.zsxq.com/AurR3rN 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1学习 -- Mac ...
- Flink 源码解析 —— Standalone session 模式启动流程
Standalone session 模式启动流程 https://t.zsxq.com/EemAEIi 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0 ...
- Flink 源码解析 —— Standalone Session Cluster 启动流程深度分析之 Task Manager 启动
Task Manager 启动 https://t.zsxq.com/qjEUFau 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1学习 -- Ma ...
- Netty启动流程剖析
编者注:Netty是Java领域有名的开源网络库,特点是高性能和高扩展性,因此很多流行的框架都是基于它来构建的,比如我们熟知的Dubbo.Rocketmq.Hadoop等,针对高性能RPC,一般都是基 ...
- MyCat源码分析系列之——配置信息和启动流程
更多MyCat源码分析,请戳MyCat源码分析系列 MyCat配置信息 除了一些默认的配置参数,大多数的MyCat配置信息是通过读取若干.xml/.properties文件获取的,主要包括: 1)se ...
- Android进阶系列之源码分析Activity的启动流程
美女镇楼,辟邪! 源码,是一个程序猿前进路上一个大的而又不得不去翻越障碍,我讨厌源码,看着一大堆.5000多行,要看完得啥时候去了啊.不过做安卓的总有这一天,自从踏上这条不归路,我就认命了.好吧,我慢 ...
随机推荐
- 【每日一题】【将cur的next尾插到pre后面,尾插k-1次】25. K 个一组翻转链表-211115&220120
给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表. k 是一个正整数,它的值小于或等于链表的长度. 如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序. 进阶: 你可以设 ...
- TransmittableThreadLocal和@Async优雅的记录操作日志
此文主要讲解: 如何实现操作记录 如何将TransmittableThreadLocal和@Async搭配使用 TransmittableThreadLocal阿里的一个开源组件,为了在使用线程池等会 ...
- aiohttp、asyncio使用协程增加爬虫效率
import aiohttp import asyncio import time async def get_requests(url): async with aiohttp.ClientSess ...
- python 异步写入文件
# -*- coding:utf-8 -*-import asyncioimport aiofilesimport time#异步操作时,函数名前必须加上asyncasync def func1(): ...
- 粘包、struct模块、进程并行与并发
目录 粘包现象 struct模块 粘包代码实战 udp协议(了解) 并发编程理论 多道技术 进程理论 进程并行与并发 进程的三状态 粘包现象 1.服务端连续执行三次recv 2.客户端连续执行三次se ...
- 精华推荐 | 【深入浅出RocketMQ原理及实战】「性能原理挖掘系列」透彻剖析贯穿RocketMQ的事务性消息的底层原理并在分析其实际开发场景
什么是事务消息 事务消息(Transactional Message)是指应用本地事务和发送消息操作可以被定义到全局事务中,要么同时成功,要么同时失败.RocketMQ的事务消息提供类似 X/Open ...
- sha1_b64_scrape
过无限debugger:https://www.cnblogs.com/hkwJsxl/p/16702143.html 网站 aHR0cHM6Ly9hbnRpc3BpZGVyOC5zY3JhcGUuY ...
- uniapp中封装一个弹框组件
第一步:在components下创建 popup.vue子组件: popup.vue中 <template> <view> <view class="popus ...
- [OpenCV实战]48 基于OpenCV实现图像质量评价
本文主要介绍基于OpenCV contrib中的quality模块实现图像质量评价.图像质量评估Image Quality Analysis简称IQA,主要通过数学度量方法来评价图像质量的好坏. 本文 ...
- P8340 [AHOI2022] 山河重整
\(20pts\) 给 \(O(2^n)\) 枚举,\(60pts\) 是 \(O(n^2)\),先看看怎么做.计数题无非容斥和 \(dp\),不妨从 \(dp\) 入手.多项式复杂度的做法意味着无法 ...