id, title, type, domain, stack, tags, level, prerequisites, est_hours, related, week, order
| id |
title |
type |
domain |
stack |
tags |
level |
prerequisites |
est_hours |
related |
week |
order |
| backend.mq.kafka |
Kafka:主题、分区、消费组、位移和顺序 |
lesson |
backend |
|
| Kafka |
| 分区 |
| 消费组 |
| offset |
| 顺序消息 |
| ISR |
|
intermediate |
|
3 |
| backend.mq.reliability |
| backend.mq.interview |
|
|
2 |
Kafka:主题、分区、消费组、位移和顺序
解释说明
模型:Kafka 是一个分布式的追加日志。消息写入主题(Topic),主题分成多个分区(Partition),每个分区是一个只追加的有序日志,消息有递增的位移(offset)。消息被消费后不会删除,按保留时间或大小清理,所以可以回溯重新消费。
- 生产者:消息带 key 时,同一个 key 总是进入同一个分区(按 key 哈希);没有 key 时分散写入。
- 消费组(Consumer Group):同一个组里,一个分区同一时间只分配给一个消费者;不同组各自独立消费全部消息。所以消费者数量超过分区数时,多出来的消费者会空闲——分区数决定了组内并行度上限。
- 位移提交:消费者记录“处理到哪里了”。先处理再提交 = 至少一次(可能重复);先提交再处理 = 至多一次(可能丢)。业务一般选至少一次 + 幂等消费。
- 副本:每个分区有多个副本,一个 leader 负责读写,follower 同步。和 leader 保持同步的副本集合叫 ISR。
- 生产者 acks:
acks=0 不等确认;acks=1 leader 写入即确认;acks=all ISR 都写入才确认(配合 min.insync.replicas 保证不丢)。
- 顺序:只保证单个分区内有序。需要“同一订单的消息有序”时,用订单 ID 作为 key。
和 RabbitMQ 怎么选
|
RabbitMQ |
Kafka |
| 模型 |
消息被消费确认后删除 |
日志保留,可回溯 |
| 优势 |
路由灵活、延迟 / 死信 / 优先级等功能多、单条消息时延低 |
吞吐量高、可回放、适合流处理 |
| 典型场景 |
业务异步任务、订单流程 |
日志采集、埋点、数据同步、事件流 |
新版本 Kafka 已用 KRaft 取代 ZooKeeper 管理元数据(Kafka 4.0 起移除 ZooKeeper),部署细节以官方文档为准:https://kafka.apache.org/documentation/
案例
- 埋点数据:前端事件写入
events 主题(几十个分区),实时计算和离线入库两个消费组各自消费。
- 订单状态变化事件:用订单 ID 作为 key,保证同一订单的“创建 → 支付 → 发货”按顺序被消费。
- 消费者 bug 导致数据处理错误:修复后把消费组位移重置到出问题前的时间点,重新消费。
代码示例
Python 客户端(confluent-kafka,示意代码,需要运行中的 Kafka;客户端参数以官方文档为准:https://docs.confluent.io/kafka-clients/python/current/overview.html ):
易错点
- 消费者比分区多:多出来的消费者空闲,加机器也提不了速度;要先加分区(分区只能增加不能减少,增加后 key 的分布会变,影响顺序)。
- 自动提交位移:消息还没处理完就提交,崩溃后丢消息;或者处理完还没提交就崩溃,重复消费。业务里建议手动提交 + 幂等。
- 以为整个主题有序:只有分区内有序。
- 单条消息处理太慢:超过
max.poll.interval.ms 会被踢出消费组并触发再均衡,导致重复消费。
acks=1 又要求不丢:leader 宕机且 follower 未同步时会丢;要 acks=all + min.insync.replicas>=2 + 副本数 >=3。
面试常问
见消息队列面试题:Kafka 为什么吞吐高、分区和消费组的关系、怎么保证顺序、怎么不丢消息、和 RabbitMQ 的区别。