web-dev-qa-db-ja.com

Spring Batch:大量かつ低レイテンシーに使用するItemReader実装

ユースケース:データベースから1,000万行[10列]を読み取り、ファイルに書き込みます(csv形式)。

  1. JdbcCursorItemReaderJdbcPagingItemReaderのどのItemReader実装が提案されますか?その理由は何でしょうか?

  2. 上記のユースケースで(高速に)パフォーマンスが向上するのはどれですか?

  3. シングルプロセスアプローチとマルチプロセスアプローチの場合、選択は異なりますか?

  4. TaskExecutorを使用したマルチスレッドアプローチの場合、どちらがより適切でシンプルですか?

16
gyani

この種のデータを処理するには、可能であれば並列化する必要があります(これを防ぐ唯一の方法は、出力ファイルが入力からの順序を保持する必要がある場合です)。処理を並列化しようとしていると仮定すると、このタイプのユースケースの2つの主なオプションが残ります(提供したものから)。

  1. マルチスレッドステップ-これは、完了するまでスレッドごとにチャンクを処理します。これにより、非常に簡単な方法で並列化が可能になります(TaskExecutorをステップ定義に追加するだけです)。これにより、前述のいずれかのItemReaderで状態の永続性をオフにする必要があるため、すぐに再起動できなくなります(データベース内のレコードに処理済みのフラグを立てるなど、これを回避する方法があります)。
  2. パーティション分割-これにより、入力データがパーティションに分割され、ステップインスタンスによって並列に処理されます(マスター/スレーブ構成)。パーティションは、スレッドを介してローカルで(TaskExecutorを介して)実行することも、リモートパーティションを介してリモートで実行することもできます。いずれの場合も、並列化によって再起動可能性が得られます(各ステップは独自のデータを処理するため、パーティションからパーティションへの状態のステップはありません)。

SpringBatchと並行してデータを処理することについて話しました。具体的には、私が提示する例は、リモートパーティションジョブです。ここで表示できます: https://www.youtube.com/watch?v=CYTj5YT7CZ

あなたの特定の質問に:

  1. JdbcCursorItemReaderとJdbcPagingItemReaderの中でどのItemReader実装が提案されますか?理由は何ですか?-これら2つのオプションのいずれかを調整して、多くのパフォーマンスニーズを満たすことができます。これは、使用しているデータベース、使用可能なドライバーオプション、およびサポートできる処理モデルによって異なります。もう1つの考慮事項は、再起動可能性が必要ですか?
  2. 上記のユースケースで(高速)パフォーマンスが優れているのはどれですか?-これも、選択した処理モデルによって異なります。
  3. シングルプロセスアプローチとマルチプロセスアプローチの場合、選択は異なりますか?-これは、SpringBatchよりもジョブを管理する方法に関係します処理できます。問題は、ジョブの外部でパーティション化を管理する(データ記述をパラメーターとしてジョブに渡す)か、それともジョブでそれを管理する(パーティション化を介して)かです。
  4. TaskExecutorを使用したマルチスレッドアプローチの場合、どちらがより適切でシンプルですか?-リモートパーティショニングがレベルを追加することを否定しませんローカルパーティショニングとマルチスレッドステップにはない複雑さ。

基本的なステップの定義から始めます。次に、マルチスレッドの手順を試してください。それでもニーズが満たされない場合は、ローカルパーティションに移動し、必要に応じて最後にリモートパーティションに移動します。 Spring Batchは、その進行を可能な限り痛みのないものにするように設計されていることに注意してください。構成を更新するだけで、通常のステップからマルチスレッドのステップに進むことができます。パーティショニングに進むには、単一の新しいクラス(パーティショナーの実装)といくつかの構成の更新を追加する必要があります。

最後に1つ。これのほとんどは、このデータの処理を並列化することについて話しました。 Spring BatchのFlatFileItemWriterはnotスレッドセーフです。最善の策は、複数のファイルに並行して書き込み、速度が最大の関心事である場合は後でそれらを集約することです。

9
Michael Minella

選択を行うには、これをプロファイルする必要があります。プレーンJDBCでは、次のようなことから始めます。

  • ResultSet.TYPE_FORWARD_ONLY および ResultSet.CONCUR_READ_ONLY でステートメントを準備します。いくつかのJDBCドライバーは、これら2つを使用しない限り、クライアント側でカーソルを「シミュレート」します。大きな結果セットの場合、JDBCドライバーがデータセット全体をバッファリングしているため、おそらくOutOfMemoryErrorにつながるため、これは望ましくありません。メモリ内。これらのオプションを使用することで、サーバー側のカーソルを取得し、結果を少しずつ「ストリーミング」する可能性が高くなります。これは、大規模な結果セットに必要なことです。一部のJDBCドライバー常にクライアント側でカーソルを「シミュレート」するため、このヒントは特定のDBMSには役に立たない場合があることに注意してください。
  • ネットワークラウンドトリップの影響を最小限に抑えるために、妥当な フェッチサイズ を設定します。多くの場合、50〜100がプロファイリングの適切な開始値です。フェッチサイズはヒントであるため、これは特定のDBMSにとっても役に立たない場合があります。

JdbcCursorItemReader は両方をカバーしているようですが、前に述べたように、すべてのDBMSで最高のパフォーマンスが得られるとは限らないので、それから始めて、パフォーマンスが不十分な場合は、 JdbcPagingItemReader を試してください。

非常に厳しいパフォーマンス要件がない限り、JdbcCursorItemReaderを使用して単純な処理を行うとデータセットのサイズが遅くなるとは思いません。 reallyJdbcPagingItemReadermightを使用して並列化する必要がある場合は簡単ですが、これら2つのインターフェースは非常に似ているため、私はそれを当てにしません。

とにかく、profile

8
gpeche