Apache Kafka 是当今事件流式处理的事实标准。Kafka 如此成功的部分原因是它能够处理大量数据,每秒处理数百万条记录的吞吐量在生产环境中并非闻所未闻。Kafka 设计中使这成为可能的一部分是分区。
Kafka 使用分区将数据负载分散到集群中的代理之间,它也是并行度的单位;更多的分区意味着更高的吞吐量。由于 Kafka 使用键值对,因此在同一分区上获取具有相同键的记录至关重要。
想想一个银行应用程序,它使用客户 ID 来生成到 Kafka 的每笔交易。将所有这些事件放在同一个分区上至关重要;这样一来,消费者应用程序就会按照记录到达的顺序处理记录。保证具有相同键的记录落在正确的分区上的机制是一个简单但有效的过程:取键模的哈希值乘以分区数。下面是一个插图,展示了这个概念的实际效果:
在较高级别上,CRC32 或 Murmur2 等哈希函数接受输入并产生固定大小的输出,例如 64 位数字。相同的输入总是产生相同的输出,无论是用 Java、Python 还是任何其他语言实现。分区器使用哈希结果一致地选择分区,因此相同的记录键将始终映射到相同的 Kafka 分区。我不会在这篇博客中详细介绍,但知道有几种哈希算法就足够了。
我今天想谈的不是分区是如何工作的,而是 Kafka 生产者客户端中的分区器。生产者使用分区器来确定给定键的正确分区,因此在生产者客户端中使用相同的分区器策略至关重要。
由于创建者客户端具有默认的分区程序设置,因此此要求应该不是问题。例如,当将 Java 创建者客户端与 Apache Kafka 发行版一起使用时,该类提供了一个默认分区器,该分区器使用 Murmur2 哈希函数来确定给定键的分区。KafkaProducer
但是,其他语言的 Kafka 生产者客户呢?优秀的 librdkafka 项目是 Kafka 客户端的 C/C++ 实现,广泛用于非 JVM Kafka 应用。此外,其他语言(Python、C#)的 Kafka 客户端也在此之上构建。librdkafka 的默认分区器使用 CRC32 哈希函数来获取键的正确分区。
这种情况本身不是问题,但很容易成为问题。Kafka 代理对客户端的语言是不可知的;只要它遵循 Kafka 协议,你就可以使用任何语言的客户端,经纪人也很乐意接受他们的生产和消费请求。鉴于当今的多语言编程环境,您可以在组织内拥有使用不同语言的开发团队,例如 Python 和 Java。但是在没有任何变化的情况下,两组都将以不同的哈希算法的形式使用不同的分区策略:librdkafka 生产者使用 CRC32,Java 生产者使用 Murmur2,因此具有相同键的记录将落在不同的分区中!那么,对这种情况的补救措施是什么?
Java 仅通过默认分区器提供一种哈希算法;由于实现分区程序很棘手,因此最好将其保留为默认值。但是 librdkafka 生产者客户端提供了多种选择。其中一个选项是 murmur2_random 分区器,它使用 murmur2 哈希函数并将空键分配给随机分区,这与 Java 默认分区器的行为等效。KafkaProducer
例如,如果在 C# 中使用 Kafka 生产者客户端,则可以使用以下行设置分区策略:
ProducerConfig.Partitioner = Partitioner.Murmur2Random;
现在,您的 C# 和 Java 创建者客户端使用兼容的分区方法!
使用非 Java Kafka 客户端时,启用与 Java 生产者客户端相同的分区策略是一个很好的主意,可以确保所有生产者对不同的键使用一致的分区。