在使用连接到Kafka的Spring Cloud Stream的Spring Boot应用程序中,我试图设置两个单独的流侦听器方法:
由于第一个侦听器进行了一些合并和汇总,因此会自动创建一些主题,例如“ test-1-KTABLE-AGGREGATE-STATE-STORE-0000000007-repartition-0”。 (不知道这是否与问题有关。)
当我通过用@StreamListener
注释两个单独的方法来设置代码时,当Spring Boot应用启动时,我得到以下错误:
Exception in thread "test-d44cb424-7575-4f5f-b148-afad034c93f4-StreamThread-2" java.lang.IllegalArgumentException: Assigned partition t1-0 for non-subscribed topic regex pattern; subscription pattern is t3
at org.apache.kafka.clients.consumer.internals.SubscriptionState.assignFromSubscribed(SubscriptionState.java:195)
at org.apache.kafka.clients.consumer.internals.ConsumerCoordinator.onJoinComplete(ConsumerCoordinator.java:225)
at org.apache.kafka.clients.consumer.internals.AbstractCoordinator.joinGroupIfNeeded(AbstractCoordinator.java:367)
at org.apache.kafka.clients.consumer.internals.AbstractCoordinator.ensureActiveGroup(AbstractCoordinator.java:316)
at org.apache.kafka.clients.consumer.internals.ConsumerCoordinator.poll(ConsumerCoordinator.java:295)
at org.apache.kafka.clients.consumer.KafkaConsumer.pollOnce(KafkaConsumer.java:1146)
at org.apache.kafka.clients.consumer.KafkaConsumer.poll(KafkaConsumer.java:1111)
at org.apache.kafka.streams.processor.internals.StreamThread.pollRequests(StreamThread.java:848)
at org.apache.kafka.streams.processor.internals.StreamThread.runOnce(StreamThread.java:805)
at org.apache.kafka.streams.processor.internals.StreamThread.runLoop(StreamThread.java:771)
at org.apache.kafka.streams.processor.internals.StreamThread.run(StreamThread.java:741)
我认为重要的部分是:“分配的分区 t1-0 用于非订阅主题正则表达式模式;订阅模式是 t3 ”。这是两个不相关的主题,据我所知,与t3相关的任何内容都不应订阅与t1相关的任何内容。引起问题的确切主题也会间歇性地更改:有时,它是自动生成的主题之一,而不是t1本身。
这是设置两个流侦听器的方式(在Kotlin中):
@StreamListener
fun listenerForT1AndT2(
@Input("t1") t1KTable: KTable<String, T1Obj>,
@Input("t2") t2KTable: KTable<String, T2Obj>) {
t2KTable
.groupBy(...)
.aggregate(
{ ... },
{ ... },
{ ... },
Materialized.with(Serdes.String(), JsonSerde(SomeObj::class.java)))
.join(t1KTable,
{ ... },
Materialized.`as`<String, SomeObj, KeyValueStore<Bytes, ByteArray>>("test")
.withKeySerde(Serdes.String())
.withValueSerde(JsonSerde(SomeObj::class.java)))
}
@StreamListener
fun listenerForT3(@Input("t3") t3KStream: KStream<String, T3Obj>) {
events.map { ... }
}
但是,当我只用一种用@StreamListener
注释的方法来设置代码,并为所有三个主题获取参数时,一切正常,例如
@StreamListener
fun compositeListener(
@Input("t1") t1KTable: KTable<String, T1Obj>,
@Input("t2") t2KTable: KTable<String, T2Obj>,
@Input("t3") t3KStream: KStream<String, T3Obj>) {
...
}
但是我认为只能使用一个@StreamListener
方法是不对的。
我知道有content-based routing可以为StreamListener
注释添加条件,但是如果这些方法定义了输入通道,那么我不确定是否需要在这里使用它-我是d认为在方法参数上使用@Input
注释足以告诉系统要绑定到哪些渠道(并因此绑定到哪个Kafka主题)?如果我需要使用基于内容的路由,如何在此处应用它以使每种方法仅接收相关主题中的项目?
我还尝试将两个侦听器方法分为两个单独的类,每个类仅对它感兴趣的接口(例如,一个用于t1和t2的接口,以及一个用于t3的接口)具有@EnableBinding
),但这无济于事。
我发现的所有与此错误消息相关的其他信息,例如here是关于拥有多个应用程序实例的,但就我而言,只有一个Spring Boot应用程序实例。
答案 0 :(得分:2)
每个StreamListener
方法都需要单独的应用程序ID。这是一个示例:
spring.cloud.stream.kafka.streams.bindings.t1.consumer.application-id=processor1-application-id
spring.cloud.stream.kafka.streams.bindings.t2.consumer.application-id=processor1-application-id
spring.cloud.stream.kafka.streams.bindings.t3.consumer.application-id=processor2-application-id
您可能想使用最新的快照(2.1.0)进行测试,因为活页夹处理应用程序ID的方式最近有所更改。
有关更多详细信息,请参见更新here。
这是多个StreamListener
方法中的working sample,它们是Kafka Streams处理器。