簡體   English   中英

使用 Spring Cloud Stream Kafka Streams 與 Avro 輸入/輸出與 nativeEncoding/decoding=false

[英]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.

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