跳到主要内容

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 流处理框架。