一个项目该建几个Topic?——Topic设计与Kafka集群运维实战
本文目录
先说结论
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设计对比
| Topic | Partition | 副本 | 保留 | acks | 公司 |
|---|---|---|---|---|---|
| user_event | 6 | 3 | 7天 | 1 | 元宇宙社交 |
| gift_txn | 6 | 3 | 30天 | all | 元宇宙社交 |
| user_sync(CDC) | 3 | 3 | 3天 | all | 元宇宙社交 |
| ad.attribution | 12 | 3 | 14天 | all | 短剧出海 |
| content.play_event | 12 | 3 | 7天 | 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年大数据老兵,聊技术、聊职场、聊成长