[英]Spring Cloud Kafka Stream: Publishing to DLQ is failing with Avro
[英]Using Spring Cloud Stream Kafka Streams with Avro input/output with nativeEncoding/decoding=false
We're testing the use of Kafka Streams via Spring Cloud Stream function support with Avro input/output records, but setting nativeEncoding= nativeEncoding=false
and nativeDecoding=false
in order to use a custom MessageConverter
where we do the Avro conversion.
默認的 serdes 是用於鍵的StringSerde
和用於值的ByteArraySerde
。
當我們只使用 KStream 到 KStream function 時一切正常,例如:
@Bean
public Function<KStream<String, DataRecordAvro>, KStream<String, DataRecordAvro>> wordsCount() {
return input -> input
.flatMapValues(value -> Arrays.asList(value.getName().toString().toLowerCase().split("\\W+")))
.map((key, value) -> new KeyValue<>(value, value))
.groupByKey(Grouped.with(Serdes.String(), Serdes.String()))
.windowedBy(TimeWindows.of(Duration.ofSeconds(5)).grace(Duration.ofMillis(0)))
.count()
.toStream()
.map((key, value) -> new KeyValue<>(key.key(), new DataRecordAvro(key.key(), value)));
}
但是當我們嘗試一個更復雜的例子時,涉及一個像這樣的輸入 KTable:
@Bean
public BiFunction<KStream<String, DataRecordAvro>, KTable<String, DataRecordAvro>, KStream<String, DataRecordAvro>> userClicksRegionKTableAvro() {
return (userClicksStream, usersRegionKTable) -> userClicksStream
.leftJoin(usersRegionKTable,
(clicks, region) -> new RegionWithClicks(region == null ? "UNKNOWN" : region.getName().toString(), clicks.getCount()))
.map((user, regionWithClicks) -> new KeyValue<>(regionWithClicks.getRegion(), regionWithClicks.getClicks()))
.groupByKey(Grouped.with(Serdes.String(), Serdes.Long()))
.reduce(Long::sum)
.mapValues((key, value) -> new DataRecordAvro(key, value))
.toStream();
}
( DataRecordAvro
class 只有兩個成員: CharSequence name; Long count;
)
當收到第一條記錄時,拋出此異常:
ClassCastException invoking Processor. Do the Processor's input types match the deserialized types? Check the Serde setup and change the default Serdes in StreamConfig or provide correct Serdes via method parameters. Make sure the Processor can accept the deserialized input of type key: java.lang.String, and value: com.xxxx.kstreams.fixtures.avro.DataRecordAvro.
Note that although incorrect Serdes are a common cause of error, the cast exception might have another cause (in user code, for example). For example, if a processor wires in a store, but casts the generics incorrectly, a class cast exception could be raised during processing, but the cause would not be wrong Serdes.
拋出異常的處理器似乎是:
KSTREAM-LEFTJOIN-0000000011:
states: [user-regions-avro-STATE-STORE-0000000008]
我們不知道為什么它在這種情況下不起作用。 也許leftJoin
操作將信息持久化到內部主題,並且沒有考慮到useNativeEncoding/Decoding=false
? 但是為什么上面的 kstream->kstream 示例確實有效? 我們認為 Avro 轉換只在拓撲的開始和結束時完成,為什么在使用leftJoin
時會出現這種轉換異常?
這是另一個可以正常工作的示例(沒有輸入 Avro 記錄,將消費者useNativeDecoding
為默認 true):
@Bean
public BiFunction<KStream<String, Long>, KTable<String, String>, KStream<String, DataRecordAvro>> userClicksRegionKTable() {
return (userClicksStream, usersRegionKTable) -> userClicksStream
.leftJoin(usersRegionKTable,
(clicks, region) -> new RegionWithClicks(region == null ? "UNKNOWN" : region, clicks))
.map((user, regionWithClicks) -> new KeyValue<>(regionWithClicks.getRegion(), regionWithClicks.getClicks()))
.groupByKey(Grouped.with(Serdes.String(), Serdes.Long()))
.reduce(Long::sum)
.mapValues((key, value) -> new DataRecordAvro(key, value))
.toStream();
}
請幫忙!
對於 Spring Cloud Stream 中的 Kafka Streams binder,我們建議使用帶有Serde
的本機解碼/編碼,除非您有充分的理由依賴消息轉換方法。 是什么用例迫使您在此處使用消息轉換器 go? 在實踐中,在 Spring Cloud Stream 的 Kafka Streams 應用程序中使用消息轉換器進行序列化目的會在拓撲中添加一個額外的層並使其更深,因此建議使用本機解碼/編碼。
正如您所指出的,對於KTable
,活頁夾始終使用本機解碼 - 目前,不可能在那里使用消息轉換器。 當您在KTable
綁定上關閉useNativeDecoding
時,綁定器會忽略它並僅使用默認字節 serde。 我建議在KTable
綁定上使用默認值,然后在應用程序配置中添加以下 bean。
@Bean
public Serde< DataRecordAvro> dataRecordAvroSerde() {
// return Serde
}
這樣,binder 將檢測到這個 bean 並意識到Serde
類型與 function 簽名中的類型匹配,然后在這些輸入上使用它。
如果您對此應用還有其他問題,請隨時分享MCRE 。 那我們可以進一步看看。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.