2. Topic与Partition核心概念:逻辑队列与物理分片,分区是并行度的基础
好,咱们今天聊聊Kafka里最基础、也最核心的两个概念——Topic和Partition。
说实话,我刚开始接触Kafka的时候,觉得Topic不就是个“主题”嘛,跟消息队列里的队列差不多。但后来在金融系统里踩了几个坑,才真正理解它俩的区别。嗯,咱们今天就把这事彻底说透。
2.1 Topic:逻辑上的消息分类
Topic,说白了就是一个逻辑上的消息容器。你往Kafka里发消息,必须指定一个Topic。消费者要读消息,也得订阅这个Topic。
举个例子,在金融系统里,我经常这样划分Topic:
- order-events:订单事件,比如下单、撤单、成交
- trade-settlements:交易结算数据
- market-data:行情数据,比如股票价格、期货报价
每个Topic代表一类业务数据。消费者按需订阅,互不干扰。
核心要点:Topic是逻辑概念,它不负责存储数据,只负责分类。真正干活的是Partition。
2.2 Partition:物理上的数据分片
Partition才是Kafka真正存储数据的地方。每个Topic可以分成多个Partition,每个Partition就是一个有序的、不可变的日志文件。
我个人的习惯是,把Partition想象成一个“大文件”,消息一条接一条地追加到文件末尾。每条消息都有一个唯一的偏移量(offset),消费者通过偏移量来定位消息。
为什么要有Partition?说白了就是为了并行。
你想想看,如果一个Topic只有一个Partition,那所有消息都写到一个文件里,写入速度受限于单台机器的磁盘IO。消费者也只能有一个线程去读,读的速度也上不去。
但如果你把Topic分成多个Partition,每个Partition可以放在不同的机器上,写入和读取都可以并行进行。这就是Kafka高吞吐量的核心秘密。
我的经验:我在做金融行情系统时,把market-data Topic分了64个Partition,部署在8台机器上。单机写入速度从2万条/秒提升到了16万条/秒。这就是分区的威力。
2.3 分区与并行度的关系
分区数直接决定了并行度。这个关系很简单:
- 生产者并行度:可以同时往多个Partition写数据,分区越多,写入并行度越高
- 消费者并行度:一个消费者组里,每个消费者可以负责一个或多个Partition。分区数越多,可以同时消费的消费者就越多
但这里有个坑——分区数不是越多越好。
我曾经在一个项目里,把Topic分了200个Partition,结果发现:
- 元数据同步开销变大
- 文件句柄占用过多
- Leader选举时间变长
所以,分区数要合理设置。我一般建议:
| 场景 | 建议分区数 | 说明 |
|---|---|---|
| 日志收集(低吞吐) | 3-6 | 数据量不大,分区多了浪费 |
| 金融交易(中等吞吐) | 12-24 | 需要一定的并行度,但不要过度 |
| 行情数据(高吞吐) | 32-64 | 数据量大,需要高并行度 |
| 物联网(超高吞吐) | 64-128 | 设备多,数据量大,但注意集群规模 |
避坑指南:我曾经把一个Topic的分区数从8改成64,结果导致消费者rebalance花了5分钟,期间所有消费都停了。所以,分区数最好在创建Topic时就定好,后期修改成本很高。
2.4 分区策略:消息该去哪个Partition?
生产者发消息时,Kafka需要决定这条消息放到哪个Partition里。这个决策过程就叫分区策略。
Kafka默认提供了几种策略:
- 轮询策略(Round Robin):消息均匀分布到所有Partition。适合没有key的场景
- 哈希策略(Hash):根据消息的key计算哈希值,相同key的消息总是进入同一个Partition。适合需要保证顺序的场景
- 自定义策略:你可以自己写代码决定消息去哪个Partition
在金融系统里,我几乎只用哈希策略。为什么?因为订单数据需要保证顺序。
举个例子,一个订单的“创建”、“支付”、“发货”三条消息,如果分散到不同Partition,消费者可能先看到“发货”再看到“创建”,这就乱套了。
所以,我会用订单ID作为key,这样同一个订单的所有消息都进入同一个Partition,消费者就能按顺序处理了。
// 生产者示例:使用订单ID作为key
ProducerRecord<String, String> record =
new ProducerRecord<>("order-events", orderId, orderJson);
producer.send(record);
小技巧:如果你不需要保证顺序,用轮询策略就行,吞吐量更高。我一般在日志收集场景用轮询,在交易场景用哈希。
2.5 物理存储:Partition在磁盘上长什么样?
咱们来看看Partition在磁盘上到底是怎么存的。这有助于你理解Kafka的性能特性。
每个Partition对应一个目录,目录名是 topic名称-分区编号。比如:
/data/kafka/order-events-0/
/data/kafka/order-events-1/
/data/kafka/order-events-2/
每个目录里包含多个Segment文件。Segment是Kafka存储的最小单位,默认1GB或1周滚动一次。每个Segment包含:
- .log文件:存储消息数据
- .index文件:偏移量索引,用于快速定位消息
- .timeindex文件:时间戳索引,用于按时间查找消息
我画了一张图,帮你理解Topic、Partition、Segment之间的关系:
这张图展示了:一个Topic包含多个Partition,每个Partition又包含多个Segment文件。消息就存储在Segment的.log文件里。
2.6 总结:记住这几点
- Topic是逻辑概念,用于消息分类
- Partition是物理分片,真正存储数据
- 分区数决定并行度,但不要盲目设大
- 分区策略影响消息分布,金融场景多用哈希保证顺序
- Segment是存储最小单位,理解它有助于调优
嗯,这一章就到这里。分区是Kafka并行度的基础,理解透了,后面讲生产者和消费者的时候,你就能明白为什么Kafka能扛住金融系统那么大的流量了。