最近、LambdaからFargateに移行して、Node.js(NestJS)アプリの動作を最適化するためにタスクスペック(CPUやメモリの割り当て)についていろいろ試行錯誤しました。この経験を踏まえて、最適な設定を見つけるまでの流れを共有します。
Lambdaとの違い
最初はLambdaを使っていたんですが、リクエストごとに新しい環境が立ち上がり、リソースの競合がなくて快適でした。短い処理ならLambdaが効率的で、オートスケーリングも自動的に対応してくれていました。
でも、長時間稼働するバッチ処理や大量データの処理になると、Lambdaではコールドスタートやタイムアウト(30 s)が気になってきました。そこで、より柔軟なリソース管理ができるFargateに移行することに決めました。
Fargateに移行してみて: タスクスペックの試行錯誤
Fargateの強みは、CPUやメモリなどのリソースを自分で細かく設定できるところですが、これが逆に難しくもあります。Node.jsはシングルスレッドで動くので、どのくらいのリソースが最適なのかを見極める必要がありました。
1vCPU 2048MB の場合
まず試したのがこの構成ですが、Node.jsのデフォルトヒープメモリ制限にすぐに引っかかり、メモリ不足が頻発しました。大量データの処理では、ガベージコレクションが頻発してタスクが落ちてしまうことが多く、パフォーマンスがかなり不安定でした。
2vCPU 4096MB の場合
ここでメモリを倍にしてCPUも増やしたところ、パフォーマンスが大幅に向上しました。Node.jsのシングルスレッド特性を活かしながら、バックグラウンドの処理(ガベージコレクションや I/O 操作)が別のコアで処理されることで、全体的なスループットが向上しました。このスペックは、かなりいい感じで落ち着きました。
4vCPU 8184MB の場合
もっとリソースを割り当てればレイテンシーが下がるんじゃね?と思い、4vCPUに増やしましたが、これは失敗でした。Node.jsのシングルスレッドでは、余ったCPUリソースを有効活用できないため、逆にオーバーヘッドが増えてパフォーマンスが低下しました。リソースの過剰割り当ては無駄が生じるだけでなく、パフォーマンスを逆に悪化させることを学びました。
オートスケーリングの設定
Fargateを使う上で、タスクの数をどう増減させるかというのは非常に重要なポイントです。設定したタスクスペックは「2vCPU 4096MB」でしたが、このスペックにしてからオートスケーリングの効果が格段に感じられるようになりました。
2vCPU 4096MB に設定した利点
この構成を選んだ理由は、Node.jsのシングルスレッド処理に対して最適なバランスを取れることです。1vCPU だとメインスレッドがリクエスト処理に使われてしまい、ガベージコレクションや I/O 処理でメモリや CPU が圧迫され、結果的にパフォーマンスが低下していました。しかし、2vCPUにすることで、メインスレッドはリクエスト処理に専念し、バックグラウンド処理を別のコアで効率的にさばけるようになりました。
また、メモリも4096MBに設定したことで、ヒープメモリ不足によるタスク落ちが激減し、安定した稼働を実現できました。特に、メモリを大量に使用するリクエストやバッチ処理を扱う場合、このスペックが最適でした。
CPU使用率60%以上で1~10のタスクを増減
オートスケーリングの設定では、CPU使用率が60%を超えるとタスクを追加し、逆に60%を下回るとタスクを減らすルールを作りました。タスクの数は1〜10の範囲で動的に増減させています。
なぜこの設定にしたかというと、Fargate上のタスクが60%を超えるタイミングが一つの目安だったからです。60%を超えると、リクエスト処理が遅延し始める傾向があったため、あらかじめタスクを増やしてリクエストを分散することで、パフォーマンスを維持しています。
また、タスク数を10まで増やすことで、ピーク時の大量リクエストにも対応できるようにしました。逆に、タスクを1 で減らすことで、負荷が低いときにはコストを削減できるようにしました。この「1〜10」の範囲が、パフォーマンスとコストのバランスを取る最適な設定でした。
まとめ
Fargateに移行して感じたことは、Lambdaと違ってリソース管理を自分でコントロールする必要があること。そして、Node.jsアプリにおいては、リソースを過剰に割り当てると逆効果になることがある点です。適切なタスクスペックを見つけ、オートスケーリングを上手に活用することで、効率的にリソースを使いながら、コストも抑えることができるようになりました。