[英]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。默認值:假。
起始偏移量
新組的起始偏移量。 允許值:
earliest
和latest
。 如果為消費者“綁定”明確設置了消費者組(通過 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.