Kafka Streams:混合匹配的PAPI和DSL KTable不进行共分区

时间:2018-07-26 15:48:05

标签: apache-kafka scalatest apache-kafka-streams embedded-kafka

我有一个混合匹配的Scala拓扑,其中主要角色是PAPI处理器,其他部分则通过DSL连接。

EventsProcessor: 
INPUT: eventsTopic
OUTPUT: visitorsTopic (and others)

整个主题中的数据(包括原始eventsTopic)通过进行分区,我们称其为DoubleKey,它具有两个字段。 访客通过接收器被发送到visitorsTopic

.addSink(VISITOR_SINK_NAME, visitorTopicName,
    DoubleKey.getSerializer(), Visitor.getSerializer(), visitorSinkPartitioner, EVENT_PROCESSOR_NAME)

在DSL中,我在以下主题上创建了一个KV KTable:

val visitorTable = builder.table(
  visitorTopicName,
  Consumed.`with`(DoubleKey.getKafkaSerde(),
  Visitor.getKafkaSerde()),
  Materialized.as(visitorStoreName))

我稍后将其连接到EventProcessor

topology.connectProcessorAndStateStores(EVENT_PROCESSOR_NAME, visitorStoreName)

所有内容都被共同分区(通过DoubleKey)。 visitorSinkPartitioner执行典型的模运算:

Math.abs(partitionKey.hashCode % numPartitions)

在PAPI处理器EventsProcessor中,我查询此表以查看是否已经存在访客。

但是,在我的测试中(使用EmbeddedKafka,但这没有什么区别),如果我在一个分区上运行它们,一切都很好(EventProcessor在同一{{1}上的两个事件上检查KTable) },并且在第二个事件上(有一些延迟),它可以看到商店中存在的DoubleKey),但是如果我使用更高的数字运行它,则EventProcessor永远不会在商店中看到该值。

但是,如果我通过API检查商店(迭代Visitor),记录就在那里。所以我知道它一定要去不同的分区。

由于KTable应该处理其分区上的数据,并且所有数据都发送到同一分区(使用显式分区程序调用相同的代码),因此KTable应该将数据获取到同一分区上。

我的假设正确吗?可能会发生什么?

KafkaStreams 1.0.0,Scala 2.12.4。

PS。当然,在PAPI上通过store.all()而不是put来创建商店,这将是可行的,因为这肯定会使用代码运行所在的分区,但这是不可能的。 / p>

1 个答案:

答案 0 :(得分:1)

是的,这些假设是正确的。

以防万一:

将分区程序传递到Scala EmbeddedKafka库时遇到问题。在其中一个测试套件中,操作不正确。 现在,按照健康的重构实践,在这种拓扑的所有套件中都使用了这种方法。

def getEmbeddedKafkaTestConfig(zkPort: Int, kafkaPort: Int) : 
    EmbeddedKafkaConfig = {
    val producerProperties = Map(ProducerConfig.PARTITIONER_CLASS_CONFIG ->
        classOf[DoubleKeyPartitioner].getCanonicalName)
    EmbeddedKafkaConfig(kafkaPort = kafkaPort, zooKeeperPort = zkPort, 
        customProducerProperties = producerProperties)
}