Topic
定义与作用
Topic 是 Kafka 中消息的逻辑分类单元。它是一类消息的命名空间——生产者将消息发送到特定 Topic,消费者从特定 Topic 订阅消息。Topic 之于 Kafka,如同"表"之于关系数据库:"订单"消息发到 orders Topic,"用户行为"消息发到 user-events Topic。
在分布式系统中,Topic 解决了消息路由与隔离的问题:不同业务的消息流互不干扰,各自拥有独立的吞吐能力与保留策略。
核心原理
Topic 的逻辑模型
Topic 本身不存储数据,只是给 Partition 集合一个名字。创建 Topic 时指定分区数(Partition Count)和副本因子(Replication Factor),这两个参数决定了 Topic 的并行度和可靠性。
Topic 的三大核心属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
partitions | int | 1(或 num.partitions) | 分区数,决定并行度 |
replication.factor | short | 1(或 default.replication.factor) | 副本数,决定可靠性 |
retention.ms | long | 604800000(7天) | 消息保留时长,超时删除 |
Topic 的内部命名空间
Kafka 内部使用两类 Topic,以双下划线 __ 开头,普通用户不应直接操作:
| 内部 Topic | 用途 | 关键特性 |
|---|---|---|
__consumer_offsets | 存储 Consumer Group 的 Offset 提交记录 | Compacted Topic(Key 级保留) |
__transaction_state | 存储事务状态(Producer Transaction) | 内部使用 |
__cluster_metadata | KRaft 模式下存储集群元数据 | 单分区,不可删除 |
完整示例
示例一:多 Topic 隔离业务消息流
场景:电商平台同时运行"订单处理"和"用户行为分析"两条数据管道,需要隔离。
操作前环境:Kafka 空集群,无自定义 Topic。
步骤:
# 1. 创建订单 Topic(大吞吐,需要较多分区)
bin/kafka-topics.sh --create \
--topic orders \
--partitions 10 \
--replication-factor 3 \
--bootstrap-server localhost:9092
# 2. 创建用户行为 Topic(高吞吐,保留期更长)
bin/kafka-topics.sh --create \
--topic user-events \
--partitions 20 \
--replication-factor 2 \
--config retention.ms=1209600000 \
--bootstrap-server localhost:9092
# 3. 创建低延迟告警 Topic(少量分区,短保留)
bin/kafka-topics.sh --create \
--topic alerts \
--partitions 3 \
--replication-factor 3 \
--config retention.ms=86400000 \
--bootstrap-server localhost:9092
# 4. 验证
bin/kafka-topics.sh --list --bootstrap-server localhost:9092
# alerts
# orders
# user-events
操作后对比:
| Topic | 分区数 | 副本数 | 保留期 | 适用场景 |
|---|---|---|---|---|
orders | 10 | 3 | 7天(默认) | 订单流水 |
user-events | 20 | 2 | 14天 | 用户行为日志 |
alerts | 3 | 3 | 1天 | 系统告警 |
示例二:读取 Topic 配置并对比
场景:确认生产环境 Topic 的配置是否符合预期。
步骤:
# 查看默认 Topic 配置
bin/kafka-configs.sh --bootstrap-server localhost:9092 \
--entity-type topics --entity-default --describe
# 输出默认配置:retention.ms=604800000, min.insync.replicas=1, ...
# 查看特定 Topic 的覆盖配置
bin/kafka-configs.sh --bootstrap-server localhost:9092 \
--entity-type topics --entity-name user-events --describe
# Dynamic configs for topic user-events are:
# retention.ms=1209600000 sensitive=false ...
# 动态修改 Topic 配置(覆盖默认值)
bin/kafka-configs.sh --bootstrap-server localhost:9092 \
--entity-type topics --entity-name user-events \
--alter --add-config retention.ms=2592000000
# Completed updating config for topic user-events.
# 删除 Topic 级别覆盖配置(回退到默认值)
bin/kafka-configs.sh --bootstrap-server localhost:9092 \
--entity-type topics --entity-name user-events \
--alter --delete-config retention.ms
# Completed updating config for topic user-events.
操作前后对比:
| 时间点 | user-events 的 retention.ms |
|---|---|
| 创建时 | 1,209,600,000(14天,显式指定) |
--alter 后 | 2,592,000,000(30天) |
--delete-config 后 | 604,800,000(7天,回退默认值) |
Topic 命名规范与最佳实践
| 原则 | 说明 | 好例子 | 坏例子 |
|---|---|---|---|
| 使用有意义的前缀 | 反映业务域 | order.created, user.login | topic1, test |
| 使用点号分隔 | 层次化命名 | payment.success | paymentSuccess |
| 避免特殊字符 | 仅用字母、数字、.、-、_ | prod.orders.v1 | order$%^ |
| 包含环境标识 | 区分生产/测试 | prod.order.created | order_created(不知环境) |
易错场景
易错 1:分区数规划过小
场景:某 Topic 预计最大吞吐 100 MB/s,但只创建了 3 个分区,每分区最大吞吐约 20 MB/s。
后果:消费者无法通过增加实例扩容(3 个分区 = 最多 3 个消费者并行),系统成为瓶颈。
教训:创建 Topic 时根据预期吞吐量和消费者并行度合理设置分区数。公式:partitions >= max(预期吞吐 / 单分区吞吐上限, 最大消费者实例数)。
易错 2:误操作内部 Topic
场景:发现 __consumer_offsets 占用空间大,想删除。
后果:所有 Consumer Group 的 Offset 丢失,消费者重启后全部从头消费——造成大量重复数据。
教训:永远不要手动操作 __ 开头的内部 Topic。
面试高频考点
Q:创建 Topic 时如何确定分区数?
A:综合考虑三个因素:
- 预期吞吐量:假设单分区可达 20 MB/s 写入(保守估计),所需分区数 = 预期总吞吐 / 20
- 消费者并行度:一个分区只能被消费组内一个消费者消费,分区数 >= 最大消费者实例数
- 集群规模:分区越多,Controller 压力越大,文件句柄、内存开销越大。单 Broker 建议不超过 4000 个分区(Kafka 3.x 在 KRaft 模式下上限更高)
经验建议:先按吞吐和并行度的最大值设置,再根据实际运行情况和集群负载调整(只能增加,不能减少)。