文章目录
-
- [一. 源起](#一. 源起)
- [二. 架构之间的区别](#二. 架构之间的区别)
-
- [1. kafka架构](#1. kafka架构)
- [2. rocketmq架构](#2. rocketmq架构)
- [三. 设计理念区别](#三. 设计理念区别)
- [四. kafka的isr机制 (In-Sync Replicas 同步副本集合)](#四. kafka的isr机制 (In-Sync Replicas 同步副本集合))
-
- [4.1 实现流程](#4.1 实现流程)
- [4.2 动态isr流程](#4.2 动态isr流程)
- [4.3 为什么要设计成动态的isr呢?](#4.3 为什么要设计成动态的isr呢?)
- [4.4 isr怎么保证的数据安全](#4.4 isr怎么保证的数据安全)
- [五. rocketmq的主从机制](#五. rocketmq的主从机制)
-
- [5.1 介绍](#5.1 介绍)
- [5.2 复制模式](#5.2 复制模式)
- [5.3 同步模式为什么不能设置成全部的salve都写入成功才ack呢?](#5.3 同步模式为什么不能设置成全部的salve都写入成功才ack呢?)
- [5.4 传统主从模式的不足](#5.4 传统主从模式的不足)
- [六. rocketmq的Dledger机制](#六. rocketmq的Dledger机制)
-
- [6.1 master和salve写数据的流程](#6.1 master和salve写数据的流程)
- [6.2 leader选举的流程](#6.2 leader选举的流程)
- [七. isr,主从,dledger机制对比总结](#七. isr,主从,dledger机制对比总结)
一. 源起
大家都知道mq在消息防丢方面的,都是分成生产者同步发送,消费者ack以及broker在多个分片持久化完成。
但是作为消息中间件的kafka和rocketmq的实现的具体过程是不同。
(虽然整体都是master副本在等到slave副本持久化成功之后 再给生成者ack)。
下面从的架构设计和设计理念分析,各自具体的实现流程。
二. 架构之间的区别
1. kafka架构

注意 kafka的副本是partion级别, 由一个leader partion和多个follower partion组成。
2. rocketmq架构

注意 rocketmq的master和slave都是broker级别的。
三. 设计理念区别
Kafka 是流平台:
1. 核心抽象是分区日志流。消息(在Kafka里更常被称为"记录")一旦被写入分区,其位置(偏移量)就是不可变的、有序的。
2. 语义是"流处理":消费者通过管理偏移量来跟踪处理进度。如果某条记录处理失败,标准的做法不是跳过它,而是停止前进,直到问题解决。因为跳过一条记录意味着数据流出现了缺口,会导致后续的状态计算(如聚合、连接)全部出错。保证数据的完整性和顺序性是流处理的生命线。
RocketMQ/ActiveMQ/RabbitMQ 是消息中间件:
1. 核心抽象是队列或主题。设计目标是为独立的、离散的"消息"提供可靠传递。
2. 语义是"消息处理":每条消息通常是独立的。一条消息的处理失败不应阻塞其他消息的处理。因此,将"坏消息"移走(到DLQ)以保持主流程畅通是一个非常合理的模式。
四. kafka的isr机制 (In-Sync Replicas 同步副本集合)

4.1 实现流程
1. 生产消息阶段: 生产者发送消息到leader副本。
这里可以配置acks控制写入策略。 这里以acks =-1要等全部说明。
2. leader写入与follower复制:
leader副本将数据写入本地log. follower副本异步的从leader副本复制数据。
3. 在所有的follower都完成数据复制的情况下,leader返回给生产者发送ack确认
acks选项 | 含义 | 适用场景 |
---|---|---|
0 | 不需要等任何确认 | 非关键的业务活动日志, 实时监控表盘数据 |
1 | leader写入数据 直接响应ack | 业务日志, 业务通知类允许特别场景少量丢失热的业务 |
-1 | 全部follower副本都完成数据复制,再响应ack | 金融交易、订单、支付、转账 |
4.2 动态isr流程
1. 落后的follower副本被踢出isr
通过 replica.lag.time.max.ms 参数控制(默认30秒)。
如果一个Follower副本在这个时间窗口内没有向Leader发起拉取请求(比如Follower宕机)或者进度差距太大,
Leader就会认为它"落后太多",将其从ISR中移除
2. follower副本重新加入isr
follower副本的进度跟上leader副本的进度就可以重新加入isr。
4.3 为什么要设计成动态的isr呢?

1. 规避木桶效应.避免单个慢节点拖垮整个分区
follower副本因为网络抖动,磁盘IO,复制速度很慢, 在静态isr场景 生产者acks=-1所有的请求都有这个副本的速度限制。动态isr通过将这个follower踢出去解决这个问题。
2. 实现动态容错能力
某个broker宕机之后, leader监测心跳,将没有没有心跳的follower踢出isr。 如果是静态isr, 需要运维同事挨个修改isr的配置
4.4 isr怎么保证的数据安全
1. 新的Leader必须从ISR集合中选举产生, 而所有的副本都有全部的数据。
2. 读写都从leader副本走, 即使follower挂掉也不影响读写。
3. 自动剔除慢速/故障副本,并在其恢复后重新纳入。
五. rocketmq的主从机制

5.1 介绍
1. master broker负责读写
2. salve broker做热备份,仅在Master故障或压力过大时,消费者才可能从Slave消费(需要配置)。
3. 该模式遇到master broker宕机时, 需要人工介入切换master。
5.2 复制模式
模式 | 特点 |
---|---|
异步 | Master写入成功即返回ACK,然后异步将数据同步给Slave。 |
同步 | 等一个Slave写入成功 即返回ack。 这里不能设置成全部salve都写入成功。 |
5.3 同步模式为什么不能设置成全部的salve都写入成功才ack呢?
- 架构简单性:RocketMQ的设计初衷是简单高效。
一对多的复杂同步协商(需要等待多个副本的ACK)会引入巨大的复杂性,如节点管理、一致性协议等。 - 性能考量:等待多个Slave的ACK会显著增加写入延迟。延迟取决于最慢的那个Slave节点。如果有一个Slave网络不稳定或磁盘慢,整个集群的写入性能都会受到拖累。
- 足够的可靠性:在大多数场景下,保证数据在两个节点(Master和一个Slave)上存在,已经能够应对单点故障,满足了高可用需求。等待更多的副本被认为是"过度设计"。
5.4 传统主从模式的不足
- 无法自动故障转移, 需要人工介入
- 数据一致性不足, 即使同步模式.也只能等一个salve同步成功之后 就会ack给生产者
六. rocketmq的Dledger机制
6.1 master和salve写数据的流程

从流程图可以看到, 需要过半的follower写入, leader才会返回给生产者ack。 这保证了数据的一致性。
6.2 leader选举的流程

1. 故障检测与心跳超时
Leader会定期向所有Follower发送心跳, 每个Follower都维护着一个随机的选举超时计时器。
如果在该时间段内没有收到当前Leader的心跳,Follower就会假定Leader已经失效。
超时时间是随机的,避免多个follower同时开始选举。
2. 转变为Candidate并开始选举
a. 超时的follower转变成Candidate
b. 增加的任期号
c. 投一票给自己,
d. 并行向其他的follower发起投票请求 RequestVote RPC
3. 其他节点投票
a. 检查任期
如果请求中的任期号 小于 接收者当前的任期号,则拒绝投票。
如果请求中的任期号 大于 接收者当前的任期号,接收者会更新自己的任期号并转为Follower。
b. 投票承诺
在一个任期内,每个节点最多只能投出一票,且遵循先到先得的原则。这防止了多个Candidate获得多数票。
c. 日志完整性检查
投票者会比较Candidate和自己的日志,Candidate最后一条日志的任期号必须比投票者的更新(任期号更大),
或者如果任期号相同,Candidate的日志索引必须不小于投票者的日志索引。
这条规则确保了只有拥有全部已提交日志的节点才能成为Leader,从而避免数据丢失。
4. 选举结果
a. 如果获得n/2 + 1个票 身份从candidate转成leader
b. 向其他节点发送心跳,宣告选举结束
5. 新Leader开始工作
a. 开始接收请求, 生产者客户端可能会短暂失败,但会通过重试机制从NameServer获取到新的路由信息,最终将请求发送到新Leader(Node B)
b. 新Leader会开始管理日志的复制。它会强制Follower复制自己的日志,确保数据最终一致
七. isr,主从,dledger机制对比总结
特性 | Kafka ISR (In-Sync Replicas) | RocketMQ 传统主从模式 | RocketMQ DLedger 模式 |
---|---|---|---|
复制机制 | Leader + ISR (同步副本集合),follower 拉取 leader 数据,需保持在 ISR 内 | Master 写入,Slave 异步复制(异步模式,可能丢数据;半同步模式,部分确认) | 基于 Raft 共识协议(DLedger 组件),强一致复制 |
写入确认 | 可配置 acks=0/1/all ,其中 all 需 ISR 全部确认 |
默认异步复制,master 成功即返回;同步刷盘模式需至少一个 slave 成功 | 必须多数派(>N/2)节点写成功才返回,保证强一致 |
主从角色 | 动态选举 leader,ISR 中存活副本可成为 leader | Master 固定,Slave 不能自动切换为 Master,需要人工或外部脚本 | 自动 leader 选举(Raft 协议),follower 可无缝升级为 leader |
高可用性 | Leader 挂掉后,Zookeeper/Controller 触发新 leader 选举 | Master 挂掉需人工干预,业务中断风险大 | Leader 自动选举,服务可快速恢复 |
数据一致性 | 最终一致性(依赖 ISR 机制和 acks 配置),可能丢数据 | 一般为"读写分离",一致性弱,主从延迟可能导致数据不一致 | 强一致性,数据不会丢失 |
运维复杂度 | 较高,需要依赖 Zookeeper 维护元数据和 ISR 列表 | 简单,但高可用和一致性较差 | 相对复杂,引入 DLedger 组件,但减少人工切换 |
适用场景 | 高吞吐场景,可在一致性和可用性之间灵活选择 | 追求简单复制,允许数据延迟或丢失 | 金融级、高一致性要求的场景 |