Apache Kafka: Log Streaming Platform
Topics, partitions and offsets, producers and consumers, consumer groups and rebalancing, replication, and delivery semantics.
A Distributed Append-Only Log
Kafka is not a queue with per-message pops — it is a partitioned, replicated append log. Producers append, consumers read at their own offset, and data stays for a retention window regardless of consumption. That design decouples producers from consumers and makes it the backbone of event streaming, log aggregation and CDC pipelines.
Topic: orders(逻辑频道)
├─ Partition 0 [m0][m1][m2][m3]... ← 不可变序列,offset 单调递增
├─ Partition 1 [m0][m1]...
└─ Partition 2 [m0][m1][m2]...
每条消息只落一个分区;分区是并行度的单位
消息 = topic + partition + offset(全局唯一定位)
顺序只在分区内保证;按 key 分区可保证同 key 有序
Producers
# 命令行快速体验
kafka-topics --bootstrap-server localhost:9092 \
--create --topic orders --partitions 3 --replication-factor 3
kafka-console-producer --bootstrap-server localhost:9092 \
--topic orders
kafka-console-consumer --bootstrap-server localhost:9092 \
--topic orders --from-beginning --group demo
# Java 客户端骨架
# Properties p = new Properties();
# p.put("bootstrap.servers", "k1:9092,k2:9092");
# p.put("key.serializer", StringSerializer.class.getName());
# p.put("value.serializer", StringSerializer.class.getName());
# KafkaProducer<String, String> producer = new KafkaProducer<>(p);
# producer.send(new ProducerRecord<>("orders", userId, json));
acks, Retries and Idempotence
# 投递可靠性三档
acks=0 发出去就不管(可能丢)
acks=1 Leader 写入即成功(Leader 挂了可能丢)
acks=all ISR 全部持久化(默认,最稳)
# 重试与幂等(生产者侧防重复)
enable.idempotence=true # 幂等生产者( PID + 序列号,单分区去重)
max.in.flight.requests.per.connection=5
retries=2147483647 # 无限重试
# 事务(跨分区精确一次)
transactional.id=order-tx # 两阶段提交到事务日志
# begin -> sendOffsets -> commit;consumers 需 isolation.level=read_committed
# 消息有序性:同一 key 的消息进同一分区即有序
# 幂等 + 限制 inflight 5 之内可保证同分区不乱序
| 语义 | 配置组合 | 成本 |
|---|---|---|
| At most once(最多一次) | acks=0 或不重试 | 可能丢,不重复 |
| At least once(至少一次) | acks=all + retries | 不丢,可能重复(默认) |
| Exactly once(精确一次) | 幂等 + 事务 + read_committed | 最强,吞吐下降 |
Consumer Groups and Rebalancing
消费组 demo(3 个消费者实例)订阅 orders(3 个分区):
消费者 A ← partition 0
消费者 B ← partition 1
消费者 C ← partition 2
分区分配策略:range / roundrobin / sticky(防抖动首选)
再均衡(Rebalance):成员变更时重新分配分区
触发:消费者上下线、订阅变化、分区数变化
代价:STW(消费全部暂停)—— 是稳定性头号敌人
__consumer_offsets:消费组提交偏移量的内部主题
enable.auto.commit=true(默认,可能重复消费)
手动提交:处理完业务再 commitSync() 更安全
Rebalance 优化:
session.timeout.ms / heartbeat 间隔调合理
max.poll.interval.ms 按处理耗时上调
lengthy 启动用 CooperativeRebalanceProtocol
Replication and ISR
- Each partition has one leader and N-1 followers; all reads and writes hit the leader, followers pull to replicate.
- ISR = followers fully caught up; acks=all waits for the ISR, not every replica.
- min.insync.replicas=2 with replication.factor=3 tolerates one node down while staying writable.
- unclean.leader.election=true lets a stale replica become leader — availability over consistency, keep false when durability matters.
The classic sizing for durability: replication.factor=3, min.insync.replicas=2, acks=all, unclean=false — you survive one broker failure with zero data loss.
分布式追加日志
Kafka 不是「取走即删」的队列,而是分区、多副本的追加日志。生产者追加,消费者按各自偏移量读取,数据按保留期存在,与是否被消费无关。这种设计解耦了生产与消费,使它成为事件流、日志聚合、CDC 管道的骨干。
Topic: orders(逻辑频道)
├─ Partition 0 [m0][m1][m2][m3]... ← 不可变序列,offset 单调递增
├─ Partition 1 [m0][m1]...
└─ Partition 2 [m0][m1][m2]...
每条消息只落一个分区;分区是并行度的单位
消息 = topic + partition + offset(全局唯一定位)
顺序只在分区内保证;按 key 分区可保证同 key 有序
生产者
# 命令行快速体验
kafka-topics --bootstrap-server localhost:9092 \
--create --topic orders --partitions 3 --replication-factor 3
kafka-console-producer --bootstrap-server localhost:9092 \
--topic orders
kafka-console-consumer --bootstrap-server localhost:9092 \
--topic orders --from-beginning --group demo
# Java 客户端骨架
# Properties p = new Properties();
# p.put("bootstrap.servers", "k1:9092,k2:9092");
# p.put("key.serializer", StringSerializer.class.getName());
# p.put("value.serializer", StringSerializer.class.getName());
# KafkaProducer<String, String> producer = new KafkaProducer<>(p);
# producer.send(new ProducerRecord<>("orders", userId, json));
acks、重试与幂等
# 投递可靠性三档
acks=0 发出去就不管(可能丢)
acks=1 Leader 写入即成功(Leader 挂了可能丢)
acks=all ISR 全部持久化(默认,最稳)
# 重试与幂等(生产者侧防重复)
enable.idempotence=true # 幂等生产者( PID + 序列号,单分区去重)
max.in.flight.requests.per.connection=5
retries=2147483647 # 无限重试
# 事务(跨分区精确一次)
transactional.id=order-tx # 两阶段提交到事务日志
# begin -> sendOffsets -> commit;consumers 需 isolation.level=read_committed
# 消息有序性:同一 key 的消息进同一分区即有序
# 幂等 + 限制 inflight 5 之内可保证同分区不乱序
| 语义 | 配置组合 | 成本 |
|---|---|---|
| At most once(最多一次) | acks=0 或不重试 | 可能丢,不重复 |
| At least once(至少一次) | acks=all + retries | 不丢,可能重复(默认) |
| Exactly once(精确一次) | 幂等 + 事务 + read_committed | 最强,吞吐下降 |
消费组与再均衡
消费组 demo(3 个消费者实例)订阅 orders(3 个分区):
消费者 A ← partition 0
消费者 B ← partition 1
消费者 C ← partition 2
分区分配策略:range / roundrobin / sticky(防抖动首选)
再均衡(Rebalance):成员变更时重新分配分区
触发:消费者上下线、订阅变化、分区数变化
代价:STW(消费全部暂停)—— 是稳定性头号敌人
__consumer_offsets:消费组提交偏移量的内部主题
enable.auto.commit=true(默认,可能重复消费)
手动提交:处理完业务再 commitSync() 更安全
Rebalance 优化:
session.timeout.ms / heartbeat 间隔调合理
max.poll.interval.ms 按处理耗时上调
lengthy 启动用 CooperativeRebalanceProtocol
副本与 ISR
- 每个分区一个 Leader 与 N-1 个 Follower;读写都走 Leader,Follower 主动拉取复制。
- ISR = 完全同步的副本集合;acks=all 等的是 ISR,不是全部副本。
- min.insync.replicas=2 加 replication.factor=3:可容忍一台宕机且仍可写。
- unclean.leader.election=true 会让落后副本当 Leader——可用性优先牺牲一致性,关键数据保持 false。
经典耐用配方:replication.factor=3 + min.insync.replicas=2 + acks=all + unclean=false——一台 broker 宕机也零丢失。