簡體   English   中英

Kafka SpringBoot StreamListener - 如何按順序使用多個主題?

[英]Kafka SpringBoot StreamListener - how to consume multiple topics in order?

我有多個來自不同主題的 StreamListener 注釋方法。 但是其中一些主題需要從“最早”的偏移量中讀取以填充內存映射(類似於狀態機),然后從其他主題中消費,這些主題中可能包含應針對“最新”執行的命令狀態機。

當前代碼類似於:

@Component
@AllArgsConstructor
@EnableBinding({InputChannel.class, OutputChannel.class})
@Slf4j
public class KafkaListener {

    @StreamListener(target = InputChannel.EVENTS)
    public void event(Event event) {
        // do something with the event
    }

    @StreamListener(target = InputChannel.COMMANDS)
    public void command(Command command) {
        // do something with the command only after all events have been processed
    }

}

我嘗試添加一些可怕的代碼,從傳入的事件消息中獲取 kafka 主題偏移元數據,然后使用信號量來阻止命令,直到事件達到總偏移量的某個百分比。 這有點有效,但讓我感到難過,一旦我們有 20 個左右的主題都相互依賴,那么維持下去會很糟糕。

SpringBoot / Spring Streams 是否有任何內置機制來執行此操作,或者是否有一些我不知道的人們使用的常見模式?

TL;DR :如何在消費來自主題 B 的任何消息之前處理來自主題 A 的所有消息,而不做一些臟事,例如在消費者中為主題 B 粘貼 Thread.sleep(60000)?

查看kafka 消費者綁定屬性resetOffsets

重置偏移量

是否將消費者的偏移量重置為startOffset提供的值。 如果提供了KafkaRebalanceListener則必須為 false; 請參閱使用 KafkaRebalanceListener。

默認值:假。

起始偏移量

新組的起始偏移量。 允許值: earliestlatest 如果為消費者“綁定”明確設置了消費者組(通過 spring.cloud.stream.bindings..group),則“startOffset”設置為最早。 否則,匿名消費者組將其設置為最新。 另請參閱resetOffsets (在此列表的前面部分)。

默認值:null(相當於最早)。

您還可以添加KafkaBindingRebalanceListener並在消費者上執行搜索。

編輯

您還可以在第二個偵聽器上將autoStartup設置為 false,並在准備好后啟動綁定。 下面是一個例子:

@SpringBootApplication
@EnableBinding(Sink.class)
public class Gitter55Application {

    public static void main(String[] args) {
        SpringApplication.run(Gitter55Application.class, args);
    }

    @Bean
    public ConsumerEndpointCustomizer<KafkaMessageDrivenChannelAdapter<?, ?>> customizer() {
        return (endpoint, dest, group) -> {
            endpoint.setOnPartitionsAssignedSeekCallback((assignments, callback) -> {
                assignments.keySet().forEach(tp -> callback.seekToBeginning(tp.topic(), tp.partition()));
            });
        };
    }

    @StreamListener(Sink.INPUT)
    public void listen(String value, @Header(KafkaHeaders.RECEIVED_MESSAGE_KEY) byte[] key) {
        System.out.println(new String(key) + ":" + value);
    }

    @Bean
    public ApplicationRunner runner(KafkaTemplate<byte[], byte[]> template,
            BindingsEndpoint bindings) {

        return args -> {
            while (true) {
                template.send("gitter55", "foo".getBytes(), "bar".getBytes());

                System.out.println("Hit enter to start");
                System.in.read();
                bindings.changeState("input", State.STARTED);
            }
        };

    }

}
spring.cloud.stream.bindings.input.group=gitter55
spring.cloud.stream.bindings.input.destination=gitter55
spring.cloud.stream.bindings.input.content-type=text/plain

spring.cloud.stream.bindings.input.consumer.auto-startup=false

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM