基于 raft 协议的 RocketMQ DLedger 多副本日志复制设计原理

上一篇 源码分析 RocketMQ DLedger(多副本) 之日志复制(传播) ,可能有不少读者朋友们觉得源码阅读较为枯燥,看的有点云里雾里,本篇将首先梳理一下 RocketMQ DLedger 多副本关于日志复制的三个核心流程图,然后再思考一下在异常情况下如何保证数据一致性。

1、RocketMQ DLedger 多副本日志复制流程图

1.1 RocketMQ DLedger 日志转发(append) 请求流程图

在这里插入图片描述

1.2 RocketMQ DLedger 日志仲裁流程图

在这里插入图片描述

1.3 RocketMQ DLedger 从节点日志复制流程图

在这里插入图片描述

2、RocketMQ DLedger 多副本日志复制实现要点

在这里插入图片描述
上图是一个简易的日志复制的模型:图中客户端向 DLedger 集群发起一个写请求,集群中的 Leader 节点来处理写请求,首先数据先存入 Leader 节点,然后需要广播给它的所有从节点,从节点接收到 Leader 节点的数据推送对数据进行存储,然后向主节点汇报存储的结果,Leader 节点会对该日志的存储结果进行仲裁,如果超过集群数量的一半都成功存储了该数据,主节点则向客户端返回写入成功,否则向客户端写入写入失败。

接下来我们来探讨日志复制的核心设计要点。

2.1 日志编号

为了方便对日志进行管理与辨别,raft 协议为一条一条的消息进行编号,每一条消息达到主节点时会生成一个全局唯一的递增号,这样可以根据日志序号来快速的判断数据在主从复制过程中数据是否一致,在 DLedger 的实现中对应 DLedgerMemoryStore 中的 ledgerBeginIndex、ledgerEndIndex,分别表示当前节点最小的日志序号与最大的日志序号,下一条日志的序号为 ledgerEndIndex + 1 。

与日志序号还与一个概念绑定的比较紧密,即当前的投票轮次。

2.2 追加与提交机制

请思考如下问题,Leader 节点收到客户端的数据写入请求后,通过解析请求,提取数据部分,构建日志对象,并生成日志序号,用 seq 表示,然后存储到 Leader 节点中,然后将日志广播(推送)到其从节点,由于这个过程中存在网络时延,如果此时客户端向主节点查询 seq 的日志,由于日志已经存储在 Leader 节点中了,如果直接返回给客户端显然是有问题的,那该如何来避免这种情况的发生呢?

为了解决上述问题,DLedger 的实现(应该也是 raft 协议的一部分)引入了已提交指针(committedIndex)。即当主节点收到客户端请求时,首先先将数据存储,但此时数据是未提交的,此过程可以称之为追加,此时客户端无法访问,只有当集群内超过半数的节点都将日志追加完成后,才会更新 committedIndex 指针,得以是数据能否客户端访问。

一条日志要能被提交的充分必要条件是日志得到了集群内超过半数节点成功追加,才能被认为已提交。

2.3 日志一致性如何保证

从上文得知,一个拥有3个节点的 DLedger 集群,只要主节点和其中一个从节点成功追加日志,则认为已提交,客户端即可通过主节点访问。由于部分数据存在延迟,在 DLedger 的实现中,读写请求都将由 Leader 节点来负责。那落后的从节点如何再次跟上集群的步骤呢?

要重新跟上主节点的日志记录,首先要知道的是如何判断从节点已丢失数据呢?

DLedger 的实现思路是,DLedger 会按照日志序号向从节点源源不断的转发日志,从节点接收后将这些待追加的数据放入一个待写队列中。关键中的关键:从节点并不是从挂起队列中处理一个一个的追加请求,而是首先查阅从节点当前已追加的最大日志序号,用 ledgerEndIndex 表示,然后尝试追加 (ledgerEndIndex + 1)的日志,用该序号从代写队列中查找,如果该队列不为空,并且没有 (ledgerEndIndex + 1)的日志条目,说明从节点未接收到这条日志,发生了数据缺失。然后从节点在响应主节点 append 的请求时会告知数据不一致,然后主节点的日志转发线程其状态会变更为COMPARE,将向该从节点发送COMPARE命令,用来比较主从节点的数据差异,根据比较的差异重新从主节点同步数据或删除从节点上多余的数据,最终达到一致。于此同时,主节点也会对PUSH超时推送的消息发起重推,尽最大可能帮助从节点及时更新到主节点的数据。

更多问题,`欢迎大家留言与我一起探讨。如果觉得文章对自己有些用处的话,麻烦帮忙点个赞,谢谢。


推荐阅读:RocketMQ 日志复制系列文章:
1、源码分析 RocketMQ DLedger 多副本存储实现
2、源码分析 RocketMQ DLedger(多副本) 之日志追加流程
3、源码分析 RocketMQ DLedger(多副本) 之日志复制(传播)


见文如面,我是威哥,热衷于成体系剖析JAVA主流中间件,关注公众号『中间件兴趣圈』,回复专栏可获取成体系专栏导航,回复资料可以获取笔者的学习思维导图
在这里插入图片描述

<think>好的,用户想了解RocketMQ的工作原理、消息队列和架构设计。首先,我需要回顾一下RocketMQ的基本架构,确保自己理解正确。根据引用[2]和引用[4],RocketMQ的架构主要包括NameServer、Broker、Producer和Consumer四个部分。NameServer负责服务发现和路由,Broker处理消息存储,而Producer和Consumer负责发送和接收消息。 接下来,用户可能想知道各个组件如何协同工作。例如,Producer发送消息到Broker,Broker将消息存储在CommitLog中,然后分发到不同的Consumer Queue。消费者从Consumer Queue拉取消息进行处理。这里需要解释清楚CommitLog和Consumer Queue的作用,以及为什么这样设计,比如提高写入效率和顺序读取。 然后,消息存储机制是关键部分。引用[4]提到了RocketMQ的存储结构,包括CommitLog、ConsumeQueue和IndexFile。需要详细说明这些部分如何配合,比如CommitLog作为主存储,ConsumeQueue作为索引,这样设计的好处是高效写入和快速检索。 分布式事务消息也是一个重点。根据引用[3],RocketMQ使用2PC协议和补偿机制来处理事务消息。这里需要解释事务消息的流程,比如预备消息、执行本地事务、提交或回滚,以及事务状态回查的机制。用户可能想知道如何保证消息的最终一致性,所以这部分要讲清楚。 高可用性和可扩展性方面,引用[1]和[2]提到RocketMQ支持主从复制Dledger集群模式。主从架构如何实现数据冗余,Dledger如何通过Raft协议保证一致性,这些都需要展开说明。此外,水平扩展能力也很重要,比如Broker的弹性扩容,NameServer的无状态设计如何支持扩展。 消息发送方式也是用户关心的点,引用[5]提到了同步、异步、顺序和单向发送。需要分别解释每种方式的适用场景,比如同步发送保证可靠性,异步发送提高吞吐量,顺序发送用于需要严格顺序的场景。 最后,用户可能有实际应用中的问题,比如如何部署监控。引用[4]提到使用rocketmq-console-ng进行监控,这部分可以简要说明如何启动控制台和访问监控界面。 整理这些点后,需要确保回答结构清晰,分点说明,同时结合引用内容自然插入引用标识。可能还需要生成相关问题,比如性能优化、事务消息细节、高可用实现等,帮助用户深入理解。</think>### RocketMQ工作原理与架构设计解析 #### 一、核心架构组件 RocketMQ的架构由四大核心组件构成: 1. **NameServer** 作为轻量级注册中心,负责Broker的注册与路由发现。采用无状态设计,多个节点间数据通过心跳机制保持同步[^2][^4]。 2. **Broker** 消息存储与转发核心节点,采用主从架构设计。单个Broker支持多主多从部署,通过Dledger技术实现数据强一致性[^3]。 3. **Producer** 支持同步/异步/单向三种消息发送模式,通过NameServer获取Broker路由信息后直接与Broker通信[^5]。 4. **Consumer** 提供集群消费和广播消费两种模式,采用长轮询机制实时拉取消息。支持消息过滤和重试机制。 $$ \text{消息流转路径:Producer} \rightarrow \text{Broker} \rightarrow \text{Consumer} $$ #### 二、消息存储机制 1. **CommitLog** 所有消息的物理存储文件,采用顺序写入方式保证高性能。单个文件默认1GB,通过内存映射技术实现零拷贝[^4]。 2. **ConsumeQueue** 逻辑队列索引文件,存储消息在CommitLog中的物理偏移量。每个Topic对应多个队列,实现消费并行度控制[^4]。 3. **IndexFile** 哈希索引文件,支持基于Message Key的消息查询。通过$key\_hash\%slotNum$快速定位数据。 #### 三、分布式事务实现 RocketMQ采用改进型两阶段提交协议: 1. 发送预备消息(Half Message) 2. 执行本地事务 3. 提交/回滚事务 4. 事务状态回查(补偿机制) $$ \begin{cases} \text{事务成功} & \rightarrow \text{提交消息可见} \\ \text{事务失败} & \rightarrow \text{删除预备消息} \end{cases} $$ 通过定时任务补偿未完成的事务消息。 #### 四、高可用设计 1. **主从复制** 同步复制(强一致)和异步复制(高性能)两种模式,支持故障自动切换。 2. **Dledger集群** 基于Raft协议实现多副本强一致性,选举过程满足$n \geq 2f+1$的容错条件[^3]。 3. **水平扩展** Broker支持弹性扩容,NameServer无状态设计可横向扩展,单集群支持管理上千Topic[^2]。 #### 五、典型应用场景 1. 削峰填谷(电商秒杀) 2. 分布式事务(订单支付) 3. 日志收集(实时数据分析) 4. 流式计算(与Flink/Spark集成)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

中间件兴趣圈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值