本記事はこちらのブログを参考にしています。
翻訳にはアリババクラウドのModelStudio(Qwen)を使用しております。
Apache Flinkのストリーミングモードとバッチモードの比較
開発者は、Apache Flinkの一元化されたアーキテクチャを利用して、ストリーミング処理とバッチ処理を組み合わせて堅牢なデータアプリケーションを構築します。Flinkジョブでストリーミングモードとバッチモードを選択する際の一般的な指針は、遅延要件を評価することです。ストリーミングモードは、データが継続的に生成され、リアルタイムまたは近似リアルタイムの処理が必要なユースケースに適しています。たとえば、リアルタイムログ監視やオンライン詐欺検出などが該当します。一方、バッチモードは、スループットが遅延よりも優先される大量の履歴データの処理に理想的です。オフラインデータ分析やレポート生成などがこれに該当します。明らかに、時間に敏感なアプリケーションではストリーミングモードが好ましい選択肢です。しかし、非リアルタイムのデータ処理にはバッチモードしか選択肢がないのでしょうか?
最近、著者はバッチモードで実行されるデータ同期ジョブの最適化を行っていた際に興味深い発見をしました。そのジョブのロジックは単純でしたが、複数のシャッフル操作を含んでいました。テスト中に、バッチモードよりもストリーミングモードの方がジョブが早く完了し、つまりストリーミングモードの方が高いスループットを達成していることがわかりました。この発見に興味を持った著者は、非リアルタイムシナリオでのストリーミングモードの潜在的な利点についてさらに調査しました。著者の分析によれば、ジョブロジックとデータ量が特定の条件を満たす場合、ストリーミングモードはバッチモードを上回るスループットを達成できることが示されました。また、ストリーミングモードはリソース利用率も向上させることができます。これは、特定のバッチジョブがストリーミングモードに切り替えることで効率を高める可能性があることを示唆しています。
このブログの次のセクションでは、ストリーミングモードとバッチモードの違いをいくつかの観点から詳しく説明します。これらの違いを理解することで、開発者は自身のニーズに最適な決定を行うことができます。
スループット
バッチモードは通常、Join、Aggregate、Reduceなどの多数のステートフル演算子を含むジョブにおいて、ストリーミングモードよりも高いスループットを提供します。これは、バッチモードが制限されたデータセットの処理効率を最適化するように設計されているためです。たとえば、Join演算子はバッチモードでHash、Sort-Merge、Nested-Loopなどのより効率的なアルゴリズムを使用します。また、データはキーに基づいて集約を行う演算子に投入される前に、キーでソートされます。これにより、各キーの状態データをメモリ内に保持でき、外部ストレージの必要性がなくなります。
これを示すために、Nexmarkベンチマークを使用して、同じリソース条件下でのApache Flinkのストリーミングモードとバッチモードのパフォーマンスを評価しました(リソース制約によりTPC-DSベンチマークは使用されませんでした)。ストリーミングモードと比較して、バッチモードはほとんどのクエリでジョブの実行時間が短縮され、実行期間の減少率は17%から92%まででした。
特に注目すべきは、クエリ10 (q10) ではバッチモードの方がストリーミングモードよりも遅いことです。これは、バッチモードでSinkノードに追加された余分なソートステップにより、CPUリソースの消費が増えたためです。実験から得られたもう一つの重要な発見は、ジョブがMapやFilterなどのステートレス演算子のみを含み、複数のシャッフルステージを含む場合、ストリーミングモードの方がバッチモードよりも効率的であることです。たとえば、クエリ0 (q0) はソーステーブルからシンクテーブルへの元のデータの移動のみを含みます。この場合、ジョブはバッチモードで約18%速く完了しました。これは、演算子チェーンが作成され、シャッフルが発生しなかったためです。ただし、実際のシナリオでは、演算子の並列度が不一致であるか、特定のジョブトポロジーにより、ステートレスジョブでの演算子チェーンが失敗することがあります。
これを示すために、q0で演算子チェーン機能を無効にして、ジョブにシャッフルを導入しました。以下の図はジョブトポロジーを示しています。
このような条件下で、テスト結果はストリーミングモードの方がバッチモードよりも約35%速くジョブを完了したことを示しました。以下のフレームグラフを分析してパフォーマンスボトルネックを特定したところ、バッチモードでのシャッフルがストリーミングモードよりも多くのCPUリソースを消費していたことがわかりました。
ストリーミングモードでは、シャッフルするデータはメモリを介して送信されます。一方、バッチモードでは、データはシャッフル前にディスクに書き込まれ、これにより余分なオーバーヘッドが発生します。さらに、q0の場合、処理ロジックが単純であるため、演算子の実行を加速するための最適化の影響は限定的です。
まとめると、インメモリシャッフルの設計により、ストリーミングモードは多くのステートレス演算子とシャッフルを含むジョブ、特に大量のデータを扱う場合に適しています。一方、バッチモードはステートフル演算子を多数含むジョブに適しており、ステートフル演算子に対して特定の最適化を提供します。
リソース利用率
ストリーミングモードでは、パイプライン内の演算子間でデータをリアルタイムで転送できます。ジョブがこのモードで実行されるとき、すべてのタスクは同時にデプロイおよび実行され、データが最小限の遅延で処理されるようにします。そのため、ジョブは必要なすべてのリソースを最初に取得し、FlinkクラスターのCPU、メモリ、ネットワークリソースを継続的に消費します。
一方、バッチモードでは、データ依存関係に基づいてタスクを異なるステージに分割します。同じステージ内のタスクは異なる時間に実行される可能性がありますが、異なるステージのタスクは順番にスケジュールおよび実行されます。したが
状態サイズが小さくトポロジーが単純なシナリオでは、ストリーミングモードはバッチモードと比較して通常、低い障害耐性コストを伴います。これは、ストリーミングモードでのチェックポイントのコストが相対的に低く、最新のチェックポイントから復旧を開始できるためです。一方、バッチモードではタスクを最初から再実行する必要があり、これが復旧時間を延ばします。しかし、状態サイズが大きくトポロジーが複雑なシナリオでは、ストリーミングモードはバッチモードよりも高い障害耐性コストを伴う可能性があります。これは、ストリーミングモードでのチェックポイントデータの量が多いためで、計算リソースとストレージに大きな要求をかけることになります。さらに、これらのチェックポイントからの復旧プロセスは長時間かかる可能性があり、タスクの再実行に関連するコストを上回るかもしれません。
結論
Flinkジョブの実行モードを選択する際には、各シナリオの具体的なニーズと特性を徹底的に評価することが重要であり、既存のガイドラインに厳格に従うべきではありません。リアルタイム要件が高いジョブはストリーミングモードに最適で、リアルタイム処理を必要としないジョブはバッチモードに適しているという一般的な考え方もありますが、スループット、リソース利用率、障害耐性コストなどの要素を詳細に分析することで、より洗練された結論に至ることができます。
ストリーミングモードに適したジョブタイプ:
- 重要なリアルタイム要件を持つジョブ
- リアルタイムではないコンテキストでの多数のシャッフル操作を含むステートレスジョブ
- 連続的かつ安定したデータ処理を必要とするジョブ
- 状態サイズが小さく、トポロジーが単純で、障害耐性コストが低いジョブ
バッチモードに適したジョブタイプ:
- リアルタイムではないシナリオでの多くのステートフルオペレータを持つジョブ
- 高いリソース利用率を必要とするジョブ
- 状態サイズが大きく、トポロジーが複雑で、障害耐性コストが高いジョブ
Flinkジョブの実行モードを選択する際に考慮すべき要素はいくつかあります。開発者は、異なるビジネス要件や特定のアプリケーションシナリオに基づいて、ストリーミングモードとバッチモードのどちらを選択するかを決定し、ジョブの実行とリソース利用率を最適化することができます。