源码分析 RocketMQ DLedger 多副本即主从切换实现原理,java开发数据库面试题

1、BrokerController 中与主从相关的方法详解


本节先对 BrokerController 中与主从切换相关的方法。

1.1 startProcessorByHa

BrokerController#startProcessorByHa

private void startProcessorByHa(BrokerRole role) {

if (BrokerRole.SLAVE != role) {

if (this.transactionalMessageCheckService != null) {

this.transactionalMessageCheckService.start();

}

}

}

感觉该方法的取名较为随意,该方法的作用是开启事务状态回查处理器,即当节点为主节点时,开启对应的事务状态回查处理器,对PREPARE状态的消息发起事务状态回查请求。

1.2 shutdownProcessorByHa

BrokerController#shutdownProcessorByHa

private void shutdownProcessorByHa() {

if (this.transactionalMessageCheckService != null) {

this.transactionalMessageCheckService.shutdown(true);

}

}

关闭事务状态回查处理器,当节点从主节点变更为从节点后,该方法被调用。

1.3 handleSlaveSynchronize

BrokerController#handleSlaveSynchronize

private void handleSlaveSynchronize(BrokerRole role) {

if (role == BrokerRole.SLAVE) { // @1

if (null != slaveSyncFuture) {

slaveSyncFuture.cancel(false);

}

this.slaveSynchronize.setMasterAddr(null); //

slaveSyncFuture = this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {

@Override

public void run() {

try {

BrokerController.this.slaveSynchronize.syncAll();

} catch (Throwable e) {

log.error(“ScheduledTask SlaveSynchronize syncAll error.”, e);

}

}

}, 1000 * 3, 1000 * 10, TimeUnit.MILLISECONDS);

} else { // @2

//handle the slave synchronise

if (null != slaveSyncFuture) {

slaveSyncFuture.cancel(false);

}

this.slaveSynchronize.setMasterAddr(null);

}

}

该方法的主要作用是处理从节点的元数据同步,即从节点向主节点主动同步 topic 的路由信息、消费进度、延迟队列处理队列、消费组订阅配置等信息。

代码@1:如果当前节点的角色为从节点:

  • 如果上次同步的 future 不为空,则首先先取消。

  • 然后设置 slaveSynchronize 的 master 地址为空。不知大家是否与笔者一样,有一个疑问,从节点的时候,如果将 master 地址设置为空,那如何同步元数据,那这个值会在什么时候设置呢?

  • 开启定时同步任务,每 10s 从主节点同步一次元数据。

代码@2:如果当前节点的角色为主节点,则取消定时同步任务并设置 master 的地址为空。

1.4 changeToSlave

BrokerController#changeToSlave

public void changeToSlave(int brokerId) {

log.info(“Begin to change to slave brokerName={} brokerId={}”, brokerConfig.getBrokerName(), brokerId);

//change the role

brokerConfig.setBrokerId(brokerId == 0 ? 1 : brokerId); //TO DO check // @1

messageStoreConfig.setBrokerRole(BrokerRole.SLAVE); // @2

//handle the scheduled service

try {

this.messageStore.handleScheduleMessageService(BrokerRole.SLAVE); // @3

} catch (Throwable t) {

log.error("[MONITOR] handleScheduleMessageService failed when changing to slave", t);

}

//handle the transactional service

try {

this.shutdownProcessorByHa(); // @4

} catch (Throwable t) {

log.error("[MONITOR] shutdownProcessorByHa failed when changing to slave", t);

}

//handle the slave synchronise

handleSlaveSynchronize(BrokerRole.SLAVE); // @5

try {

this.registerBrokerAll(true, true, brokerConfig.isForceRegister()); // @6

} catch (Throwable ignored) {

}

log.info(“Finish to change to slave brokerName={} brokerId={}”, brokerConfig.getBrokerName(), brokerId);

}

Broker 状态变更为从节点。其关键实现如下:

  • 设置 brokerId,如果broker的id为0,则设置为1,这里在使用的时候,注意规划好集群内节点的 brokerId。

  • 设置 broker 的状态为 BrokerRole.SLAVE。

  • 如果是从节点,则关闭定时调度线程(处理 RocketMQ 延迟队列),如果是主节点,则启动该线程。

  • 关闭事务状态回查处理器。

  • 从节点需要启动元数据同步处理器,即启动 SlaveSynchronize 定时从主服务器同步元数据。

  • 立即向集群内所有的 nameserver 告知 broker 信息状态的变更。

