web-dev-qa-db-ja.com

kafkaストリームでの集約と状態ストアの保持

次のようなユースケースがあります。着信イベントごとに、特定のフィールドを調べて、ステータスがAからBに変更されたかどうかを確認し、変更された場合は、それを出力トピックに送信します。フローは次のようになります。キー「xyz」のイベントがステータスAで受信し、しばらくしてから別のイベントがキー「xyz」のステータスBで受信します。このコードは高レベルDSLを使用しています。

final KStream<String, DomainEvent> inputStream....

final KStream<String, DomainEvent> outputStream = inputStream
          .map((k, v) -> new KeyValue<>(v.getId(), v))
                    .groupByKey(Serialized.with(Serdes.String(), jsonSerde))
                    .aggregate(DomainStatusMonitor::new,
                            (k, v, aggregate) -> {
                                aggregate.updateStatusMonitor(v);
                                return aggregate;
                            }, Materialized.with(Serdes.String(), jsonSerde))
                    .toStream()
                    .filter((k, v) -> v.isStatusChangedFromAtoB())
                    .map((k,v) -> new KeyValue<>(k, v.getDomainEvent()));

DSLを使用してこのロジックを書くためのより良い方法はありますか?

上記のコードの集計によって作成された状態ストアに関するいくつかの質問。

  1. デフォルトでメモリ内の状態ストアを作成していますか?
  2. 無制限の数の一意の着信キーがある場合はどうなりますか?デフォルトでインメモリストアを使用している場合、永続ストアに切り替える必要はありませんか? DSLでそのような状況をどのように処理しますか?
  3. 状態ストアが非常に大きい場合(メモリ内または永続的)、起動時間にどのように影響しますか?ストアが完全に初期化されるようにストリーム処理を待機させるにはどうすればよいですか?または、Kafkaストリームは、着信イベントが処理される前に状態ストアが完全に初期化されることを保証しますか?

前もって感謝します!

7
sobychacko
  1. デフォルトでは、永続的なRocksDBストアが使用されます。インメモリストアを使用する場合は、Materialized.as(Stores.inMemoryKeyValueStore(...))を渡します。

  2. 一意のキーが無数にある場合、最終的にメインメモリまたはディスクが不足し、アプリケーションが停止します。セマンティクスに応じて、古いキーを期限切れにする代わりに、大きな「ギャップ」パラメータを使用してセッションウィンドウ集計を使用することで「TTL」を取得できます。

  3. 新しいデータの処理が行われる前に、状態は常に復元されます。インメモリストアを使用する場合、これは、基になる変更ログトピックを消費することによって発生します。州の規模によっては、これにはしばらく時間がかかる場合があります。永続的なRocksDBストアを使用する場合、状態はディスクから読み込まれるため、復元は不要であり、処理はすぐに実行されます。ローカルディスクの状態を失った場合にのみ、この場合、変更ログトピックからの復元が行われます。

12
Matthias J. Sax