📚

【AWS】大規模なバッチ処理を支える技術選定

2023/09/21に公開

この記事は?

金融や公共、あるいはToC向けのアプリなどでは大量のユーザーに伴って処理するデータやトラフィック量が多くなるので、大規模なバッチ処理を支えるためにも設計に工夫が必要です。通常AWSでバッチを構築する場合、比較的構築が簡単なので、インフラにAWSを使っている組織が簡単なバッチを動かしたい場合にはまずLambdaが考えられる選択肢となります。一方、バッチを動かす手段として他に、Fargate(ECS or AWS Batch) があり、サーバーレスではあるが構築難度や一部コストがLambdaと比べると高まりやすい特徴があります。そこで、Lambdaではなく敢えてFargateをもちいて大規模なバッチ処理を設計するケースをこの記事では紹介しようと思います。

Lambda, ECS, Batchそれぞれの比較

前述の通り、AWSでバッチ処理を行おうとするとLambda, ECS, Batchを用いる3パターンが代表的ですが、以下にそれぞれの比較検討を表でまとめてみました。

Lambda ECS Batch
構築がどれほど難しいか? 簡単 難しい 普通
15分以上の処理に対応可能か? 無理 可能 可能
起動•実行上のオーバヘッドは? 縛りあり 設定次第 縛りあり
既存環境からの移行難易度は? 縛りあり 普通 普通
リソースのカスタマイズ性は? 縛りあり 高い 普通
アプリ側の言語やライブラリ等諸技術は自由に選べるか? 縛りあり 基本自由 基本自由
大量データ処理に適するか? 普通(10MGまで) 適する(120GiBまで) 適する(120Gibまで)
大量リクエスト処理に適するか? 普通 普通 適している(デフォルトでジョブキュー保持)
ロギング(一元管理)の自由度 /lambda以下に保存 自由に設定 /batch以下に保存

ここから、表で挙げた内容をそれぞれ解説していきます。

構築難度に関しては、関数を実装するだけで済むLambdaが最も簡単で、バッチ専用に特化されたサービスであるBatchに関しては比較的バッチ構築はしやすい印象ですが、ECSに関してはバッチに特化していないため、バッチ処理を行うようにカスタマイズする必要があります。

タイムアウト制約に関して留意すべきは、Lambdaの実行時間は15分までなので、それ以上を超える処理時間のバッチは実装できないことです。

起動•実行上のオーバーヘッドに関しては、Lambdaにはコールドスタートがあるため起動時にオーバーヘッドを考える必要があり、Batchではジョブをキューに送信して、最適化のために、ある程度のジョブがキューイングしてから実行しようするので、即時性を求める処理には不向きです。

既存バッチを移行したいケースがあると思いますが、Lambdaで動かせるように合わせて関数ハンドラーを実装する必要があることや、PHPなど多くの企業が使用している言語をLambdaのランタイムがサポートしていないため、バッチの移行先としてLambdaは制限されることがあります。

カスタマイズ性に関しては、Lambdaはリソースにさまざまな制限があるため、インフラリソースをカスタマイズしにくいと言えます。また、Lambdaを使う場合前述の通り、PHPなどの言語をサポートしていないほか、言語のバージョン指定や使えるライブラリに制限があるため、もし使う場合はサポートされている言語を選び、常に(Node.jsなどの言語では結構頻繁にある印象)EOLを意識してバージョンアップデートの改修を定期的に行っていく必要があります。

大量データを扱うために必要なディスク容量ですが、最近Lambdaでは元々512MBと低かったのが10MGまで一気に改善された一方、Fargateを使う場合は120GiBまで指定でき、Lambdaにはまだ制約がある一方でFargateには10倍の開きがあって大量データも対応しやすいです。

