![Kafka进阶](https://wfqqreader-1252317822.image.myqcloud.com/cover/408/43738408/b_43738408.jpg)
3.4.1 生产者分区机制
Kafka消息系统为什么要进行Topic的分区呢?我们都知道Kafka的主题Topic是由分区组成的,而将Topic进行分区的主要目的就是提供负载均衡和容错的能力,以及实现系统的高伸缩性和高可用性。Kafka的消息组织方式实际上是三层结构:主题—分区—消息。主题下的每条消息只会保存在某一个分区中,而不会在多个分区中保存多份。在创建Topic的时候可以指定每个分区的副本数,用于支持分区中消息的容错。图3.3是Kafka官方网站上的截图,展示了Kafka消息模型的三层结构。
![](https://epubservercos.yuewen.com/527ABA/23020654009771406/epubprivate/OEBPS/Images/42653-00-074-01.jpg?sign=1738950104-U9icTSKi9LJBZfnMBdsS3DMXc9s3qfea-0-3bef5987cb8dac2f0aa4d81680adc137)
图3.3 Kafka消息模型的三层结构
不同的分区能够放置在Kafka集群中不同的节点上,而生产者和消费者在产生消息和消费消息的时候,也都是针对分区进行的,这样每个节点的机器都能独立执行各自分区的读写请求处理,并且还可以通过添加新的Kafka节点来增加整体系统的吞吐量。
既然Kafka提供了分区的机制,那么Kafka又为我们提供了哪些分区的策略呢?所谓的分区策略是决定生产者将消息发送到哪个分区的算法。Kafka生产者的分区策略都实现了接口org.apache.kafka.clients.producer.Partitioner,常见的分区策略主要有几下几种。
(1)默认分区策略(org.apache.kafka.clients.producer.internals.DefaultPartitioner)。
下面的注释摘至源码中的说明。
![](https://epubservercos.yuewen.com/527ABA/23020654009771406/epubprivate/OEBPS/Images/42653-00-074-1.jpg?sign=1738950104-SBbUBG4ucX2DOFPzdWIXRccjfg020JFY-0-ac8abe3d2e73dfb30cf1ad92cd372198)
从注释的说明可以看出,默认的分区机制将按照以下的逻辑进行分区。
• 如果记录中指定了分区,则可以直接使用。
• 如果记录中未指定分区,但指定了key值,则根据key的hash值选择一个分区。这种策略的本质就是Hash分区。
• 如果记录中未指定分区,也未指定key值,则以黏性分区策略选择一个分区。
下面的partition方法实现了Kafka默认的分区机制。
![](https://epubservercos.yuewen.com/527ABA/23020654009771406/epubprivate/OEBPS/Images/42653-00-074-2.jpg?sign=1738950104-Nda3v8jhC9yHZlLAPbfZE433hP6Y0WuT-0-622066924c3380f166d7ea3f838ecc4d)
![](https://epubservercos.yuewen.com/527ABA/23020654009771406/epubprivate/OEBPS/Images/42653-00-075-1.jpg?sign=1738950104-SIZzeiOPDgJJJbhALuFpkwDGeXVeVCvT-0-9c89fcd813f141cd4a92a582a564ec1b)
(2)轮询分区策略(org.apache.kafka.clients.producer.RoundRobinPartitioner)。
如果key值为null,并且使用了默认的分区器,Kafka会根据轮询(Random Robin)策略将消息均匀地分布到各个分区上。下面是RoundRobinPartitioner的核心代码。
![](https://epubservercos.yuewen.com/527ABA/23020654009771406/epubprivate/OEBPS/Images/42653-00-075-2.jpg?sign=1738950104-1gv2Urhjeu40889npMYSwqbxH6ey5huJ-0-53dd91e59b973612ec3598b99a09ad4d)
![](https://epubservercos.yuewen.com/527ABA/23020654009771406/epubprivate/OEBPS/Images/42653-00-076-1.jpg?sign=1738950104-KK0wj9wYpdAJburivpiPG8WURCM3IhbU-0-d11f719073923694759db6caa90afe33)
(3)黏性分区策略(org.apache.kafka.clients.producer.UniformStickyPartitioner)。
黏性分区策略就像黏住这个分区一样,只要这个分区没有被填满,就会尽可能地坚持使用该分区。这种策略首先会选择单个分区发送所有无key的消息,一旦这个分区已填满,黏性分区策略就会随机选择另一个分区。
通过查看源码,可以得到黏性分区策略是通过org.apache.kafka.clients.producer. internals.StickyPartitionCache来实现的,下面展示了StickyPartitionCache中的核心代码。
![](https://epubservercos.yuewen.com/527ABA/23020654009771406/epubprivate/OEBPS/Images/42653-00-076-2.jpg?sign=1738950104-PJj1sDX8nmzRoA62w2nh4qiqe0kX6sFo-0-66df2a62f57c2092639ccce69e9b6db6)
![](https://epubservercos.yuewen.com/527ABA/23020654009771406/epubprivate/OEBPS/Images/42653-00-077-1.jpg?sign=1738950104-v3sg2raFTnyPtHeYoCAl25KSFF2ZDLHQ-0-19e583e5dd9ef975634c9a660cca4cd2)
(4)散列分区策略。
如果键值不为null,并且使用了默认的分区器,Kafka会对键进行散列,然后根据散列值把消息映射到对应的分区上。下面的代码是在DefaultPartitioner中使用的散列分区。
![](https://epubservercos.yuewen.com/527ABA/23020654009771406/epubprivate/OEBPS/Images/42653-00-077-2.jpg?sign=1738950104-257PCUutICeP3h8UuTRFuuXyST9ACOaa-0-b3a321ba347eeff417e6944aa1613eaa)
(5)自定义分区策略。前面提到Kafka生产者的分区策略都实现了接口org.apache.kafka.clients. producer.Partitioner,用户可以根据需要对数据使用不一样的分区策略,只需要实现该接口即可。用户创建了自定义分区策略后,只需要在生产者的Properties中指定ProducerConfig.PARTITIONER_CLASS_CONFIG参数即可,代码如下所示。
![](https://epubservercos.yuewen.com/527ABA/23020654009771406/epubprivate/OEBPS/Images/42653-00-077-3.jpg?sign=1738950104-wEiVVkqEYE22LwOXUqNLHcwBXHj2Wu7b-0-30db954171e1490c397304409c2e94d6)
下面我们通过一个具体的例子来实现Kafka生产者的自定义分区。在发送到Kafka系统的消息中,key将包含员工所在的部门号,这里将根据部门号来建立分区。例如,10号部门的员工数据将发送到0号分区;20号部门的员工数据将发送到1号分区;30号部门的员工数据将发送到2号分区;其他部门的员工数据将发送到3号分区。
完整的代码如下。
![](https://epubservercos.yuewen.com/527ABA/23020654009771406/epubprivate/OEBPS/Images/42653-00-077-4.jpg?sign=1738950104-mnUT4bChN4nt5lYq5QUVOF3WGUG6Z1F3-0-047db42e2ca6cee2f4a324425e71a296)
![](https://epubservercos.yuewen.com/527ABA/23020654009771406/epubprivate/OEBPS/Images/42653-00-078-1.jpg?sign=1738950104-codoZKFtIdi2hsps4DOHvebxn6wO7AWk-0-a08c269b490a721905f302aae5977340)
自定义分区策略创建完成后,将其加入生产者的配置参数中。
![](https://epubservercos.yuewen.com/527ABA/23020654009771406/epubprivate/OEBPS/Images/42653-00-078-2.jpg?sign=1738950104-mjKmnluHrqZNNx2MKLRRsm6Frr5C6urE-0-b4330b5e3f7d8892bd08d3599a2bff67)