Serverless Doesn't Make Sense - YouTube の内容が興味深かったのでメモ。
- サーバーレス(今回のケースでは特に FaaS: Function as a Service) の最も大きな利点はスケーラビリティである。アクセス数が予測できなくとも、必要に応じて関数の実行環境が立ち上がるため、アクセスの急増に対応しやすい。
- 実行回数に応じて課金されるため、常時起動サーバーのような固定コストが発生しないことも利点である。コードが実行されていないときには、料金は発生しない。
- ところで、昨今のサービス開発では応答速度も非常に重要な観点である。例として Node.js で画像をリサイズするするコードを Google Cloud Functions にデプロイしたところ、平均実行時間が 2 秒前後だった。これは 2020 年の水準で考えると受け入れがたい遅さである。
- 当初 Node.js を使っているせいだと考えていたが、本当の原因は言語ではなく、FaaS における コールドスタート(Cold Start) だった。FaaS では関数を実行する前に Node プロセスの起動などの予備的処理が発生するが、これがコールドスタートの原因である。
- 一度環境が立ち上がると、一定時間プロセスは維持される。プロセスが維持されている状態で再度実行するときには、コールドスタートは発生しない。
- 今回の画像リサイズの例では、コールドスタートが 1 秒程度関数全体の実行時間を遅らせていた。Lambda の場合は AWS X-Ray を使うことで、コールドスタートの所要時間と関数本体の実行時間とを正確に把握できる。
- 各 FaaS におけるコールドスタートの所要時間について詳細に検証した記事が見つかった: Comparison of Cold Starts in Serverless Functions across AWS, Azure, and GCP | Mikhail Shilkov。これによれば Node.js は Python や Go と比較して極端にコールドスタートが遅いとは言えない。
- 各 Faas におけるコールドスタートの所要時間を比較すると AWS Lambda 一択であるように見える。特別な理由がなければ GCP や、特に Azure は採用しにくい。
- FaaS では関数に割り当てるメモリの容量を調整できる。メモリ容量を増やすと単位時間あたりの費用が上がるが、割り当てられる CPU 数も増えるため、実行時間が短くなる。したがって、コスト・実行時間のどちらを重視するかによるが、最適なメモリ容量(スイートスポット)が決定できる。
- ここまで見てきたコールドスタートの問題に対処するため、AWS Lambda では Provisioned Concurrency (プロビジョニングされた同時実行数と訳されている) という機能が存在する。あらかじめ決められた数のプロセスを用意しておき、コールドスタートを防ぐというもの。
- しかしここで大きな矛盾に突き当たる。そもそも FaaS やサーバーレスを採用する理由は、予想できないアクセス数に対して、スケーラビリティを気にすることなく開発が進められる点であるはずだ。それなのに、 Provisioned Concurrency のような機能を活用するには事前に必要なプロセスの数を検討する必要がある。それが事前にわかっているのであれば、わざわざサーバーレスを活用する必要は無い。FaaS にこだわってコールドスタートの解決に時間をかけるのは、ビジネスロジックに集中できるというサーバーレスの利点を放り出しているようなものである。
- 結論としては、 FaaS はコールドスタートを許容できるようなシーンでのみ活用の余地がある。コールドスタートの数百 ms が問題になるようなケースでは、 FaaS にこだわる必要はない。
- Cloudflare Workers はこの観点からは面白いサービスである。なんと公式が 0ms のコールドスタートを謳っている。リクエストごとに CPU 時間を 50ms しか使えないなど使い所を選ぶサービスではあるが、ニーズに合致すれば試す価値はあるだろう。