1.5 changeToMaster

BrokerController#changeToMaster

public void changeToMaster(BrokerRole role) {

if (role == BrokerRole.SLAVE) {

return;

}

log.info(“Begin to change to master brokerName={}”, brokerConfig.getBrokerName());

//handle the slave synchronise

handleSlaveSynchronize(role); // @1

//handle the scheduled service

try {

this.messageStore.handleScheduleMessageService(role); // @2

} catch (Throwable t) {

log.error("[MONITOR] handleScheduleMessageService failed when changing to master", t);

}

//ha

《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》

【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享

ndle the transactional service

try {

this.startProcessorByHa(BrokerRole.SYNC_MASTER); // @3

} catch (Throwable t) {

log.error("[MONITOR] startProcessorByHa failed when changing to master", t);

}

//if the operations above are totally successful, we change to master

brokerConfig.setBrokerId(0); //TO DO check // @4

messageStoreConfig.setBrokerRole(role);

try {

this.registerBrokerAll(true, true, brokerConfig.isForceRegister()); // @5

} catch (Throwable ignored) {

}

log.info(“Finish to change to master brokerName={}”, brokerConfig.getBrokerName());

}

该方法是 Broker 角色从从节点变更为主节点的处理逻辑,其实现要点如下:

  • 关闭元数据同步器,因为主节点无需同步。

  • 开启定时任务处理线程。

  • 开启事务状态回查处理线程。

  • 设置 brokerId 为 0。

  • 向 nameserver 立即发送心跳包以便告知 broker 服务器当前最新的状态。

主从节点状态变更的核心方法就介绍到这里了,接下来看看如何触发主从切换。

2、如何触发主从切换


从前面的文章我们可以得知,RocketMQ DLedger 是基于 raft 协议实现的,在该协议中就实现了主节点的选举与主节点失效后集群会自动进行重新选举,经过协商投票产生新的主节点,从而实现高可用。

BrokerController#initialize

if (messageStoreConfig.isEnableDLegerCommitLog()) {

DLedgerRoleChangeHandler roleChangeHandler = new DLedgerRoleChangeHandler(this, (DefaultMessageStore) messageStore);

((DLedgerCommitLog)((DefaultMessageStore) messageStore).getCommitLog()).getdLedgerServer().getdLedgerLeaderElector().addRoleChangeHandler(roleChangeHandler);

}

上述代码片段截取自 BrokerController 的 initialize 方法,我们可以得知在 Broker 启动时,如果开启了 多副本机制,即 enableDLedgerCommitLog 参数设置为 true,会为 集群节点选主器添加 roleChangeHandler 事件处理器,即节点发送变更后的事件处理器。

接下来我们将重点探讨 DLedgerRoleChangeHandler 。

2.1 类图

在这里插入图片描述

DLedgerRoleChangeHandler 继承自 RoleChangeHandler,即节点状态发生变更后的事件处理器。上述的属性都很简单,在这里就重点介绍一下 ExecutorService executorService,事件处理线程池,但只会开启一个线程,故事件将一个一个按顺序执行。

接下来我们来重点看一下 handle 方法的执行。

2.2 handle 主从状态切换处理逻辑

DLedgerRoleChangeHandler#handle

public void handle(long term, MemberState.Role role) {

Runnable runnable = new Runnable() {

public void run() {

long start = System.currentTimeMillis();

try {

boolean succ = true;

log.info(“Begin handling broker role change term={} role={} currStoreRole={}”, term, role, messageStore.getMessageStoreConfig().getBrokerRole());

switch (role) {

case CANDIDATE: // @1

if (messageStore.getMessageStoreConfig().getBrokerRole() != BrokerRole.SLAVE) {

brokerController.changeToSlave(dLedgerCommitLog.getId());

}

break;

case FOLLOWER: // @2

brokerController.changeToSlave(dLedgerCommitLog.getId());

break;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值