大してアクセスないサイトにECSはオーバースペック
概要
私が業務で触ったシステムは全部ECSでホスティングされています。ECSは動いてる間中ずっと課金されます。しかしlambdaはリクエスト~レスポンス構築完了 の時間しか課金されません。よって大してアクセス数がないサイトや、CloudFrontのキャッシュが効きまくるサイトはECSが暇をしている時間が長いことになり、オーバーパワーです。その時間課金されないlambdaで作れば安いことになります。lambdaなんかで複雑なサイトが作れるかよという話になりますが、aws amplifyなどを使えばモダンなフレームワークで作ったアプリを勝手にlambdaでデプロイしてくれるため、そんなに遠い夢ではありません。そこで今回はaws lambdaとECSの料金を比較し、損益分岐点を探してみます。
想定するwebサービス
ニュースサイトのような、記事が読めて楽しいね、みたいなサイトを想定します。
3Dモデルや動画ファイルみたいな重いファイルはない、ルート検索や検索のような重い処理もない、ゲームのようなリアルタイム性もない、といった計算量的には楽なサイトです。もし例に挙げたようなきつめの要求があるなら、計算がそこそこ必要なのでlambdaとかは選択肢にも上げないほうがいいと思います。
それぞれの構成
lambda
lambda関数1個しか呼び出されないものとします。aws amplifyでデプロイしたときどのような形のlambdaがデプロイされるかはわかりませんが、以下の理由から1個だけということにします
- 私が業務で携わっているwebサービスではサブプロセスを使っていない
- 重いファイルも複雑な処理も必要ない
そのほかのパラメータは以下とします。
パラメータ | 値 | 理由 |
---|---|---|
CPUアーキテクチャ | Arm | x86より安いから |
実行秒数(s) | 3 | 先人の経験則。応答時間がこれ超えたら使ってくれる人が激減するらしいので、何としてもここまでに収めるとする。 |
メモリ(GB) | 2 | 今仕事で携わってるシステムの半分の量。そっちはFargateなので並列にレスポンスをさばいている。lambdaは複数呼び出されたら複数個立ち上がるので、1リクエスト処理するだけでいい=並列処理する分のメモリはいらない |
エフェメラルストレージ(GB) | 10 | lambdaに指定できる最大値。かなり余裕を持っている |
ECS
コンテナ1個で固定とします。
オートスケールするのがECSのいいところですが、オートスケールするほど負荷が高いシステムならlambdaと比較する必要はありません。どう考えてもECSをそのまま使ったほうがいいです。
そのほかのパラメータは以下とします。
パラメータ | 値 | 理由 |
---|---|---|
CPUアーキテクチャ | Arm | x86より安いから |
vCPU(単位なし) | 1 | 今仕事で携わってるシステムと同じ量 |
メモリ(GB) | 2 | 今仕事で携わってるシステムと同じ量 |
料金の計算
計算1:計算リソースの料金だけ比較
まず純粋に計算リソースを何で作るかだけ比較します。ECSならAPI GatewayとかNAT Gatewayとかいろいろ課金されるし、lambdaもapi gatewayに課金されます。簡単のためそれらを無視し、lambdaとecsの利用料金を比較します。
lambdaの料金は計算時間*(確保するメモリ*メモリあたりの料金+確保するストレージ*ストレージ当たりの料金)
で計算できます(リクエスト数に応じても課金されますが、月100万リクエストまで無料なので計算に含めません)。また、lambdaには無料枠があり、1 か月あたり 40 万 GB 秒のコンピューティング時間
が無料で使えます。よって確保するメモリ*計算時間 から40万GB秒を引いて料金を計算します。
上のパラメータで計算してみると以下のようになります。
アクセス数(アクセス/月) | 計算された料金(USD/月) |
---|---|
10000 | 0.01 |
100000 | 2.78 |
200000 | 10.89 |
300000 | 19.00 |
400000 | 27.11 |
500000 | 35.22 |
1000000 | 75.78 |
ECSの料金は起動時間*(確保するvCPU*vCPU当たりの料金+確保するメモリ*メモリあたりの料金)
で計算できます。こっちは初年度以外無料枠がありません。上のパラメータでこちらも計算すると以下のようになります。(aws pricing calcuratorで計算しました)
単位変換管理イベント
タスクまたはポッドの数: 1 /日 * (730 時間 (1 か月) / 24 1 日の時間数) = 30.42 /月
平均期間: 1 days = 24 hours
料金の計算
30.42 タスク x 1 vCPU x 24 時間 x 0.04045 USD /時間 = 29.53 USD vCPU 時間用
30.42 タスク x 2.00 GB x 24 時間 x 0.00442 USD/GB/時間 = 6.45 USD GB 時間用
20 GB - 20 GB (追加料金なし) = 0.00 タスクあたりの GB 請求可能エフェメラルストレージ
29.53 USD vCPU 時間用 + 6.45 USD GB 時間用 = 35.98 USD 合計
これを見ると、計算リソースへの課金だけなら50万アクセス/月程度が損益分岐点ということになります。さらにこれはキャッシュが一切効かない環境での話です。もしキャッシュヒット率が50%あるなら、損益分岐点は100万アクセス/月ということになります。ちなみに私の携わっているサービスのキャッシュヒット率はもっと高いです。
lambdaの料金の途中計算
1ドル160円としている(私の人生最大値付近で計算しやすい値)
アクセス数/月 | メモリ(GB/秒) | ストレージ(GB/秒) | 計算された料金(USD/月) | 計算された料金(円/月) | aws pricing calcuratorの回答(USD) |
---|---|---|---|---|---|
10000 | 60000 | 300000 | 0.01 | 2 | |
20000 | 120000 | 600000 | 0.02 | 4 | |
30000 | 180000 | 900000 | 0.03 | 5 | |
40000 | 240000 | 1200000 | 0.04 | 7 | |
50000 | 300000 | 1500000 | 0.06 | 9 | |
60000 | 360000 | 1800000 | 0.07 | 11 | |
70000 | 420000 | 2100000 | 0.34 | 55 | |
80000 | 480000 | 2400000 | 1.16 | 185 | |
90000 | 540000 | 2700000 | 1.97 | 315 | |
100000 | 600000 | 3000000 | 2.78 | 444 | |
200000 | 1200000 | 6000000 | 10.89 | 1742 | |
300000 | 1800000 | 9000000 | 19.00 | 3040 | |
400000 | 2400000 | 12000000 | 27.11 | 4338 | |
500000 | 3000000 | 15000000 | 35.22 | 5635 | |
600000 | 3600000 | 18000000 | 43.33 | 6933 | |
700000 | 4200000 | 21000000 | 51.44 | 8231 | |
800000 | 4800000 | 24000000 | 59.55 | 9529 | |
900000 | 5400000 | 27000000 | 67.67 | 10827 | |
1000000 | 6000000 | 30000000 | 75.78 | 12124 | 75.72 |
2000000 | 12000000 | 60000000 | 156.89 | 25102 | |
3000000 | 18000000 | 90000000 | 238.00 | 38080 | |
4000000 | 24000000 | 120000000 | 319.11 | 51057 | |
5000000 | 30000000 | 150000000 | 400.22 | 64035 | |
6000000 | 36000000 | 180000000 | 481.33 | 77013 | |
7000000 | 42000000 | 210000000 | 562.44 | 89990 | |
8000000 | 48000000 | 240000000 | 643.55 | 102968 | |
9000000 | 54000000 | 270000000 | 724.66 | 115946 | |
10000000 | 60000000 | 300000000 | 805.77 | 128923 | |
20000000 | 120000000 | 600000000 | 1616.87 | 258700 | |
30000000 | 180000000 | 900000000 | 2427.98 | 388477 | |
40000000 | 240000000 | 1200000000 | 3239.08 | 518253 | |
50000000 | 300000000 | 1500000000 | 4050.19 | 648030 | |
60000000 | 360000000 | 1800000000 | 4861.29 | 777807 | |
70000000 | 420000000 | 2100000000 | 5672.39 | 907583 | |
80000000 | 480000000 | 2400000000 | 6483.50 | 1037360 | |
90000000 | 540000000 | 2700000000 | 7294.60 | 1167136 | |
100000000 | 600000000 | 3000000000 | 8105.70664 | 1296913 |
計算2:付随するリソースの料金も含めて比較
しかし計算リソースだけではwebサイトをホスティングすることはできません。上では計算量のみを比較するためにコンテナを1つとしましたが、ECSならコンテナが複数あるのが普通であり、その場合ルーティングを行うALBを設置する必要があります。lambdaではapi gatewayがないとインターネット経由でlambdaを呼び出せません。これらの料金をシンプルに加算して比較してみましょう。
API Gatewayは100万アクセスでも月1.29USDくらいです。アクセス数が少なければもっと安いですが、簡単のために全部この金額がかかることにします。
512 KB/リクエスト / 512 KB リクエストの増分 = 1 リクエスト
RoundUp (1) = 1 請求可能なリクエスト
1 1 か月あたりのリクエスト x 1,000,000 単位乗数 x 1 請求可能なリクエスト = 1,000,000 請求可能なリクエストの合計
Tiered price for: 1,000,000 リクエスト
1,000,000 リクエスト x 0.00000129 USD = 1.29 USD
合計階層コスト = 1.29 USD (HTTP API リクエスト)
HTTP API リクエストのコスト (毎月): 1.29 USD
2025/9/16 追記)API Gatewayは必須ではない
ここでAPI Gatewayが必須かのように書いていますが、これは誤りでした 🙇
API Gatewayを使わなくてもlambdaをインターネット経由で呼び出す方法を教えてもらいました。Lambda Function URLsを関数に設定すればAWSの用意したURLでインターネットに公開できます。(さらにCloudFrontを経由するなら、CloudFrontのOriginをFunction URLのURLにし、CloudFrontの代替ドメインに自分のURLを設定することで、任意のURLで公開できます。)
ALBは存在するだけでUSD 0.0243/Application Load Balancer/時 かかります。月に直すと17.74USDとなります。通信量に応じてもっとかかりますが、通信量は想像がつかないので一旦お金がかからないものとします。
これをシンプルに足してみると表は以下のようになります。
アクセス数(アクセス/月) | 料金(USD/月) |
---|---|
10000 | 1.30 |
100000 | 4.07 |
200000 | 12.18 |
300000 | 20.29 |
400000 | 28.40 |
500000 | 36.51 |
700000 | 52.73 |
1000000 | 77.07 |
ECS
35.98+17.74=53.72 USD
損益分岐点は70万アクセスくらいになりました。キャッシュヒット率0%での話です。かなりlambdaが安く見えますね。
結論
- (当然だけど)アクセス数が少ないうちはlambdaが安く、アクセス数が上がるとECSが安い
- 同じインスタンスサイズでさばければの話
- この設定だと損益分岐点は50万アクセス/月
- キャッシュヒット率が上がるほどさらにlambdaが安い
- 意外とそこそこの規模のサイトでもlambdaのほうが安いのではなかろうか
月100万アクセスあってもキャッシュヒット率50%でlambdaが勝ちます。月10万アクセスくらいならECS使うな。
じゃあ以後うちのプロジェクトは全部lambdaで作ろう
そういうわけにはいきません。これまでweb開発をやっていた人たちはサーバーにデプロイしてnginxやapacheでリクエストを受け付けていたものです。それがコンテナになるのはまだこれまでの延長線上にありますが、lambdaは理の外にあります。作り始めたらどんな問題が起きるかわかりません。私自身もlambdaで全部システムを構築したことがないエンジニアの一人です。lambdaでサービス全部作るなんてバカだぜという知見を持っている方は教えてください。
すぐ思いつく範囲でも以下のような問題があります。考えるよりやってみたほうが早そう。ちゃんと時間かけて個人サービス作ったよ~という人は教えてください。私もやる気が出たら実験します。
- 純粋にlambdaで作るときに美しくモジュール分割できなそう
- amplifyを信じていいのか?
- RDB使えない
- VPCにlamdba置いてRDS建てましょう。IG分余計にお金とられるけど
- RDSよりsqlite on efsのほうが安いらしいです
- できればDynamo使えると無料枠があるのでさらに安上がりです
Discussion
ここで Lambda Function URLs が最初から選択肢に入っていないのは何か理由があるのでしょうか?
(文脈を掴めていなかったらすみません…)
普通に知りませんでした。API Gateway使わなくてもパブリックアクセスができると追記しておきます。
知見ありがとうございます🙇
うちは会社の方針で可能な限り Web サイトには Lambda を採用する方針となっています。(もう10年くらい?)
Lambda で Web サイトをホストできるか?の一番の判断のポイントは「Cold Start が許容できるか」です。ECS では常時起動になりますが、Lambda では Cold Start があります。(Lambda はコンテナと違い複数リクエストを1コンテナで受ける、みたいなことができないのでこれは Provisioned Concurrency 等を用意していても基本避けられないと考えたほうがいいです。めちゃめちゃリクエストがあるなら別ですが) ランタイム自体の起動時間は多くの場合無視できますが、アプリケーション自体に起動時に時間のかかる処理が必要な場合、もしくは起動に数秒かかってしまうほど大規模なアプリケーションな場合、Lambda は諦めることになります。
しかし Cold Start の問題がクリアできれば、Lambda は驚くほどスムーズに Web バックエンドとして機能してくれます。前段は API Gateway でもいいですし、Function URL + CloudFront でも OK です。最近は VPC Lambda も癖無く動いてくれます。
Lambda をうまく使うコツは、「Function だからと言ってむやみに責務を複数の Lambda に分けない(界隈では Lambdalith という名前で知られています)」「できる限り Cold Start(起動時間)を速くするよう意識してコードを書く」「RDS に直接繋がない(RDS Proxy や DSQL を検討する)」「メモリキャッシュはできる限り使わない」あたりでしょうか。
あと最新の Next.js は正直現状 Lambda だと微妙なので、OpenNext で Cloudflare に上げたほうが体験はいいです。(この数か月で改善されていたらすみません)
会社単位でlambda使ってるところもあるんですね!社内で提案する勇気が湧いてきます
確かにコールドスタートの問題がありましたね。前Django乗せる方法あるじゃん!と思って起動遅いって書いてあってやめた記憶がよみがえってきました
知見をありがとうございます🙇
弊社で直近でやった案件では React SPA + Lambda + DSQL(最近 GA されたやつ)で構築しました。DSQL は RDS と違い常時起動ではない PostgreSQL 互換の DB (一部制約あり)で、 リクエスト単位の動作(起動も一瞬)なので DB の稼働も節約できる(無料枠もあって、場合によってはかからない)構成です。
担当者数人しか使わない、極めて小規模な業務アプリの受託開発でした。それほどアクセスも高頻度でなく、データ量もそこまでなので、この場合インスタンスのランニングコストは当分かからない可能性もあります。小さい規模だとそれほど Cold Start も気にならない(Hono が薄いのもある)ですし、UIの工夫次第で感じ方を軽減できる可能性はあると思います。
ただし、Lambda と CloudFront を直接繋ぐ際、リクエストボディのハッシュ値を
x-amz-content-sha256
ヘッダーとして渡す必要があります。これらの解決を Lambda@Edge で行ったり等の多少の工夫が必要になります。私が前提としている詳しい構成や設定方法等は、(私の友人が書いた著書ですが)以下の本をご参照ください。Pulumi による IaC まで含んでいます。ご参考までに。
apprunnerはどうですか? 以前会社で小規模アプリを構築するときに採用しました。ECSより手軽に構築できますが、ECSほど細かく設定することはできない感じなので、スモールスタートに良い印象でした。費用感の比較はしていないので、参考までに🙏
Lambda良いですよね!!!個人的にはAPI Gatewayと組み合わせてWebSocketを作れるところが好きです。
Lambdaを置くのがPrivate Subnet, Public Subnetに関わらず、IGWのみで外部ネットワークに接続することはできません。NATインスタンスを使うのが定石ですが、コストを極限まで抑えるのであればLambdaにEIPをアタッチする方法もあります。 外部APIを叩くなどしなければ、そもそも不要ですが…(リクエストを受け付けることはできる)
RDBに関してはAWS縛りがなければ、SupabaseやD1などに逃がしてしまうのが手っ取り早い気がします。
わかりやすい記事をありがとうございました。
lanbda web adapterというライブラリを用いることで、webサーバに限ってはコンテナと同等の負担でlambdaデプロイが可能になります。
こちらの記事が大変わかりやすいので、ご参考にしていただけると嬉しいです。
Lambda良いですよね。私も大好きで、Lambdaで完結しているWebシステムもいくらかあるので少しコメントさせて頂きます。
「モダンなフレームワークを使えば勝手にLambdaでデプロイしてくれる」と書かれていますが、私の場合はLaravelを使うことが多いので、そのときはLaravel Vaporを使ってデプロイします。長いものだともう5年以上経ちますが、非常に安定して動いてくれています。
お金のかかり方は構成によってかなり違いますよね。
記事でも書かれていますが、DynamoDBで済ませるようなケースもあり、その場合は固定費はほとんどかかりません。外部サービスではありますが、Tursoのようなサービスが利用可能であれば、固定費のほぼかからないRDBとの組み合わせも作れるかもしれません。
一方でRDSを組み合わせると、RDSやらNATゲートウェイやらで途端に固定費が嵩みます。こちらのパターンは相当な規模までいかないとLambdaの費用が固定費を超えることはない印象です。こちらの場合、小規模だとVPS1台で済ませたりする方がずっと安上がりなので、必ずしもコスト的なメリットはありません。ですが個人的には、インフラのメンテから解放されるだけでも結構大きいと思っています。
複数のLambda関数の組み合わせについては、一般的にはLambdaからLambdaの直呼び出しはアンチパターンと言われていますが、現実的には同期処理したいことも多いので私は結構やってしまいます…。
正直Cloudflare Workersを使いたいシーンもあるんですけどね…ネットワーク待機中は課金されないのとか魅力的ですし。ですがそれを差し引いても、Lambdaの自由度はとても魅力的です。