こんにちは! Agoと申します。
今回は問題が発生していたシステムをStepfunctionとECSで構成したことで問題解決できた内容及び、構成する上で詰まった点等を共有させていただきたいと思います。
読む時間が無い方にも要約(TL;DR)を載せてありますのでそちらだけでも読んでいただけると幸いです。
TL;DR
- AWS Batch + EC2でZipファイルを解凍して配置するシーケンシャルな構成だった
- 旧システムの仕組み上、大容量のZipを配置しようとすると、次の定期実行までに終わらず、ファイルが配置できない問題が発生していた
- EventBridge + Stepfunctions + ECSでイベントドリブンな構成をすることで問題が解決した
- StepfunctionでECSを選択する場合、かんたんに後続処理に値を渡すことができない
- StepfunctionsでECSに渡した入力データをそのまま取得して後続処理に渡す力技で対応を行った
前提
旧システムはzipファイル配置バケットから対象となる30件ずつリスト化し、RDSに保存するジョブとRDSの配置リストを元に30件ずつzipを展開して指定バケットに配置するジョブが別れており、それぞれ定期実行で動くシーケンシャルな構成でした。
下記が以前のインフラの構成図になります
以前までは1つのZipファイルの容量はおよそ50MB〜3GBが主でした
また、一日のZipの配置数は約1000件ほどありました。
抱えていた問題
- Zipファイルの肥大化
旧システムの仕組み上、Zipの解凍及び展開jobで従来のZipファイルのサイズよりも大きいZipファイルが対象となった場合、定期実行処理のシーケンスに間に合わなくなり、その定期実行処理で拾われた30件のZipファイルがいつまでも配置されない問題が度々発生する様になりました。
つまり、今回のケースのように、シーケンシャルな構成だと、大容量のZipファイルが置かれた場合に耐えられない構成になっていました。
解決方法
上記問題を解決するために下記の構成で解決を検討しました。
- Event Bridge + Stepfunctions + lambdaを使ってS3にZipが配置されたタイミングで1件ごとにZipファイルを処理するイベントドリブンな構成
しかし、この構成だと10GB以上のZipファイルが配置された場合にlambdaの処理制限時間の15分に間に合わないことが判明したため、断念をしました。
そこで、大容量のZipファイルを処理するために下記の構成にすることで、時間制限なく大容量のzipファイルを処理することに成功しました。
- Event Bridge + Stepfunctions + ECSを使ってS3にzipが配置されたタイミングを検知し、1件ごとにzipファイルを処理するイベントドリブンな構成
つまずいた点
StepfunctionsでECSを行う構成で作成を行った際につまずいた点があるため、共有します
-
StepfunctionsにおいてECSの結果データをアプリコード内のreturnで後続処理に渡すことができない
lambdaだと、 下記のように設定することで、処理結果を後続処理に渡すことができますが、# 何らかの処理 return { "error_code": 0, "zip_path": "fugafuga.zip" }
## stepfunctionの出力結果 "Payload": { "error_code": 0, "zip_path": "fugafuga.zip" } ## 下記をstepfunctionの後続jobに記述することで後続処理に結果を渡すことができる "Parameters": { "error_code.$": "$..Payload.input.error_code", "zip_path.$": "$..Payload.zip_path" }
ECSだと、 アプリ内でreturnを記述してもoutputには出力されず、うまく後続処理に結果を渡すことができません。
今回のケースだと、ECSのあとにlambdaで処理を行う設定があったのですが、ECSに渡した入力データのまま出ていることがわかったので、その内容から必要な値をlambdaのeventに渡すという力技で対応を行いました。
# 出力結果をそのままlambdaに渡して、 lambdaのコード内で必要な値を取得するように設定 "Parameters": { "Payload.$": "$" }
終わりに
今回の改善によって得られたことは以下の通りでした。
- stepfunctionのjobの選択肢として、lambdaの処理制限に引っかかるのであればECSを選ぶのもあり
- ただし、lambdaのように後続処理に値を渡すことが容易ではないため、stepfunctionの定義する内容から取得する等、工夫する必要がある。