Kafka 为什么不用 Raft协议?

一句话回答

Kafka 不是"一个队列"需要强一致,而是"一个日志流"需要高吞吐 。Raft 是为强一致设计的强约束协议,跟 Kafka 的基因(高吞吐、水平扩展、回溯消费)天然冲突。Kafka 用了"类 Quorum 思想"但更松散的 ISR 机制------这是它在 CAP 里选了 AP 之后的工程妥协。

一、先理解:Raft 的本质是什么?

Raft 是一个强一致 + 严格约束的协议:

Raft 的硬性要求:

  1. 任何写入必须被多数派(Quorum)确认才返回

  2. Leader 必须串行处理所有写请求(不能并行)

  3. 每次 Leader 变更都要 Term 自增

  4. Follower 只能从当前 Leader 同步(拒绝旧 Leader)

  5. 提交(commit)必须按日志顺序

  6. 任何不一致都会被检测和修复

这套机制换来的:强一致 + 不会丢数据 + 不会脑裂。

代价 :每次写都要等多数派网络往返------延迟是硬伤

二、Kafka 不用 Raft 的 6 个核心理由

1. 架构基因不同:一个"队列" vs 一个"日志流"

RabbitMQ Quorum Queue

  • 一个队列,就是一份数据
  • 强一致是核心诉求(消息不能丢、不能重)
  • Raft 的"每次写等多数派"在低吞吐下完全可接受

Kafka

  • 一个 Topic 有几百个 Partition,每个 Partition 独立
  • 核心诉求是吞吐(百万级/s)
  • 如果每个 Partition 都走 Raft 多数派同步 → 延迟直接爆炸

类比

RabbitMQ 是市区公路(强一致 = 保证畅通) Kafka 是高速公路(高吞吐 = 千万辆车/小时) Raft 是"红绿灯 + 限速 + 安全员"------对市区适用,对高速就是灾难

2. Raft 的"串行写入"会彻底毁掉 Kafka 的吞吐

Raft 的硬约束

  • Leader 必须串行处理请求(一次一个,不能并行)
  • 每次写都要等 多数派 ACK同步等待

Kafka 的现实需求

  • 生产者要批量发送(batch.size 攒 16KB / linger.ms 攒 5ms)
  • 顺序写磁盘(PageCache 顺序 IO)→ 千万级/s
  • 如果强制 Raft 串行 → 吞吐从百万级掉到几千级------Kafka 死了

具体数字对比

协议 单 Partition 吞吐 延迟
Raft(强一致) ~1-3 万/s 10-50ms
Kafka ISR(acks=1) ~10-30 万/s 1-3ms
Kafka ISR(acks=all) ~5-10 万/s 5-10ms

Kafka 选了 ISR 而不是 Raft,本质是用"可控的弱一致"换"数量级的吞吐提升"

3. Kafka 已经通过 Partition 实现了"分片 Raft"的效果

很多人没意识到:Kafka 的每个 Partition 内部,本身就是一个简化版 Raft

一个 Partition:

  • Leader(处理读写)

  • Follower 列表(从 Leader 拉数据)

  • ISR(同步副本集合)

  • 故障时从 ISR 选新 Leader

和 Raft 的对比

机制 Raft Kafka Partition
Leader 选举 Term + 多数派投票 Controller 选主(ZK/KRaft 协调)
日志复制 强同步,多数派确认 异步拉取replica.fetch.min.bytes
一致性保证 强一致 最终一致(acks=all 时接近强一致)
水平扩展 难(多节点难分片) 天然支持(加 Partition 就行)

Kafka 等于"把 Raft 拆成 N 份,每份独立并行跑"------这是和 Raft 根本不同的设计哲学。

4. Kafka 牺牲一致性换"水平扩展的极限"

Raft 的扩展性瓶颈

  • 增加节点 = 多数派增加 = 写延迟增加
  • 5 节点 Raft:写要 3 个 ack
  • 7 节点 Raft:写要 4 个 ack
  • 节点越多写越慢------这就是为什么 etcd 推荐 3/5 节点,不上 7

Kafka 的扩展思路

  • 增加节点 = 增加 Partition 数 = 总吞吐线性增长
  • 100 个 Partition × 10 万/s = 1000 万/s
  • Raft 永远做不到

这是分布式系统设计里"分片(Sharding)"的胜利------Raft 没分片,所以扩不动;Kafka 天然分片,所以能扩到上千节点。

5. Kafka 要"回溯消费",Raft 不支持

Kafka 的核心能力

  • 消费者可以重新消费历史消息(重置 offset 到任意位置)
  • 这要求消息持久化在磁盘 + 保留一段时间(如 7 天)

Raft 的设计目标

  • 数据"提交"后即可被状态机消费
  • 没有"保留"概念------提交即应用,应用即删除
  • 想要"回放"?在 Raft 之上再搭一套,那不是 Raft 本身的能力

这俩的设计目标不同 ------Kafka 选 ISR 配 log.retention.hours 保留数据,Raft 是"提交即消费"。

