简介

Kafka 有主题(Topic)的概念,它是承载真实数据的逻辑容器,而在主题之下还分为若干个分区,也就是说 Kafka 的消息组织方式实际上是三级结构:主题 - 分区 - 消息。主题下的每条消息只会保存在某一个分区中,而不会在多个分区中被保存多份。Kafka官网上的这张图十分详细的展示了这个三级结构:

Kafka 发送指定分区 kafka消息分区_java

常见的分区策略

分区策略是决定生产者将消息发送到哪个分区的算法。Kafka 为我们提供了默认的分区策略,同时也支持自定义分区策略。

轮询策略(Round-robin)

即顺序分配。比如一个主题下有 3 个分区,那么第一条消息被发送到分区 0,第二条被发送到分区 1,第三条被发送到分区 2,以此类推。当生产第 4 条消息时又会重新开始,即将其分配到分区 0,轮询策略总能保证消息最大限度地被平均分配到所有分区上。如下图所示:

Kafka 发送指定分区 kafka消息分区_java_02

随机策略(Randomness)

随机分配,即每次先得到该主题有多少个分区,然后每次随机返回一个小于该分区数的正整数,随机策略也是为了让消息可以尽量分散到各个分区上,但是实际效果可能没有轮询策略来的好,故一般使用的比较少。

按消息键保序策略(Key-ordering)

Kafka 允许为每条消息定义消息键,简称为 Key。这个 Key 的作用非常大,它可以是一个有着明确业务含义的字符串,比如客户代码、部门编号或是业务 ID 等;也可以用来表征消息元数据。一旦消息被定义了 Key,那么你就可以保证同一个 Key 的所有消息都进入到相同的分区里面,由于每个分区下的消息处理都是有顺序的,故这个策略被称为按消息键保序策略。概况来说就是对每个key,随机选择一个分区,这样相同的key值就会到同一个分区内,如下图所示:

Kafka 发送指定分区 kafka消息分区_自定义_03

自定义分区策略

如果要自定义分区策略,你需要显式地配置生产者端的参数partitioner.class。在编写生产者程序时,你可以编写一个具体的类实现org.apache.kafka.clients.producer.Partitioner接口,并实现其中的partition()和close()。其中我们需要将自定义的分区策略算法在partition()中进行实现。以下是partition()接口的入参,也即kafka提供给我们的参数。

int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster);

这里的topic、key、keyBytes、value和valueBytes都属于消息数据,cluster则是集群信息(比如当前 Kafka 集群共有多少主题、多少 Broker 等)。我们需要根据这些数据来决定这个消息需要发送到哪个分区上,实现这个接口之后,设置partitioner.class参数为你自己实现类的全限定域名即可。

思考

  • 为什么需要引入分区的概念?