AWS Batchを使ってアプリケーションコードを書くことなくバッチの多重起動を防ぐ

記事概要

AG-Boostのtishiです。
インフラ領域である多重起動の制御のために極力アプリケーションのコードを書きたくなかったので、書かずに制御する方法を模索しました。 AWS Batchに多重起動を防ぐ機能はないため、無理矢理感はありますが実現できたので方法を紹介します。

AWS BatchのvCPUとジョブの実行の関係

AWS Batchでは、コンピュート環境に実行できるだけのvCPUの空きがあれば、キューに詰められたジョブが実行されます。
図のようにキューにジョブがいくつか詰まっており、最初のジョブのvCPUが1でコンピュート環境の空いているvCPUが3の場合、十分に空きがあるため実行されます。

初期状態
最初のジョブが実行される

コンピュート環境に十分な空きがない場合、キューのジョブは待ち状態になります。 ジョブが完了して、コンピュート環境内に空きができるとキューのジョブが実行されます。

十分な空きがない場合待ち状態になる
空きができるとキューのジョブが実行される

実現方法

この特性を利用してコンピュート環境のvCPUのサイズとジョブのvCPUのサイズを同じにすることで、一つづつジョブが実行されるようになり、多重起動を防ぐことができます。

ジョブが一つ実行される
空きがないため待ち状態になる

ただしいくつか注意点があります。

注意点

この方法では全てのジョブのvCPUサイズが同じ前提です。 サイズがまばらになると、複数のジョブが同時に実行されてしまう可能性があります。 そのためジョブによってサイズを変えたい場合、今回の方法は使えません。

コンピュート環境の最低vCPUのサイズが1なのに対して、ジョブの最低vCPUのサイズは0.5です。 なので最小のvCPUが0.5で足りるジョブだったとしても、多重起動を防ぐために1を設定する必要があります。

AWS Batchではキューを複数のコンピュート環境と紐付けることができます。 複数紐付けるとそれぞれのコンピュート環境でジョブが処理されて、ジョブの多重起動が起きる場合があります。 多重起動を防ぐための専用のコンピューティング環境を用意して、キューにはそのコンピューティング環境以外紐付けないでください。

また今回はFargateで検証したため、ECS on EC2でも可能なのか不明です。

余談1 同時実行数の制御

多重起動を防ぐ方法を応用すれば同時実行数の制御も可能です。 コンピューティング環境のvCPUサイズをジョブのvCPUサイズのn倍にすれば、同時実行数はnになります。

余談2 AWS Batch以外で実現できるか

AWSにはAWS Batchの他にバッチ処理ができる以下のサービスがあります。 1. Lambda 2. ECS これらのサービスでバッチの多重起動を防ぐことができるか考えたので軽くまとめます。

Lambda

Lambdaでは予約済同時実行数を1に設定することで、多重起動を防いで一つづつバッチが動く状態にできます。 パラメータを設定するだけで制御できるためアプリケーションコードを書く必要もありません。 また前段にSQSを置くことでSQS側の設定で多重起動を防ぐこともできます。 アプリケーションコードを書くことなく、バッチの多重起動を防ぐことはできますが、15分の実行時間の制限があるため注意が必要です。 軽量なバッチであればLambdaを使うのが良さそうです。

ECS

タスクの多重起動や同時実行数の設定ができないため、単体で多重起動を防ぐことはできません。 前段に同時実行数を制御するワーカーを配置することでできるかもしれません。 ただし、そのためにはワーカーのアプリケーションコードを書く必要があるため、今回の要件から外れてしまいます。 アプリケーションコードを書くことを許容できる場合は選択肢に入ってくるかと思います。

まとめ

今回はAWS Batchを使って、アプリケーションコードを書くことなく、バッチの多重起動を防ぐ方法を紹介しました。 AWSの方に相談したところ、同様の方法を試してみることを勧められたため、AWS Batchで多重起動を防ぐ場合は今回の方法が良さそうです。