![](/img/trans.png)
[英]How to implement total count over multiple partitions in Kafka Streams
[英]Aggregate over multiple partitions in Kafka Streams
这部分是对Apache Kafka Streams中特定分区上的聚合的后续操作
假设我有一个名为“事件”的主题,它带有3个分区,在该分区上发送字符串->整数数据,如下所示:
(Bob,3)在分区1上
(Sally,4)在分区2上
(Bob,2)在分区3上
...
我想在所有分区上聚合值(在此示例中,只是一个简单的总和),最终得到一个看起来像这样的KTable
:
(莎莉,4)
(鲍勃,5岁)
正如我在上面链接的问题的答案中所提到的,不可能直接进行这种跨分区聚合。 但是,答复者提到,如果消息具有相同的密钥,则是可能的(在这种情况下,这是正确的)。 如何做到这一点?
我还希望能够从在Kafka Streams应用程序的每个实例之间复制的“全局”状态存储中查询这些聚合值。
我的第一个想法是使用GlobalKTable
(根据此页面 ,我相信这应该是我所需要的)。 但是,此状态存储的changelog主题具有与原始“事件”主题相同的分区数量,并且仅基于每个分区而不是跨所有分区进行聚合。
这是我的应用程序的精简版-不确定从何处去:
final Properties streamsConfig = new Properties();
streamsConfig.put(StreamsConfig.APPLICATION_ID_CONFIG, "metrics-aggregator");
streamsConfig.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
streamsConfig.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass().getName());
streamsConfig.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, CustomDoubleSerde.class.getName());
streamsConfig.put(StreamsConfig.producerPrefix(ProducerConfig.LINGER_MS_CONFIG), 0);
streamsConfig.put(StreamsConfig.NUM_STREAM_THREADS_CONFIG, 1);
final StreamsBuilder builder = new StreamsBuilder();
KStream<String, Double> eventStream = builder.stream(INCOMING_EVENTS_TOPIC);
KTable<String, Double> aggregatedMetrics = eventStream
.groupByKey()
.aggregate(() -> 0d, (key, value, aggregate) -> value + aggregate);
aggregatedMetrics.toStream().print(Printed.<String, Double>toSysOut());
aggregatedMetrics.toStream().to(METRIC_CHANGES_TOPIC);
final KafkaStreams streams = new KafkaStreams(builder.build(), streamsConfig);
streams.cleanUp();
streams.start();
builder.globalTable(METRIC_CHANGES_TOPIC, Materialized.<String, Double, KeyValueStore<Bytes, byte[]>>as(METRICS_STORE_NAME));
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
streams.close();
}));
Kafka Streams假定输入主题按键分区。 此假设不适用于您的情况。 因此,您需要将此事告诉Kafka Streams。
在您的特定情况下,您可以将groupByKey
替换为groupBy()
KTable<String, Double> aggregatedMetrics = eventStream
.groupBy((k,v) -> k)
.aggregate(() -> 0d, (key, value, aggregate) -> value + aggregate);
lambda是一个不会修改密钥的虚拟对象,但是,这暗示了Kafka Streams在进行聚合之前会根据密钥对数据进行重新分区。
关于GlobalKTable
:这是一种特殊的表,它不是聚合的结果,而只是从changelog主题填充的。 看来您的代码已经在做正确的事情:将聚合结果写入主题,然后将该主题重新读取为GlobalKTable
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.