跳到主要内容

Kafka 副本机制

副本机制是 Kafka 实现高可用和数据持久化的核心机制。本章将详细介绍 Kafka 副本的工作原理、同步机制和配置优化。

副本概述​

什么是副本?​

Kafka 通过将分区数据复制到多个 Broker 来实现高可用。每个分区可以有多个副本,分布在不同 Broker 上,当某个 Broker 故障时,其他副本可以继续提供服务。

副本角色​

角色说明职责
Leader主副本处理所有读写请求,负责数据同步
Follower从副本被动复制 Leader 数据,不处理客户端请求
ISR同步副本集合与 Leader 保持同步的副本,有资格成为新 Leader

为什么需要副本?​

  1. 高可用:Broker 故障时,副本可以接管服务
  2. 数据持久化:多副本存储,避免单点数据丢失
  3. 负载均衡:Follower 可以承担部分读请求(通过 Follower Fetching)
  4. 容灾:跨机房部署副本,实现异地容灾

副本同步机制​

同步原理​

关键概念​

LEO(Log End Offset):日志末端偏移量,表示下一条要写入的消息偏移量。每个副本都有自己的 LEO。

HW(High Watermark):高水位,表示已成功复制到所有 ISR 副本的消息偏移量。消费者只能看到 HW 之前的消息。

  • 绿色:HW 之前,消费者可见
  • 红色:HW 之后,尚未完全复制,消费者不可见

副本同步流程​

  1. Follower 发送 Fetch 请求:携带当前 Fetch Offset
  2. Leader 处理 Fetch 请求:从日志中读取数据返回
  3. Follower 写入日志:更新本地 LEO
  4. Leader 更新 HW:取所有 ISR 副本 LEO 的最小值
  5. Follower 更新 HW:从下一次 Fetch 响应中获取

副本 Fetcher 配置​

# Follower 拉取配置
replica.fetch.max.bytes=1048576
replica.fetch.min.bytes=1
replica.fetch.wait.max.ms=500
replica.fetch.backoff.ms=1000
replica.socket.timeout.ms=30000
replica.socket.receive.buffer.bytes=65536

ISR(In-Sync Replicas)​

什么是 ISR?​

ISR(In-Sync Replicas)是当前与 Leader 保持同步的副本集合。只有 ISR 中的副本才有资格成为新的 Leader。

ISR 判定条件​

副本是否在 ISR 中,取决于是否能在配置时间内追上 Leader:

# 判定副本是否在 ISR 中的时间阈值(默认 30s)
replica.lag.time.max.ms=30000

如果 Follower 在 replica.lag.time.max.ms 时间内没有发送 Fetch 请求或未能追上 Leader 的 LEO,则会被踢出 ISR。

ISR 动态调整​

ISR 收缩:当 Follower 滞后时,Leader 将其从 ISR 中移除,并通知 Controller。

ISR 扩张:当 Follower 追上 Leader 时,Leader 将其加入 ISR,并通知 Controller。

min.insync.replicas​

min.insync.replicas 定义了 ISR 中必须保持的最小副本数:

# 生产环境建议设置为 2
min.insync.replicas=2

作用:

  • 配合 acks=all 使用,确保消息写入足够多的副本
  • 如果 ISR 数量少于该值,生产者会收到 NotEnoughReplicasException
  • 提高数据可靠性,牺牲一定的可用性

消息确认机制(acks)​

acks 配置选项​

// acks=0:不等待确认
props.put("acks", "0");
// 最高吞吐,最低可靠
// 适用于可丢失消息的场景(如日志收集)

// acks=1:Leader 确认
props.put("acks", "1");
// 默认配置
// Leader 写入成功即返回,可能丢失数据(Leader 故障且 Follower 未同步)

// acks=all(或 -1):所有 ISR 确认
props.put("acks", "all");
// 最高可靠,稍低吞吐
// 配合 min.insync.replicas 使用

可靠性与性能权衡​

acks可靠性吞吐量延迟数据丢失场景
0最低最高最低Broker 故障即丢失
1中等高低Leader 故障且 Follower 未同步
all最高较低较高ISR 全部故障

推荐配置​

// 高可靠配置
Properties highReliabilityProps = new Properties();
highReliabilityProps.put("bootstrap.servers", "localhost:9092");
highReliabilityProps.put("key.serializer", "StringSerializer");
highReliabilityProps.put("value.serializer", "StringSerializer");

// 确保消息复制到多个副本
highReliabilityProps.put("acks", "all");
highReliabilityProps.put("min.insync.replicas", "2");

// 启用幂等性和重试
highReliabilityProps.put("enable.idempotence", "true");
highReliabilityProps.put("retries", "3");
highReliabilityProps.put("max.in.flight.requests.per.connection", "5");

Leader 选举​

选举触发条件​

  1. Leader 所在 Broker 故障:Controller 检测到 Broker 不可用
  2. 手动触发首选副本选举:恢复初始 Leader 分布
  3. 手动指定 Leader:管理员强制指定

选举策略​

正常选举(Clean Election):

  • 从 ISR 中选择新的 Leader
  • 保证数据不丢失
  • ISR 为空时无法选举

