バッチ処理をECSからAWSBatchに乗り換えた理由

こんにちは、GMOメイクショップの越川です。 次世代ECの管理画面で工夫した機能CSV出力に関して、悩んだ部分や解消方法についてまとめてみました。

CSV機能について

弊社のサービスでは、多数のCSV出力をする必要がありますが、旧システムではオンラインで処理されるため 応答時間が長くなってしまっていたり、指定可能な範囲が短すぎたり、限界がきておりました。 次世代ECでは、件数や範囲に応じて、オンラインで応答する場合と、バッチで実行する場合を使い分けるように設計いたしました。

当初の計画

以前のブログでもご紹介させていただきましたが、次世代ECでは、ECSのコンテナを多数使って運用しております。 今回新設するCSVのバッチに関しても、当初はECSで動かすことを考えていました。簡単に図解しますと、以下の通りです。

machineryという非同期処理のフレームワークを使用して、 オンライン側からSQSにメッセージ送信することで、非同期のバッチ処理を実現しようと考えました。

github.com

課題

処理に関しては、当初のECS案でも問題なく、実現できていましたが、 バッチ処理が実行中に、ECS(Fargate)のタスクを新しいバージョンにローリングアップデートするケースに問題がありました。 Fargateのコンテナが強制終了されるまでの待機時間が120秒までしか伸ばせず、実行中のバッチが中途半端な状態で止まってしまうことがありました。

docs.aws.amazon.com

解決案①

AWS CodeDeployを使用し、ローリングアップデートから、ブルーグリーンデプロイに変更して、 旧タスクを数時間程度活かしておくことをまず考えました。

これなら、旧タスクを活かしておく時間を調整できるので、想定外のCSVがダウンロードされなければデプロイ問題は解消できそうでしたが、 そのタスクを活かしておく時間のデプロイができなくなったり、SQSを新用、旧用で用意する必要がありそうだったり、 まだ課題の残るものとなりました。

解決案②

ECSでやりきるのは難しそうだったので、AWSBatchの使用も検討しました。

  1. AWSBatchのデプロイはジョブ定義を更新する
  2. ジョブ定義のリビジョンはカウントアップされる
  3. オンラインの処理からは、ジョブ定義のみ指定し、リビジョンは指定せず常に最新バージョンを指定する形で実行する

この形なら、デプロイ時に実行中のタスクは旧タスクが利用され、バッチ側のデプロイが完了した次からの実行は 最新のバージョンが使用できるようになりました。

デプロイは問題なさそうなので、AWSBatchで運用することを決めました。

ローカル環境

localstackでエミュレートしてローカル環境にAWSBatchの環境を作ろうと思いましたが、 お求めやすくはなかったので、断念しました。

docs.localstack.cloud

ローカルのオンラインから、ElasticMQにキュー登録された時に、 バッチ用のコンテナを立ち上げる処理をGolangで用意して、 なんちゃってAWSBatch風のものを作成し、ローカルで活用しています。

まとめ

弊社でのバッチ処理の概要をご紹介させていただきました。 AWSでは、同じようなことができる機能が複数あります。 今回のバッチでも、ECS、EC2、Lambda、Glue、Batchなどが候補になり得たと思います。

適切なサービスを選択できるように、アンテナをはっておきつづけたいと思いました。