跳转至

Kafka 架构与存储:Topic、Partition、ISR

30 秒版(开场)

Kafka 是 分布式 commit log:Topic 按 Partition 水平切分,每条消息追加到分区末尾;Leader + ISR 副本 保证可用与一致性。消费并行度 = partition 数;分区内有序、跨分区无序。生产关键词:ISR、HW/LEO、replication.factor、min.insync.replicas。

3 分钟版(精讲深度)

  1. 是什么:Broker 集群存储 Topic;每个 Partition 是一个有序日志(Segment 文件);Producer 按 key hash 或轮询写入 partition;Consumer Group 按 partition 分配消费。
  2. 为什么:高吞吐顺序写 + 零拷贝;适合 日志流、事件总线、CDC;交易所成交、审计流水常见选型。
  3. 怎么做:replication.factor=3;min.insync.replicas=2 + acks=all 防丢;partition 数按目标吞吐与 consumer 并行度规划;监控 ISR 收缩与 under-replicated partitions。

10 分钟版(原理 + 图示)

flowchart TB
  P[Producer] --> L[Partition Leader]
  L --> F1[Follower ISR]
  L --> F2[Follower ISR]
  CG[Consumer Group] --> L
概念 说明
Topic 逻辑主题,如 trade.matched
Partition 物理分片;顺序日志;并行单元
Offset 分区内单调递增位置
Leader 读写入口;Follower 从 Leader 拉取
ISR 与 Leader 同步足够的副本集合
HW High Watermark;消费者可见的最大 offset
Segment 日志分段文件 + 索引,便于 retention 删除

写入路径:Producer → Leader 追加 → Follower replicate。acks=all 会等待当前 ISR 全部复制到位;min.insync.replicas 规定 ISR 至少还剩多少成员时才接受这种写入。它不是“只等 minISR 个副本”的计数参数。

Partition 数规划

因素 建议
目标吞吐 单 partition 约 MB/s 级(视消息大小)
Consumer 并行 partition 数 ≥ 峰值 consumer 实例数
顺序要求 需顺序的 key 固定进同一 partition
过多 partition 文件句柄、rebalance 成本、端到端延迟上升

生产场景

  • CEX 成交事件:symbol 作 key → 同交易对顺序;多 partition 水平扩展
  • 充提审计流水:高持久、可回放;retention 7~30 天或 compact
  • 风控特征流:多 consumer group 各自读全量(账务组 / 风控组 / 大屏组)

排查与工具

工具 用途
kafka-topics.sh --describe partition、leader、ISR
kafka-reassign-partitions 均衡、扩 partition
Broker metrics under-replicated、offline partitions
AKHQ / UI 可视化 ISR、lag

架构取舍

方案 适用 不适用
多 partition 高吞吐、并行消费 强全局顺序
单 partition 严格全序 吞吐瓶颈
RF=3, minISR=2 生产默认 测试环境可降
Log compaction changelog、KV 状态 纯事件流全量保留

深挖问答

  1. Leader 挂了? → Controller 从 ISR 选新 Leader;非 ISR 副本不能自动当选(unclean.leader.election=false 防丢数据)。
  2. HW 和 LEO 区别? → LEO 是副本自身末尾;HW 是已 commit、对消费者可见的位置。
  3. 和 RocketMQ CommitLog? → 思想类似顺序写;Kafka 以 partition 为并行单元(见 S-RMQ-01)。
  4. 能否减少 partition? → 不能直接减;只能新建 topic 迁移。

反模式与事故

  • partition=1 扛全站成交 → 单点吞吐瓶颈
  • min.insync.replicas=1 + 磁盘故障 → 丢已 ack 消息
  • ISR 长期 shrink 未告警 → 故障时无法选 Leader
  • 按天建 topic 而非 partition → 运维碎片化

代码示例

// segmentio/kafka-go:指定 key 保证同 symbol 进同 partition
writer := &kafka.Writer{
    Addr:     kafka.TCP("kafka:9092"),
    Topic:    "trade.matched",
    Balancer: &kafka.Hash{}, // 按 Message.Key 哈希
}
if err := writer.WriteMessages(ctx, kafka.Message{
    Key:   []byte("BTC-USDT"),
    Value: payload,
}); err != nil {
    return err
}

延伸阅读