大量リクエストに関してはキャンペーンなどがあって大量リクエストを捌く場合、キューを使って非同期処理を行うことになりますが、標準でジョブキューの機構があるのはBatchで、LambdaとECSもSQSを使えば実装が可能です。ただし、Batchではジョブキューが標準装備されているが故に、ジョブキューにある程度ジョブを送信してから、ある程度の量がキューイングされることで最適化されるために、即時実行をしたいケース向かないことは注意が必要です。

管理しやすさに関してLambdaとBatchではログの出力先が制限される一方、ECSにはログドライバーがあって柔軟にログの出力先を指定できるので、他の2者に比べてログ管理の優位性が高く、運用する上でのメリットと言えます。ECSではタスクの一元管理ができるため、実行中の複数タスクをリアルタイムで監視することができる点に関しても優れた点であると言って良いでしょう。

大規模のバッチを捌くには?

Lambdaに色々な制約があるのは上記で見た通りですが、バッチに特化しており大量リクエストにも対応できるAWS Batchに関しては、公式が挙げているユースケースとして、数十万のバッチおよび機械学習 (ML) コンピューティングジョブで、金融やライフサイエンス分野のゲノム分析などのユースケースとしてあげており、一般のアプリケーションで使うにはオーバースペックとなったり、前述の通り即時実効性に欠ける点はバッチを動かす上でデメリットであると言えます。こういった点を考慮して筆者は、大規模バッチを設計するケースでBatchやLambdaではなくECSを第一のリソースとして使っていくことを選んだため、以下にその理由を述べていきます。

まず、バッチは常に時間通り動かしておきたいからです。タイムアウトを起こして実行が不完全になったり、時間通りに処理が行われないようなことは避けたく、顧客影響を考えるとバッチを安定に稼働させることの優先度は高いです。仮にバッチが失敗したとしても、ECSではタスクの一元管理が可能で、バッチの数が大量にあっても可視性は担保でき、StepFunctionsとも連携させることによって失敗したジョブをすぐにリトライができます。Lambdaではインフラリソースおよびアプリ側のカスタマイズ性が低いこともあり、ECSを使うことでバッチ処理で使う技術を自由に選べるメリットを享受することで、技術的な縛りといったLambda特有の問題にリソースを割かず本筋のアプリ開発に時間をかけられることも良い点かなと思いました。例えば、Lambdaで使える言語/ライブラリの縛りがあること、EOLが頻繁に来ることで改修を迫られたり、ECRを介してコンテナを使うとしてもまだ一工夫が必要だったり、Lambda特有の実装を行う必要がある部分について、特にAWSが最近サポートし始めた機能に関しては個人的にはまだ使用が途上の感覚があります。

運用面は、3rdパーティの監視ツールで効率よく全体の監視をしつつ、詳細についてはAWS標準のCloudWatchではコンソールで適宜ログを見るように棲み分ければ、効率よく実行状況や問題を検知できるため、バッチの数が多く、仮に一部失敗してもスピーディな対応が可能だと考えます。

アプリ側で処理速度を上げる工夫

もちろん、インフラ側だけではなく、DBおよびアプリ側でも処理効率の最適化は必要で、
バッチではデータ処理がメインなのでその辺りのボトルネックをまず減らしたいかなと思います。

著者の知見で、すぐに思いつくような実装の内容は以下の通りですが、インデックスやストアド、並列処理あたりは気軽にやりやすいと思うので積極的に活用しようと思います。

・(もしある場合)スロークエリを見つけて削減
・パーティショニングでデータを複数分割
・インデックスを張ってデータ検索を高速化
・ストアドプロシージャを使って通信量削減
・並列/非同期処理を行うことで処理時間短縮

主な参考記事(リファランス)

https://aws.amazon.com/jp/batch/
https://aws.amazon.com/jp/blogs/news/aws-batch-best-practices/
https://techblog.timers-inc.com/entry/2019/08/06/aws-batch-lambda-ecs-comparison
https://zenn.dev/faycute/articles/fb310e3ccd783f#複数ジョブの制御
https://qiita.com/kazuktym/items/0ecc1dbf98c3c3623473

Discussion