未记录事实核验 · 状态:维护中
记录仅说明核验时间与维护状态,不保证适用于所有环境;使用前请留意正文中的版本、适用条件与风险提示。
warning 适用边界与维护说明
本文适合用于 Topic 命名、容量估算、副本配置和扩容方案讨论;本次仅作全文结构审阅,未进行外部事实核验或命令实测。吞吐量与分区数量已明确为示例或待验证的规划假设,不应视为生产容量保证,场景分区数建议也需结合目标环境压测使用。配置默认值应以实际 Kafka 版本及集群配置为准,3 副本练习需至少 3 个 Broker。分区键一节的“保证处理顺序”应限定为分区数及路由规则稳定时的分区日志顺序,业务处理顺序仍取决于生产和消费方式;保留时长也不意味着单条消息到期即刻删除,compact 示例不宜理解为完整历史或所有最新状态的永久存档。 已取消无法确定目标的可点击引用「13-集群管理与运维」,保留原提及;Ambiguous link target: 13-集群管理与运维
主题与分区设计 - 像规划城市交通一样设计Topic
info 前置知识
- 消费者深入剖析 - 理解消费者组和分区分配关系
- 第一个 Kafka 程序 - 了解 Producer/Consumer 基本用法
- Kafka 核心术语 - 掌握 Topic、Partition、Replica 的概念
Topic 和分区的设计是 Kafka 集群中最需要事先规划的决策,因为分区数只能增加不能减少,而错误的设计会在流量增长后引发难以修复的问题。本文提供可落地的计算方法和选型原则,不讲废话。
Topic 命名规范
好的命名规范有助于降低运维中的识别和沟通成本。推荐格式:
{环境}.{业务域}.{实体}-{动词/事件}
命名示例:
# 生产环境,电商域,订单创建事件
prod.ecommerce.order-created
# 测试环境,用户域,用户行为日志
test.user.behavior-log
# 支付域,交易成功事件
prod.payment.transaction-success
# DWD 层数仓 Topic(数据仓库管道常见用法)
dwd.user.profile-snapshot
# 死信队列(处理失败的消息)
prod.ecommerce.order-created.dlq
tip 命名规则清单
- 只使用小写字母、数字、连字符(
-)和点(.),避免下划线(下划线在某些监控工具中显示异常) - 包含环境前缀(
prod/test/dev),防止生产和测试消息混流 - 用动词或事件描述(
order-created),而非名词堆叠(order-data) - 避免
topic、kafka、data等无意义词汇 - 死信队列统一加
.dlq后缀
查看 Topic 信息的常用命令:
# 列出集群中所有 Topic
kafka-topics.sh --list \
--bootstrap-server localhost:9092
# 查看某个 Topic 的分区分布和副本状态
kafka-topics.sh --describe \
--topic prod.ecommerce.order-created \
--bootstrap-server localhost:9092
# 查看 Topic 的覆盖配置(非默认值才会显示)
kafka-configs.sh --describe \
--entity-type topics \
--entity-name prod.ecommerce.order-created \
--bootstrap-server localhost:9092
分区数规划
为什么分区数很重要
分区是 Kafka 并行处理的基本单位:
- 一个分区同一时刻只能被消费者组内的一个消费者消费
- 消费者的最大并行度 = 分区数
- 分区数决定了 Producer 端的写入并行度(通过 Key 分区)
生活类比:把分区想象成高速公路的车道。车道越多,同时通行的车辆越多(吞吐量越高)。但车道也不是越多越好——车道太多而车辆少,会浪费基础设施,而且增加了 Broker 管理的开销(每个分区在 Broker 上对应一组文件)。
分区数计算公式
基于吞吐量的计算方式:
目标分区数 = ceil(max(
目标生产吞吐量 / 单分区生产吞吐量,
目标消费吞吐量 / 单分区消费吞吐量
))
容量计算的示例假设值(假设使用 SSD、100 字节消息、无压缩;下列数值不代表已提供依据的实测结果):
| 指标 | 参考值 |
|---|---|
| 单分区写入吞吐 | ~10 MB/s |
| 单分区消费吞吐 | ~50 MB/s(示例假设值;zero-copy 可降低部分传输开销,但不保证消费吞吐高于写入吞吐) |
计算示例:
某电商订单 Topic,峰值生产速率 100 MB/s,消费速率需匹配生产:
生产侧需要:100 MB/s ÷ 10 MB/s = 10 个分区
消费侧需要:100 MB/s ÷ 50 MB/s = 2 个分区(消费能力足够)
→ 基础分区数 = 10,再增加 30% 容量余量 → 至少设置 13 个分区,也可按部署需求选择 15 个分区
warning 分区数的上限问题
分区数不是越多越好。每个分区在 Controller 节点和每个 Broker 上都有元数据开销。可把单个 Broker 4000 个分区副本、整个集群 200,000 个分区作为待验证的规划假设,而非通用上限;适用范围取决于 Kafka 版本、控制器模式、硬件及负载。分区增多可能增加 Broker 重启和 Leader 选举的开销,应通过目标环境测试确定容量边界。
不同场景的分区数建议
| 场景 | 建议分区数 | 理由 |
|---|---|---|
| 日志收集(低 QPS,顺序不重要) | 3~6 | 默认值,管理简单 |
| 业务事件流(中等吞吐,需要顺序) | 12~24 | 按峰值 QPS 计算,留余量 |
| 大数据管道(高吞吐,TB 级) | 48~96 | 对齐下游 Spark/Flink 任务并行度 |
| 需要全局有序的场景 | 1 | 单分区提供统一的日志写入顺序;业务事件顺序仍需生产和消费处理配合 |
分区扩容注意事项
warning 扩容会打乱 Key 的分区映射
Kafka 支持增加分区数,但不支持减少。更重要的是:增加分区后,相同 Key 的消息可能被路由到不同的分区(因为 hash(key) % partition_count 的结果变了)。这会破坏"相同 Key 的消息保证顺序"的语义。
扩容前必须确认:消费者是否依赖同 Key 消息的顺序?如果是,扩容需要配合消费者的状态迁移方案。
# 将 hello-kafka 的分区数从 3 扩容到 6
kafka-topics.sh --alter \
--topic hello-kafka \
--partitions 6 \
--bootstrap-server localhost:9092
# 扩容后验证
kafka-topics.sh --describe \
--topic hello-kafka \
--bootstrap-server localhost:9092
副本因子选择
副本(Replica)是分区的完整拷贝,分布在不同 Broker 上。副本因子决定了数据冗余度和容灾能力。
选择原则
| 副本因子 | 适用场景 | 说明 |
|---|---|---|
| 1 | 开发/测试环境 | 无冗余,Broker 故障可能导致不可用,存储损坏时可能丢数据;不适合要求高可用和数据冗余的生产场景 |
| 2 | 对成本极度敏感,可容忍单点故障丢数据 | 单个副本故障后是否可继续写入取决于 ISR 状态、min.insync.replicas 和 acks;仅凭副本因子不能判断是否丢数据 |
| 3 | 生产环境标准配置 | 在 acks=all、min.insync.replicas=2 且剩余副本保持同步等条件下,可容忍 1 个副本所在 Broker 故障,兼顾成本和可靠性 |
| 5 | 金融、支付等强可靠性场景 | 在 acks=all、min.insync.replicas 不大于 3 且剩余副本保持同步等条件下,可容忍 2 个副本所在 Broker 同时故障,存储成本高 |
note 副本因子不能超过 Broker 数量
副本因子 ≤ 集群 Broker 数量。3 节点集群最多设 3 副本。新建 Topic 时,如果副本因子超过 Broker 数,命令会报错。
与 min.insync.replicas 的配合
副本因子单独配置意义有限,需要与 min.insync.replicas(最小同步副本数)配合:
| 副本因子 | min.insync.replicas | 含义 |
|---|---|---|
| 3 | 1 | acks=all 时允许 ISR 最少仅有 Leader,但仍等待当前 ISR 中所有副本确认;ISR 缩至 1 时仅有单副本保障 |
| 3 | 2 | acks=all 时要求 ISR 至少有 2 个副本,并等待当前 ISR 中所有副本确认 |
| 3 | 3 | acks=all 时要求 ISR 有 3 个副本,并等待全部 ISR 副本确认;ISR 少于 3 时拒绝写入 |
生产推荐组合:副本因子 3 + min.insync.replicas=2 + acks=all
这个组合要求 ISR 至少有 2 个副本,并等待当前 ISR 中所有副本确认;单个副本所在 Broker 故障后,若剩余 ISR 仍满足要求且完成必要的选主,该分区可继续写入。
Topic 关键配置参数
Topic 级别的配置会覆盖 Broker 的全局默认值,可以针对每个 Topic 单独调整:
# 创建 Topic 时指定配置
kafka-topics.sh --create \
--topic prod.ecommerce.order-created \
--partitions 12 \
--replication-factor 3 \
--config retention.ms=604800000 \
--config compression.type=lz4 \
--config min.insync.replicas=2 \
--bootstrap-server localhost:9092
# 对已有 Topic 修改配置(在线生效,无需重启)
kafka-configs.sh --alter \
--entity-type topics \
--entity-name prod.ecommerce.order-created \
--add-config retention.ms=259200000 \
--bootstrap-server localhost:9092
# 删除某项 Topic 配置(恢复为 Broker 默认值)
kafka-configs.sh --alter \
--entity-type topics \
--entity-name prod.ecommerce.order-created \
--delete-config compression.type \
--bootstrap-server localhost:9092
核心配置参数说明
数据保留相关:
| 参数 | 默认值 | 说明 |
|---|---|---|
retention.ms |
604800000(7 天) |
消息保留时长(毫秒),超过后被删除 |
retention.bytes |
-1(不限制) |
分区最大字节数,超过后从最早消息开始删除 |
cleanup.policy |
delete |
数据清理策略:delete(按时间/大小删除)或 compact(按 Key 保留最新值) |
segment.bytes |
1073741824(1GB) |
单个日志段文件的大小,达到上限时滚动新文件 |
segment.ms |
604800000(7 天) |
强制滚动日志段的时间间隔(即使未达到大小上限) |
性能相关:
| 参数 | 默认值 | 说明 |
|---|---|---|
compression.type |
producer(保持生产者压缩) |
Broker 端压缩算法:gzip/snappy/lz4/zstd/uncompressed |
message.timestamp.type |
CreateTime |
消息时间戳来源:CreateTime(生产者时间)或 LogAppendTime(Broker 写入时间) |
max.message.bytes |
1048588(~1MB) |
Broker 接受的最大记录批次大小;启用压缩时按压缩后的批次大小判断 |
可靠性相关:
| 参数 | 默认值 | 说明 |
|---|---|---|
min.insync.replicas |
1 |
acks=all 时,至少需要多少副本在 ISR 中 |
unclean.leader.election.enable |
false |
是否允许非 ISR 副本参选 Leader(允许则可能丢数据,禁止则可能短暂不可用) |
典型场景配置示例
场景 1:业务事件流(高可靠,7 天保留)
retention.ms=604800000
compression.type=lz4
min.insync.replicas=2
unclean.leader.election.enable=false
场景 2:日志采集(大量写入,只保留 1 天)
retention.ms=86400000
retention.bytes=10737418240
compression.type=gzip
segment.bytes=268435456
场景 3:数据库变更日志(CDC,按 Key 压缩,永久保留最新状态)
cleanup.policy=compact
compression.type=snappy
min.insync.replicas=2
分区键的选择
分区键(Message Key)决定消息路由到哪个分区。默认策略是 hash(key) % partitionCount。
选择原则:
- 需要保证顺序:用能代表"处理单元"的字段作为 Key。订单系统用
orderId,用户行为用userId,这样同一订单/用户的所有消息进入同一分区,保证处理顺序。 - 不需要保证顺序:可以不设 Key(实际路由策略取决于客户端版本和分区器配置,不一定逐条轮询),或用随机值,让消息均匀分布在所有分区,最大化吞吐量。
- 避免热点 Key:如果某个 Key 对应的消息量远超其他 Key(比如用超级用户的 ID 作为 Key),会导致某个分区消息堆积而其他分区空闲,出现"数据倾斜"。此时可以给热点 Key 加随机后缀(
userId + "_" + random(0,10)),将其分散到多个分区,代价是牺牲该 Key 的顺序保证。
掌握检查
- [ ] 能够按吞吐量需求计算合理的分区数,并知道为什么不能无限增加
- [ ] 理解副本因子与
min.insync.replicas的关系,能解释"3 副本 + minISR=2"的含义 - [ ] 掌握
retention.ms、cleanup.policy、compression.type三个核心配置的使用场景 - [ ] 知道分区扩容的限制(不可减少、Key 路由变化),能解释扩容前需要确认什么
- [ ] 能够根据业务场景选择合适的分区键,并识别数据倾斜风险
实践练习
基础题:在本地集群创建一个 Topic test.order-events,要求:6 个分区,3 副本,消息保留 3 天,启用 lz4 压缩,min.insync.replicas=2。写出完整的 kafka-topics.sh 命令。
进阶题:假设一个用户行为 Topic 目前有 6 个分区,你需要将其扩容到 12 个分区。请描述:扩容之前需要与下游消费者团队确认哪些事情?扩容后消费者需要做哪些调整?
前置知识:消费者深入剖析 下一步学习:副本机制与一致性 - 深入理解 ISR、HW、LEO 等副本同步机制 相关文档:偏移量管理 | 性能调优实战 | 集群管理与运维