生产者启动和消息发送流程
Producer
名词解释与设计架构可以阅读官方文档
生产者由于是用户使用的, 所以自然是用户创建的, 设置参数包括生产者的启动都应该是用户来进行,
所以我们从DefaultMQProducerTest默认的MQ生产者测试类作为入口看看producer的启动流程, 并且看看producer与broker的消息交互
start()
在测试类中, 有一个初始化方法init(), 其中给producer设置了namesrv地址, 设置了消息压缩的阈值, 设置了消息的topic, 然后调用了producer的start方法
在start方法中仅仅设置了生产者集群名称而后调用了impl的start
在impl中有两个start方法, 一个是无参的, 无参的start方法启动时会启动MQClientFactory
而启动MQClientFactory的时候又会启动impl, 所以这是调用有参方法, 跳过启动工厂的步骤
public void start() throws MQClientException {
this.start(true);
}
public void start(final boolean startFactory) throws MQClientException {
switch (this.serviceState) {
case CREATE_JUST:
// 省略部分内容
// 获取工厂单例
this.mQClientFactory = MQClientManager.getInstance().getOrCreateMQClientInstance(this.defaultMQProducer, rpcHook);
// 将生产者注册进工厂
// 这里会放到工厂对象中的producerTable里面
boolean registerOK = mQClientFactory.registerProducer(this.defaultMQProducer.getProducerGroup(), this);
// 如果注册失败说明相同名称的生产者已经启动过
if (!registerOK) {
this.serviceState = ServiceState.CREATE_JUST;
throw new MQClientException("The producer group[" + this.defaultMQProducer.getProducerGroup()
+ "] has been created before, specify another name please." + FAQUrl.suggestTodo(FAQUrl.GROUP_NAME_DUPLICATE_URL),
null);
}
// key为topic, value为发布信息存入map中
this.topicPublishInfoTable.put(this.defaultMQProducer.getCreateTopicKey(), new TopicPublishInfo());
// 启动mq客户端工厂
if (startFactory) {
mQClientFactory.start();
}
log.info("the producer [{}] start OK. sendMessageWithVIPChannel={}", this.defaultMQProducer.getProducerGroup(),
this.defaultMQProducer.isSendMessageWithVIPChannel());
this.serviceState = ServiceState.RUNNING;
break;
case RUNNING:
case START_FAILED:
case SHUTDOWN_ALREADY:
throw new MQClientException("The producer service state not OK, maybe started once, "
+ this.serviceState
+ FAQUrl.suggestTodo(FAQUrl.CLIENT_SERVICE_NOT_OK),
null);
default:
break;
}
this.mQClientFactory.sendHeartbeatToAllBrokerWithLock();
this.timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
try {
RequestFutureTable.scanExpiredRequest();
} catch (Throwable e) {
log.error("scan RequestFutureTable exception", e);
}
}
}, 1000 * 3, 1000);
}
最后在clientFactory中会从namesrv获取broker信息, 启动生产消费服务, 启动消息交互的channel
/**
* 不论是生产者还是消费者, 始终都是属于mq的客户端, 所以MQClient的start会启动拉取推送两个服务
* 在实际生产中, 有很多生产者同时也会扮演消费者的角色去broker中拉取数据, 所以这里一次性启动
*/
public void start() throws MQClientException {
synchronized (this) {
switch (this.serviceState) {
case CREATE_JUST:
this

本文详细解析RocketMQ生产者启动流程,从`start()`方法开始,探讨MQClientFactory如何从namesrv获取broker信息,并启动消息交互的channel。接着分析消息生产和发送过程,包括同步与异步方式,并深入到broker接收消息的处理,最终揭示RocketMQ如何保证commitLog的顺序写入,确保线程安全。
最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



