3. Topic 与 Partition:从创建到分区,把消息管道的骨架搭稳
Topic 和 Partition,说白了就是 Kafka 里最核心的两个概念。你建 Topic 就像在数据库里建表,而 Partition 就像是给这张表做了水平分片。我刚开始接触 Kafka 时,总觉得 Partition 越多越好,结果踩了不少坑。今天咱们就把这块彻底聊透。
3.1 Topic 的创建与管理
创建 Topic 的方式有好几种。我个人习惯在测试环境用命令行,生产环境用脚本或自动化工具。先看最直接的方式:
# 创建一个名为 "order-events" 的 Topic,3 个分区,副本因子为 2
bin/kafka-topics.sh --create \
--bootstrap-server localhost:9092 \
--topic order-events \
--partitions 3 \
--replication-factor 2
这里有几个参数你得注意:
- --bootstrap-server:指定集群地址,别只写一个 broker,万一挂了就尴尬了
- --partitions:分区数,决定了你的并行处理能力
- --replication-factor:副本因子,数据冗余的保障
查看 Topic 列表和详情也很简单:
# 列出所有 Topic
bin/kafka-topics.sh --list --bootstrap-server localhost:9092
# 查看某个 Topic 的详细信息
bin/kafka-topics.sh --describe --topic order-events --bootstrap-server localhost:9092
输出结果会告诉你每个 Partition 的 Leader、Replicas 和 ISR 信息。嗯,这里要提醒一句:生产环境不要随意删除 Topic,除非你确认数据已经备份或不再需要。我曾经见过有人手滑删了核心 Topic,恢复起来那叫一个痛苦。
3.2 Partition 分区机制:消息到底怎么分?
Partition 是 Kafka 实现高吞吐的关键。每个 Partition 是一个有序的、不可变的消息序列,新消息追加到尾部。你想想看,如果只有一个 Partition,那所有消费者都得排队读,性能肯定上不去。
消息写入哪个 Partition,由分区策略决定。Kafka 默认提供了几种策略:
| 策略名称 | 说明 | 适用场景 |
|---|---|---|
| RoundRobinPartitioner | 轮询分配,消息均匀分布到各分区 | 无 key 或 key 不重要时 |
| UniformStickyPartitioner | 粘性分区,一批消息尽量发到同一个分区 | 减少网络开销,提升吞吐 |
| 自定义 Partitioner | 根据业务 key 计算分区 | 需要保证相同 key 的消息有序 |
举个例子,如果你处理的是订单数据,希望同一个订单 ID 的所有消息都进入同一个 Partition,那就得用自定义策略:
public class OrderKeyPartitioner implements Partitioner {
@Override
public int partition(String topic, Object key, byte[] keyBytes,
Object value, byte[] valueBytes, Cluster cluster) {
// 根据订单 ID 的哈希值取模
int partitionCount = cluster.partitionCountForTopic(topic);
return Math.abs(key.hashCode()) % partitionCount;
}
}
我在项目中遇到过一个问题:某个 Topic 的 Partition 数设得太少,导致部分 Partition 数据量巨大,而其他 Partition 却很空闲。说白了就是数据倾斜。后来我改用自定义 Partitioner,按业务 ID 哈希,才把负载均衡了。
3.3 副本因子设置:数据安全的第一道防线
副本因子(Replication Factor)决定了每个 Partition 有多少个副本。副本因子为 1 表示没有冗余,Broker 挂了数据就丢了。生产环境我建议至少设为 3。
副本之间是怎么工作的?看这张图就明白了:
副本因子设置时,有几个原则:
- 至少 2,推荐 3:2 个副本虽然能扛单点故障,但万一再坏一个就危险了
- 副本数不能超过 Broker 数:比如你有 3 台 Broker,副本因子设为 4 就创建失败
- 考虑机架感知:如果集群跨机房,尽量让副本分布在不同的机架上
3.4 分区分配策略:副本该放在哪台 Broker?
当你创建 Topic 时,Kafka 需要决定每个 Partition 的 Leader 和 Follower 分别放在哪些 Broker 上。这个过程叫分区分配。Kafka 默认的策略是 RoundRobin,尽量让 Leader 均匀分布。
但默认策略不一定最优。举个例子,如果你有 3 台 Broker,创建 3 个 Partition 且副本因子为 3,默认分配可能让所有 Leader 都挤在同一台机器上。这就失去了负载均衡的意义。
Kafka 提供了几种分配策略:
| 策略 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| 默认 RoundRobin | 按 Broker 列表轮询分配 Leader | 简单,无需额外配置 | 可能 Leader 分布不均 |
| Sticky 分配 | 尽量保持已有分配不变,只调整新增的 | 减少重分配时的数据移动 | 实现复杂 |
| 自定义分配器 | 实现 Admin 接口,按机架或标签分配 | 灵活,适合复杂拓扑 | 需要开发维护 |
我建议你在生产环境使用 Sticky 分配。为什么?因为集群扩容或缩容时,默认策略会大量移动 Partition,造成网络和磁盘 IO 飙升。Sticky 策略会尽量保持现有分配,只移动必要的部分。
配置方式很简单,在 server.properties 里加上:
# 使用 Sticky 分配策略
partition.assignment.strategy=org.apache.kafka.clients.consumer.StickyAssignor
另外,还有一个容易被忽略的参数:leader.rebalance.enable。默认是 true,表示 Kafka 会定期检查 Leader 分布是否均匀,如果不均匀就触发重平衡。我个人习惯在稳定集群中把它设为 false,避免不必要的 Leader 切换。
3.5 实战建议:Topic 设计的最佳实践
聊了这么多理论,最后给几个实战建议:
- 分区数怎么定? 我一般按目标吞吐量来算。假设单个 Partition 能处理 10MB/s,你期望 100MB/s,那就至少 10 个分区。再留 20% 的余量。
- 副本因子设多少? 开发测试用 1,预发用 2,生产至少 3。如果数据极其重要,可以设 4 或 5,但磁盘占用也会翻倍。
- Topic 命名规范:我习惯用
<业务域>-<数据主题>-<环境>的格式,比如order-payment-prod。这样一眼就能看出用途。 - 不要频繁创建删除 Topic:每次操作都会触发元数据变更,影响集群稳定性。
嗯,Topic 和 Partition 这块内容就这些。你只要把分区机制和副本策略搞明白,Kafka 的骨架就算搭稳了。后面咱们再聊消息生产和消费的细节,那才是真正跑起来的时候。