web-dev-qa-db-ja.com

RecordTooLargeException in Kafkaストリームが結合します

次の例外を除いて故障しているKStreamxKStream結合があります。

_Exception in thread “my-clicks-and-recs-join-streams-4c903fb1-5938-4919-9c56-2c8043b86986-StreamThread-1" org.Apache.kafka.streams.errors.StreamsException: Exception caught in process. taskId=0_15, processor=KSTREAM-SOURCE-0000000001, topic=my_outgoing_recs_prod, partition=15, offset=9248896
    at org.Apache.kafka.streams.processor.internals.StreamTask.process(StreamTask.Java:203)
    at org.Apache.kafka.streams.processor.internals.StreamThread.processAndPunctuate(StreamThread.Java:679)
    at org.Apache.kafka.streams.processor.internals.StreamThread.runLoop(StreamThread.Java:557)
    at org.Apache.kafka.streams.processor.internals.StreamThread.run(StreamThread.Java:527)
Caused by: org.Apache.kafka.streams.errors.StreamsException: task [0_15] exception caught when producing
    at org.Apache.kafka.streams.processor.internals.RecordCollectorImpl.checkForException(RecordCollectorImpl.Java:136)
    at org.Apache.kafka.streams.processor.internals.RecordCollectorImpl.send(RecordCollectorImpl.Java:87)
    at org.Apache.kafka.streams.state.internals.StoreChangeLogger.logChange(StoreChangeLogger.Java:59)
    at org.Apache.kafka.streams.state.internals.ChangeLoggingSegmentedBytesStore.put(ChangeLoggingSegmentedBytesStore.Java:59)
    at org.Apache.kafka.streams.state.internals.MeteredSegmentedBytesStore.put(MeteredSegmentedBytesStore.Java:105)
    at org.Apache.kafka.streams.state.internals.RocksDBWindowStore.put(RocksDBWindowStore.Java:107)
    at org.Apache.kafka.streams.state.internals.RocksDBWindowStore.put(RocksDBWindowStore.Java:100)
    at org.Apache.kafka.streams.kstream.internals.KStreamJoinWindow$KStreamJoinWindowProcessor.process(KStreamJoinWindow.Java:64)
    at org.Apache.kafka.streams.processor.internals.ProcessorNode$1.run(ProcessorNode.Java:47)
    at org.Apache.kafka.streams.processor.internals.StreamsMetricsImpl.measureLatencyNs(StreamsMetricsImpl.Java:187)
    at org.Apache.kafka.streams.processor.internals.ProcessorNode.process(ProcessorNode.Java:133)
    at org.Apache.kafka.streams.processor.internals.ProcessorContextImpl.forward(ProcessorContextImpl.Java:82)
    at org.Apache.kafka.streams.processor.internals.SourceNode.process(SourceNode.Java:80)
    at org.Apache.kafka.streams.processor.internals.StreamTask.process(StreamTask.Java:189)
    ... 3 more
Caused by: org.Apache.kafka.common.errors.RecordTooLargeException: The request included a message larger than the max message size the server will accept.
_

ClickトピックとRecommendationトピックを結合しています。 Clickオブジェクトは本当に小さいです(KB未満)。一方、Recommendationは大きくなる場合があり、場合によっては1MBを超えることもあります。

私は例外をグーグルで検索し、プロデューサー構成で_max.request.size_を設定する必要があることを発見しました( ここ )。

私が理解していないのは、プロデューサーがストリームのどこに参加するのかということです。上記の例外のトピック_topic=my_outgoing_recs_prod_は推奨トピックであり、最終的に結合されたトピックではありません。ストリーミングアプリケーションは、それから単に「消費」することになっているのではありませんか?

それでも、プロパティをconfig.put("max.request.size", "31457280");として設定してみました。これは30MBです。推奨レコードがその制限を超えるとは思わない。それでも、コードはクラッシュしています。

Kafkaクラスターの構成を変更することはできませんが、必要に応じて、Kafkaの関連トピックのプロパティを変更できます。

誰かが私が試すことができる他に何を提案できますか?

何も機能しない場合、私はそのような特大のメッセージを無視するつもりです。ただし、このRecordTooLargeExceptionを処理する方法がわかりません。

結合を実行するための私のコードは次のとおりです。

_Properties config = new Properties();
config.put(StreamsConfig.APPLICATION_ID_CONFIG, JOINER_ID + "-" + System.getenv("HOSTNAME"));
config.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, booststrapList);
config.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass().getName());
config.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, Serdes.ByteArray().getClass().getName());
config.put("max.request.size", "314572800");
config.put("message.max.bytes", "314572800");
config.put("max.message.bytes", "314572800");


KStreamBuilder builder = new KStreamBuilder();

KStream<String, byte[]> clicksStream = builder.stream(TopologyBuilder.AutoOffsetReset.LATEST, Serdes.String(), Serdes.ByteArray(), clicksTopic);
KStream<String, byte[]> recsStream = builder.stream(TopologyBuilder.AutoOffsetReset.LATEST, Serdes.String(), Serdes.ByteArray(), recsTopic);

KStream<String, ClickRec> join = clicksStream.join(
        recsStream,
        (click, recs) -> new ClickRec(click, recs),
        JoinWindows.of(windowMillis).until(3*windowMillis));

join.to(Serdes.String(), JoinSerdes.CLICK_SERDE, jointTopic);

KafkaStreams streams = new KafkaStreams(builder, config);
streams.cleanUp();
streams.start();
_

ClickRecは結合されたオブジェクトです(これはRecommendationオブジェクトよりはるかに小さく、数KBより大きくなるとは思わない)。

このような時折特大のオブジェクトから回復するために、上記のコードのどこに_try...catch_を配置しますか?

7
Nik

さまざまなレベルで複数の構成があります。

  1. ブローカー設定がありますmessage.max.bytes(デフォルトは1000012)(cf http://kafka.Apache.org/documentation/#brokerconfigs
  2. トピックレベルの設定がありますmax.message.bytes(デフォルトは1000012)(cf http://kafka.Apache.org/documentation/#topicconfigs
  3. プロデューサーはmax.request.size(デフォルトは1048576)(cf。 http://kafka.Apache.org/documentation/#producerconfigs

スタックトレースは、ブローカーまたはトピックレベルで設定を変更する必要があることを示しています。

原因:org.Apache.kafka.common.errors.RecordTooLargeException:リクエストに最大メッセージサイズserverは受け入れます。

たぶん、プロデューサーの設定を増やす必要もあります。

そもそもなぜこれが必要なのですか:

KStream-KStream結合を実行すると、結合演算子は状態を構築します(結合を計算するには、両方のストリームからのレコードをバッファリングする必要があります)。状態はデフォルトでKafkaトピックに裏打ちされています-ローカル状態は基本的にキャッシュですが、Kafkaトピックは信頼できる情報源です。したがって、すべてのレコードは、Kafka Streamsが自動的に作成するこの「変更ログトピック」に書き込まれます。

12
Matthias J. Sax