Unclean 选举:

  • 当 ISR 为空时,允许从非 ISR 副本中选举 Leader
  • 可能导致数据丢失
  • 需要显式启用:unclean.leader.election.enable=true

手动触发选举​

# 首选副本选举
kafka-leader-election.sh --bootstrap-server localhost:9092 \
--topic my-topic \
--partition 0 \
--election-type preferred

# Unclean 选举(谨慎使用)
kafka-leader-election.sh --bootstrap-server localhost:9092 \
--election-type unclean \
--topic my-topic \
--partition 0

副本分配策略​

自动分配​

Kafka 自动分配副本到 Broker,遵循以下原则:

  1. 副本分散:同一分区的副本分布在不同 Broker
  2. Leader 均衡:Leader 均匀分布到各 Broker
  3. 机架感知:考虑机架位置,跨机架分布副本(如果配置)

手动分配​

创建主题时可以指定副本分布:

# 指定副本分配
kafka-topics.sh --create \
--topic my-topic \
--bootstrap-server localhost:9092 \
--replica-assignment "0:1:2,1:2:0,2:0:1"
# 分区0: 副本在 Broker 0,1,2
# 分区1: 副本在 Broker 1,2,0
# 分区2: 副本在 Broker 2,0,1

机架感知配置​

# Broker 配置
broker.rack=rack1

# 创建主题时会考虑机架
# 同一分区的副本会分布在不同机架

副本重分配​

# 1. 创建重分配计划
cat > reassign.json << EOF
{
"version": 1,
"partitions": [
{"topic": "my-topic", "partition": 0, "replicas": [1,2,3]},
{"topic": "my-topic", "partition": 1, "replicas": [2,3,0]}
]
}
EOF

# 2. 执行重分配
kafka-reassign-partitions.sh --execute \
--reassignment-json-file reassign.json \
--bootstrap-server localhost:9092

# 3. 验证进度
kafka-reassign-partitions.sh --verify \
--reassignment-json-file reassign.json \
--bootstrap-server localhost:9092

副本监控​

关键指标​

# 查看副本状态
kafka-topics.sh --describe \
--topic my-topic \
--bootstrap-server localhost:9092

输出说明:

Topic: my-topic    Partition: 0    Leader: 1    Replicas: 1,2,3    Isr: 1,2,3
↑ ↑
AR (Assigned) ISR (In-Sync)

常见问题​

问题原因解决方案
ISR 数量减少Follower 滞后或故障检查网络和磁盘性能
副本不同步复制速度慢调整 replica.fetch.max.bytes
Leader 不均衡Broker 重启后未恢复执行首选副本选举
UnderReplicated副本数少于期望值检查 Broker 状态和网络

监控脚本​

#!/bin/bash
# 检查副本状态

echo "=== 检查 Under-Replicated 分区 ==="
kafka-topics.sh --describe \
--under-replicated-partitions \
--bootstrap-server localhost:9092

echo ""
echo "=== 检查离线分区 ==="
kafka-topics.sh --describe \
--unavailable-partitions \
--bootstrap-server localhost:9092

JMX 指标​

指标说明
UnderReplicatedPartitions复制不足的分区数
IsrShrinksPerSecISR 收缩速率
IsrExpandsPerSecISR 扩张速率
LeaderElectionRateLeader 选举频率
ReassignmentPercentCompleted重分配完成百分比

故障恢复​

Broker 故障恢复​

恢复后同步​

当故障 Broker 恢复后:

  1. Broker 重新上线,成为 Follower
  2. 从新 Leader 同步数据,截断 HW 之后的消息
  3. 追上 Leader 后,重新加入 ISR
  4. 可能成为 Leader(如果是首选副本)

数据恢复​

# 检查日志完整性
kafka-dump-log.sh --files /var/lib/kafka/data/topic-0/00000000000000000000.log \
--print-data-log

# 检查副本一致性
kafka-replica-verification.sh \
--broker-list "0:9092,1:9092,2:9092" \
--topic-white-list ".*"

最佳实践​

副本配置​

# 生产环境推荐配置
default.replication.factor=3
min.insync.replicas=2
unclean.leader.election.enable=false

# 副本同步配置
replica.lag.time.max.ms=30000
num.replica.fetchers=2

容量规划​

场景副本数min.insync.replicas特点
开发测试11最小资源占用
一般生产21平衡可用性和成本
高可用生产32高可用,容忍 1 个节点故障
金融级别3+2+极高可用性

监控告警​

建议设置以下告警:

  • ISR 数量变化告警
  • UnderReplicated 分区告警
  • Leader 选举频繁告警
  • 副本同步延迟告警

小结​

  1. 副本机制是 Kafka 高可用的基础,通过多副本存储保证数据安全
  2. Leader 处理读写请求,Follower 被动复制数据
  3. ISR 是与 Leader 同步的副本集合,决定哪些副本可以成为 Leader
  4. acks 配置影响消息可靠性,acks=all 配合 min.insync.replicas 实现最高可靠性
  5. 合理配置副本数和 min.insync.replicas 保证高可用

下一步​

接下来让我们学习 Kafka Streams 流处理框架。