🔭 嗨,您好 👋 我是 vnjohn,在互联网企业担任后端开发,CSDN 优质创作者
📖 推荐专栏:Spring、MySQL、Nacos、Java,后续其他专栏会持续优化更新迭代
🌲文章所在专栏:RocketMQ
🤔 我当前正在学习微服务领域、云原生领域、消息中间件等架构、原理知识
💬 向我询问任何您想要的东西,ID:vnjohn
🔥觉得博主文章写的还 OK,能够帮助到您的,感谢三连支持博客🙏
😄 代词: vnjohn
⚡ 有趣的事实:音乐、跑步、电影、游戏
目录
前言
RocketMQ 专栏篇:
从零开始:手把手搭建 RocketMQ 单节点、集群节点实例
保护数据完整性:探索 RocketMQ 分布式事务消息的力量
RocketMQ 分布式事务消息实战指南:确保数据一致性的关键设计
RocketMQ 生产者源码分析:DefaultMQProducer、DefaultMQProducerImpl
RocketMQ MQClientInstance、生产者实例启动源码分析
RocketMQ 投递消息方式以及消息体结构分析:Message、MessageQueueSelector
RocketMQ DefaultMQProducer#send 方法源码解析:生产者投递消息(一)
RocketMQ DefaultMQProducer#send 方法源码解析:生产者投递消息(二)
如上来自于官网中的通信结构图,核心接口:RemoteService、RemoteServer、RemoteClient,核心类:NettryRemotingServer、NettyRemotingClient,底层基于 Netty 网络通信框架实现
通信机制
RocketMQ 消息队列集群主要包括:NameServer、Broker(Master/Slave)、Producer、Consumer 四个角色,基本通讯流程如下:
-
Broker 在调用 start 方法时需要完成一次将自己注册到 NameServer 的操作,随后每隔 30s 定时向 NameServer 上报 Topic 路由信息,如下源码来自于 BrokerController#start 方法
// 如果没有开启DLeger的相关设置,默认没有启动,启动时首次向 NameServer 上报 Topic 路由信息 if (!messageStoreConfig.isEnableDLegerCommitLog()) { startProcessorByHa(messageStoreConfig.getBrokerRole()); handleSlaveSynchronize(messageStoreConfig.getBrokerRole()); this.registerBrokerAll(true, false, true); } // 每隔 30s 时间定时向 NameServer 上报 Topic 路由信息,允许值范围:10000~60000. this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { try { BrokerController.this.registerBrokerAll(true, false, brokerConfig.isForceRegister()); } catch (Throwable e) { log.error("registerBrokerAll Exception", e); } } // 1000 * 30 }, 1000 * 10, Math.max(10000, Math.min(brokerConfig.getRegisterNameServerPeriod(), 60000)), TimeUnit.MILLISECONDS);
-
消息生产者 Producer 作为客户端发送消息时,需要根据消息的 Topic 从本地缓存的 TopicPublishInfoTable 获取路由信息。如果没有则更新路由信息会从 NameServer 上重新拉取,同时 Producer 会默认每隔 30s 向 NameServer 拉取一次路由信息
Producer 定时调度拉取 Topic 路由信息,源码如下:
// MQClientInstance#startScheduledTask this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { try { MQClientInstance.this.updateTopicRouteInfoFromNameServer(); } catch (Exception e) { log.error("ScheduledTask updateTopicRouteInfoFromNameServer exception", e); } } // 1000 * 30 }, 10, this.clientConfig.getPollNameServerInterval(), TimeUnit.MILLISECONDS);
-
消息生产者 Producer 根据第二点中获取到的路由信息选择一个 MessageQueue 队列进行消息发送,Broker 作为消息的接收者接收消息并落盘存储
-
消息消费者 Consumer 根据第二点中获取到的路由信息,完成客户端的负载均衡后,选择其中某一个或几个消息队列来拉取消息并进行消费
从上面第 1-3 点,可以看出消息生产者、消费者、Broker、NameServer 之间都会发送通信
rocketmq-remoting 模块是 RocketMQ 消息队列中负责网络通信模块,它几乎被其他所有需要网络通信的模块(诸如:rocketmq-client、rocketmq-broker、rocketmq-namesrv)所引用,为了实现客户端与服务器之间高效的数据请求与接收,RocketMQ 消息队列自定义了通信协议并在 Netty 基础之上扩展了通信模块.
Remoting 通信类结构
接下来就开始介绍 remoting 通信类结构下的几个类
接口:RemotingService,实现子接口:RemotingServer、RemotingClient,实现子类:NettyRemotingServer、NettyRemotingClient
public interface RemotingService {
// 启动 Netty Boss、Worker 事件循环组
void start();
// 释放对应的线程资源,优雅退出等
void shutdown();
// 注册类似拦截器的功能,在请求前、后执行对应的操作
void registerRPCHook(RPCHook rpcHook);
}
接口:RemotingServer,实现子类:NettyRemotingServer,Broker、NameServer 会使用它来进行创建实例