关于Kafka分区器的一个关键细节

328 阅读4分钟

Apache Kafka是当今事件流的事实上的标准。Kafka之所以如此成功,部分原因是它有能力处理大量的数据,每秒数百万条记录的吞吐量,在生产环境中并非闻所未闻。Kafka的设计中,有一个部分使其成为可能,那就是分区。

Kafka使用分区来将数据的负载分散到集群中的经纪商,它也是并行性的单位;更多的分区意味着更高的吞吐量。由于Kafka使用键值对工作,因此在同一分区中获得具有相同键值的记录是至关重要的。

想想看,一个银行业的应用,在它产生的每笔交易中都使用了客户的ID,而Kafka也是如此。在同一个分区上获取所有这些事件是非常关键的;这样一来,消费者应用程序就会按照记录到达的顺序来处理它们。保证具有相同密钥的记录落在正确的分区上的机制是一个简单而有效的过程:将密钥的散列值与分区的数量相乘。这里有一个插图,显示了这个概念的作用:

在高层次上,CRC32或Murmur2等哈希函数接受一个输入,并产生一个固定大小的输出,如64位数字。无论是用Java、Python还是其他语言实现,相同的输入总是产生相同的输出。分区器使用哈希结果来一致地选择一个分区,所以相同的记录键将总是映射到相同的Kafka分区。我不会在这篇博客中讨论更多的细节,但只要知道有几种散列算法就足够了。

我今天想说的不是分区如何工作,而是Kafka生产者客户端中的分区器。生产者使用分区器来确定给定密钥的正确分区,所以在你的生产者客户端中使用相同的分区器策略是至关重要的。

由于生产者客户端有一个默认的分区器设置,这个要求不应该是一个问题。例如,当使用Apache Kafka发行版的Java生产者客户端时,KafkaProducer 类提供了一个默认的分区器,它使用Murmur2 哈希函数来确定给定键的分区。

但是其他语言的Kafka生产者客户端呢?优秀的librdkafka项目是Kafka客户端的C/C++实现,广泛用于非JVM Kafka应用。此外,其他语言的Kafka客户端(Python、C#)也建立在它之上。librdkafka的默认分区器使用CRC32哈希函数来获得一个键的正确分区。

这种情况本身并不是一个问题,但它很容易成为问题。Kafka代理对客户端的语言是不可知的;只要它遵循Kafka协议,你就可以使用任何语言的客户端,而代理会很乐意接受他们的生产和消费请求。考虑到今天的多语言编程环境,你可以在一个组织中拥有使用不同语言的开发团队,例如Python和Java。但如果不做任何改变,这两个小组将使用不同的分区策略,即不同的哈希算法:librdkafka生产者使用CRC32,Java生产者使用Murmur2,所以具有相同密钥的记录将落在不同的分区中那么,这种情况的补救措施是什么呢?

JavaKafkaProducer 只通过默认的分区器提供了一种散列算法;由于实现分区器很麻烦,所以最好让它处于默认状态。但是librdkafka生产者客户端提供了多种选择。其中一个选项是murmur2_random分区器,它使用murmur2哈希函数并将空键分配给随机分区,相当于Java默认分区器的行为。

例如,如果你在C#中使用Kafka生产者客户端,你可以用这一行设置分区策略:

ProducerConfig.Partitioner = Partitioner.Murmur2Random;

现在你的C#和Java生产者客户端使用了兼容的分区方法

当使用非java的Kafka客户端时,启用与Java生产者客户端相同的分区策略是一个很好的主意,以确保所有生产者对不同的键使用一致的分区。

事实上的标准 算法 Java(编程语言) Kafka Python(语言) 数据(计算

趋势

  • 数据加密:优点、类型和方法

  • React V18的好处:综合指南

  • 聘请工程经理的终极游戏手册

  • 什么是Argo CD?顾名思义,Kubernetes的GitOps工具。