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: order-events Partition 0 Leader: Broker 1 Replicas: [1, 2, 3] Partition 1 Leader: Broker 2 Replicas: [2, 3, 1] Partition 2 Leader: Broker 3 Replicas: [3, 1, 2] Partition 0 的 Segment 文件 00000000000000000000.log 偏移量: 0 ~ 999 00000000000000001000.log 偏移量: 1000 ~ 1999 00000000000000002000.log 偏移量: 2000 ~ 2999

这张图展示了:一个Topic包含多个Partition,每个Partition又包含多个Segment文件。消息就存储在Segment的.log文件里。

2.6 总结:记住这几点

  • Topic是逻辑概念,用于消息分类
  • Partition是物理分片,真正存储数据
  • 分区数决定并行度,但不要盲目设大
  • 分区策略影响消息分布,金融场景多用哈希保证顺序
  • Segment是存储最小单位,理解它有助于调优

嗯,这一章就到这里。分区是Kafka并行度的基础,理解透了,后面讲生产者和消费者的时候,你就能明白为什么Kafka能扛住金融系统那么大的流量了。


专注资料整理