订阅更新

一个项目该建几个Topic?——Topic设计与Kafka集群运维实战

Kafka手册 第 10 题 约 8 分钟读完

本文目录
  1. 先说结论
  2. Topic命名规范
  3. 怎么决定Topic数量?——按业务域拆分
  4. Partition数、副本数、保留时间怎么定?
  5. 我在两家公司的Topic设计对比
  6. Kafka集群运维要点
  7. 实战踩坑:大Topic拆分
  8. 面试高频追问
  9. 总结

先说结论

Topic设计遵循'按业务域拆分'原则:不同业务含义的数据放不同Topic,不要为了省事把所有数据塞一个Topic。Partition数、副本数、保留时间要根据业务特点单独配置。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

Topic设计看起来简单,但设计不好会带来一堆运维问题。在某元宇宙社交公司,我一开始把所有埋点数据都塞进一个user_event Topic,后来发现不同类型的事件消费速度差异巨大,快的拖着慢的,Lag居高不下。后来拆分成多个Topic才解决。这道题面试官想看的是你有没有Topic设计的全局思维和运维经验。

Topic命名规范

好的命名规范让运维变得轻松。我在两家公司都用过类似的命名方式:

# Topic命名规范:{业务域}.{数据类型}.{数据层级}
#
# 示例(某元宇宙社交公司):
# app.user_event.raw        ← 原始用户行为埋点
# app.gift_transaction.raw  ← 原始礼物交易数据
# app.user_profile.cdc      ← MySQL用户表CDC同步
# app.user_event.cleaned    ← 清洗后的事件数据
#
# 示例(某短剧出海公司):
# ad.attribution.raw        ← 广告归因原始数据
# ad.spend.raw              ← 广告消耗数据
# content.play_event.raw    ← 播放行为事件
#
# 好处:
# ① 一看名字就知道是什么数据
# ② 按前缀可以批量管理(比如查看所有ad.开头的Topic)
# ③ 不同层级的数据(raw/cleaned/aggregated)一目了然

怎么决定Topic数量?——按业务域拆分

Topic拆分的核心原则:不同消费速度、不同保留策略、不同可靠性要求的数据,应该放不同Topic。

拆分维度示例为什么要拆
业务域不同用户行为 vs 交易流水消费逻辑不同,不该耦合
消费速度不同高频点击 vs 低频注册快的和慢的混在一起会互相拖累
可靠性不同埋点(acks=1) vs 交易(acks=all)不同Topic配不同acks和副本数
保留时间不同日志(3天) vs 交易(30天)不同Topic设不同retention
数据格式不同JSON埋点 vs Avro CDC序列化方式不同,混合会出问题

Partition数、副本数、保留时间怎么定?

这三个参数是每个Topic必须设计的:

# 创建Topic时的参数配置
kafka-topics.sh --bootstrap-server broker1:9092 \
    --create --topic app.gift_transaction.raw \
    --partitions 6 \
    --replication-factor 3 \
    --config retention.ms=604800000 \
    --config min.insync.replicas=2
 
# Partition数决策:
# 公式:max(预期吞吐/单Partition吞吐, 下游Consumer并行度)
# 经验值:中流量 6-12,高流量 20-50
# 宁可多设不要少设(只能加不能减)
 
# 副本数决策:
# 生产环境一律3副本(除非Broker<3个)
# 测试环境可以1-2副本
 
# 保留时间:根据业务需求
# 日志/埋点:3-7天     交易:7-30天    CDC:3天(有MySQL兜底)

我在两家公司的Topic设计对比

TopicPartition副本保留acks公司
user_event637天1元宇宙社交
gift_txn6330天all元宇宙社交
user_sync(CDC)333天all元宇宙社交
ad.attribution12314天all短剧出海
content.play_event1237天1短剧出海

注意几个设计细节:CDC Topic保留时间可以短一些(3天),因为MySQL本身是完整数据源,Kafka只是中间管道。广告归因的Partition设了12个,因为投放数据量大且要求5分钟时效,需要更高的并行度。

Kafka集群运维要点

① 磁盘监控是第一优先级

Kafka的数据全在磁盘上,磁盘满了整个Broker就废了。我在元宇宙社交公司设的报警阈值是80%告警、90%严重,每周清理一次过期数据。

② Topic的Partition数不要轻易改

Partition只能增加不能减少。增加后按Key分区的数据会被打散,下游Consumer需要重新分配。非必要不改,一开始就多给点余量。

③ 用工具管理,别裸操作

# 常用运维命令
 
# 查看Topic列表
kafka-topics.sh --bootstrap-server broker1:9092 --list
 
# 查看Topic详情(Partition分布、ISR状态)
kafka-topics.sh --bootstrap-server broker1:9092 --describe --topic gift_txn
 
# 查看Consumer Lag
kafka-consumer-groups.sh --bootstrap-server broker1:9092 \
    --describe --group flink-gift-etl
 
# 修改Topic配置(比如调整保留时间)
kafka-configs.sh --bootstrap-server broker1:9092 \
    --alter --entity-type topics --entity-name gift_txn \
    --add-config retention.ms=2592000000  # 改为30天

在元宇宙社交公司我用Know Streaming做可视化管理,在短剧出海公司用云厂商的控制台。生产环境一定要有可视化工具,用命令行排查效率太低了。

实战踩坑:大Topic拆分

早期在元宇宙社交公司,我把所有用户行为事件都放在一个user_event Topic里:点击、浏览、在线时长、虚拟空间操作全部混在一起。后来发现问题:

问题一:虚拟空间操作的事件处理逻辑复杂,Flink处理很慢。但它和点击事件混在同一个Topic,导致简单的点击事件也被拖慢了。

问题二:实时大盘只需要点击和浏览事件,但不得不消费全部事件再过滤。浪费了大量计算资源。

解决方案:把user_event拆成三个Topic:user_click(点击/浏览)、user_session(在线时长)、user_space(虚拟空间操作)。不同Topic配不同的Flink Job和Partition数,各自独立扩缩容。拆分后实时大盘的消费延迟从秒级降到毫秒级,Flink资源占用也减少了30%。

面试高频追问

追问一:Topic太多会有什么问题?

Topic太多(1000+)会导致:① 每个Topic的Partition都有一组文件,文件数暴增导致磁盘随机IO增加;② ZooKeeper存储的元数据增多,Controller选举和Rebalance变慢。一般几十到上百个Topic没问题,超过1000个要考虑拆集群。

追问二:怎么做Topic的容量规划?

核心公式:磁盘需求 = 日均消息量 x 单条消息大小 x 副本数 x 保留天数。比如日均1亿条 x 1KB x 3副本 x 7天 = 约2.1TB。留30%余量就是2.7TB。按这个算需要多少Broker和多大磁盘。

总结

Topic设计面试答三个层面:① 命名规范(业务域.数据类型.层级);② 拆分原则(按业务域、消费速度、可靠性要求拆分);③ 参数配置(Partition数按吞吐定、副本一律3个、保留时间按业务需求定)。能讲出'大Topic拆分'的实战经历和效果对比,面试官会觉得你有架构设计和运维优化的意识,不是只会写代码。

下一篇聊Kafka的消息格式选择:JSON、Avro、Protobuf该用哪个?Schema管理怎么做?

你们的Kafka Topic是怎么命名和管理的?有多少个Topic?评论区聊聊~

关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长

刷题进度保存在当前浏览器