6. Kafka 的 Quorum 需求是"分区级别",不是"集群级别"

RabbitMQ Quorum Queue 的 Quorum

  • 一个队列的副本集合(3 个节点)
  • Quorum=2(多数派确认)

Kafka 的"类 Quorum"

  • 一个 Partition 的 ISR 集合(可能是 3 个 broker 中的 2 个)
  • min.insync.replicas=2(acks=all 时要 2 个 ISR 确认)

关键差异

  • RabbitMQ 一个集群可能就 3-5 个节点 → Quorum 简单
  • Kafka 一个集群可能几百个 broker,几千个 Partition不可能对整个集群做 Raft

Raft 在大规模集群里根本行不通------把 Raft 跑在几百节点上?选主一次要等所有节点投票 → 选主风暴 → 集群崩。

三、Kafka 实际用了"类 Quorum"的什么机制?

三个关键配置(记住就够用)

1. 副本数(影响 Quorum 大小)

default.replication.factor=3

2. 最少同步副本数(Quorum 硬约束)

min.insync.replicas=2

→ acks=all 时,必须有 2 个 ISR 副本确认才返回

3. 生产者确认级别

acks=all

→ Leader 等所有 ISR 同步完才返回

这三个配置组合 = Kafka 的"等效 Quorum"

  • 3 副本
  • 2 个 ISR 确认
  • 可以容忍 1 个节点挂掉,不丢数据

和 Raft 的 Quorum=2 在数据安全上等价 ,但没有 Raft 的强约束(如 Term、日志顺序、串行写入)------这给了 Kafka 巨大的性能空间。

unclean.leader.election.enable=false(防脑裂的关键)

Kafka 默认是 true(为了可用性),金融场景必须设 false

unclean.leader.election.enable=false 的含义:

  • 挂掉的 Follower 恢复后,只在 ISR 列表里才能成为 Leader

  • 已经被踢出 ISR 的副本(数据落后的)不能选主

  • 这避免了"数据落后的副本选为主,丢消息"

⚠️ 代价:所有 ISR 都挂时,Partition 不可用(高可用受损)

✅ 收益:杜绝脑裂和数据丢失(强一致)

这个开关本质上就是"在 AP 和 CP 之间切换"

  • true:AP 优先(牺牲一致性保可用性)
  • false:CP 优先(牺牲可用性保一致性)

四、面试话术

"Kafka 不用 Raft 是架构基因决定的------

Raft 是为强一致设计的 (串行写入、多数派确认、Term 选举),但 Kafka 的核心诉求是高吞吐 + 水平扩展 。Raft 一上,单 Partition 吞吐从 10 万级掉到 1 万级,Kafka 死了

Kafka 用了"类 Quorum"的 ISR 机制 ------replication.factor=3 + min.insync.replicas=2 + acks=all 就是它的等效 Quorum,能容忍 1 挂、零丢失

再配合 unclean.leader.election.enable=false 防止脑裂 ------这套组合在数据安全上和 Raft 等价,但保留了 Kafka 的高吞吐能力。

本质区别 :Raft 是'一个队列的强一致',Kafka 是'一千个分片的高吞吐'------设计目标不同,没有对错。"

五、再深一层:CAP 三选一的体现

系统 CAP 选型 体现
RabbitMQ Quorum Queue CP(强一致) Raft 协议,挂了不可用但数据安全
Kafka(默认) AP(可用性) ISR 机制,挂掉副本会"降级服务"
Kafka(acks=all + unclean=false) CP(强制强一致) 牺牲可用性保一致
etcd CP Raft,挂了不可用
Cassandra AP 最终一致

Kafka 默认是 AP,但配置到位可以接近 CP------这是它灵活的地方。

六、对比表(最终版)

维度 Kafka(ISR) RabbitMQ(Quorum) Raft 协议本身
设计目标 吞吐 投递可靠 强一致
CAP 选型 AP(可配 CP) CP CP
副本同步 异步拉取 同步推送 同步推送
多数派确认 手动配(min.insync.replicas) 内置 强制
串行写入 ❌(可批量)
水平扩展 ✅ 几千 Partition ❌ 队列不能分片 ❌ 节点越多越慢
吞吐/Partition 10-30 万/s 1-3 万/s 1-3 万/s
回溯消费 ✅ 天然 ❌ 不支持 ❌ 不支持
脑裂保护 unclean=false Quorum 强约束 Term 机制
适用场景 日志、流计算、削峰 订单、支付、RPC 配置中心、服务发现

七、一句话总结

Kafka 不用 Raft 是因为它要的是"分片高吞吐",不是"单点强一致"ISR 机制 = 弱化的 Quorum + 高吞吐 ,配上 acks=all + min.insync.replicas=2 + unclean=false 就能在数据安全上等价 Raft ,但没有 Raft 的强约束(串行/Term/严格顺序)------这给了 Kafka 数量级的性能优势。