AWSを使い始めた頃、コンピューティングサービスの選択で毎回迷っていた。「とりあえずEC2でいいか」という判断を何度かしたが、後から運用コストの高さや過剰なスペックに気づいて後悔したことがある。EC2・Lambda・ECSはそれぞれ特性がまったく異なり、ユースケースに合わない選択をするとコストと運用負荷の両方が跳ね上がる。
本記事では、3つのサービスの特性を整理し、実務でどう判断しているかを解説する。
3つのサービスの特性比較
| 比較項目 | EC2 | Lambda | ECS(Fargate) |
|---|---|---|---|
| 起動速度 | 数分 | ミリ秒〜秒 | 秒〜数十秒 |
| 課金単位 | 時間(インスタンス稼働時間) | 実行時間(100ms単位) | vCPU・メモリの使用時間 |
| スケール | 手動or Auto Scaling | 自動(同時実行数) | タスク数で自動スケール |
| 最大実行時間 | 無制限 | 15分 | 無制限 |
| サーバー管理 | 必要(OS・パッチ) | 不要 | 不要(Fargate使用時) |
| 主なユースケース | 汎用サーバー・既存移行 | イベント駆動・短命な処理 | コンテナワークロード |
コスト面でいえば、処理が発生しない時間帯が多い場合はLambdaが圧倒的に有利だ。EC2は起動している間ずっと課金され続けるため、使用率が低いと非常に割高になる。
「とりあえずEC2」をやめた理由
EC2は「何でもできる」が故に選ばれやすい。OSにSSHで入れる安心感、使い慣れたLinuxコマンド、既存のデプロイスクリプトがそのまま動く——この柔軟性は魅力的だ。
しかし、EC2を選ぶということは次の運用コストも引き受けることになる。
- OSのパッチ適用・セキュリティアップデート
- 稼働していない夜間・休日も課金
- スケールアップが手動またはAuto Scaling設定が必要
- インスタンスが落ちたときの自動復旧の仕組みを別途構築
以前、社内ツールのバックエンドをt3.mediumで動かしていたが、実際の使用率は平均5%以下だった。その後Lambdaに移行したところ、月額コストが約80%削減された。
EC2が本当に向いているのは「長時間かつ高負荷で動き続けるワークロード」か「既存システムのリフトアンドシフト」だ。新規開発でEC2から始める理由は、今やほとんどない。
Lambdaに向いている処理・向いていない処理
向いている処理
- イベント駆動の処理: S3にファイルがアップロードされたら変換する、DynamoDBのストリームを処理する
- API Gateway + Lambdaのサーバーレスバックエンド: リクエスト数が読めないサービスのAPI
- 定期バッチ処理: EventBridge(CloudWatch Events)でcronトリガーする夜間バッチ
- 軽量なWebhookエンドポイント: Slack通知やGitHub Webhookの受け口
import json
import boto3
def handler(event, context):
# S3イベントを受け取って処理する例
s3 = boto3.client('s3')
for record in event['Records']:
bucket = record['s3']['bucket']['name']
key = record['s3']['object']['key']
print(f"Processing: s3://{bucket}/{key}")
# ... 処理ロジック
return {'statusCode': 200, 'body': json.dumps('OK')}
向いていない処理
- 15分以上かかる処理: タイムアウト上限が15分のため、長時間バッチには使えない
- コールドスタートが問題になるリアルタイム処理: 初回起動時の遅延(数百ms〜数秒)が許容できない場合
- 大量のディスクI/Oが必要な処理: 一時ストレージは512MB〜10GBに制限される
- 常時接続が必要なWebSocket: 接続を維持するサーバーとしては不向き
コールドスタート問題は「Provisioned Concurrency」で緩和できるが、コストが上がる。その場合はECSの方がトータルで安くなるケースもある。
ECS(Fargate)をコンテナ実行基盤として選ぶ条件
ECS + Fargateは「Lambdaでは制約が多すぎるが、EC2のサーバー管理はしたくない」という場合に最適だ。
Fargateを選ぶ条件
- 実行時間が15分を超えるが、常時起動は不要: 数時間かかるデータ処理バッチ
- コンテナ化されたアプリをそのまま動かしたい: Dockerイメージがあればそのまま移行できる
- スケールアウト・インを柔軟にコントロールしたい: タスク数の自動スケールが細かく設定できる
- 複数コンテナを組み合わせたい: サイドカーパターン(アプリ +ログエージェント等)
ECSのタスク定義は次のようなJSONで定義する。
{
"family": "my-batch-task",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "512",
"memory": "1024",
"containerDefinitions": [
{
"name": "batch-processor",
"image": "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/my-batch:latest",
"essential": true,
"environment": [
{ "name": "ENV", "value": "production" }
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/my-batch",
"awslogs-region": "ap-northeast-1",
"awslogs-stream-prefix": "ecs"
}
}
}
]
}
実務での判断フロー
実際のプロジェクトでは、次の質問を順番に考えて選択している。
Q1.処理時間は15分以内に収まるか? →NoならLambdaは除外。EC2 or ECSを検討。
Q2.イベント駆動で、処理が発生しない時間が長いか? →YesならLambdaが最有力。コスト効率が大幅に改善する。
Q3. Dockerコンテナで動かしているか、またはコンテナ化できるか? →Yesで常時起動が不要ならECS(Fargate)が適切。
Q4.既存のサーバーアプリをそのまま動かしたいか?(リフト&シフト) →YesならEC2が現実的な選択。ただし中長期でコンテナ化を目指す。
Q5.高い同時接続・低レイテンシが要求されるか? →ECS(常時起動タスク)かEC2を検討。Lambdaのコールドスタートを避ける。
治験システムのコンピューティング選定——「いつ動くか」と「どう落ちるか」で決めた
医療系スタートアップで治験管理システムのインフラを再設計したとき、EC2・Lambda・ECSの3択は「コスト」より「動作特性」を軸に考えた。
治験システムのワークロードは大きく2種類に分かれる。「モニタリングサイトのWeb UI・API」という常時リクエストを受け付けるものと、「EDCからのデータ取り込みバッチ」という日次で数分〜数十分動くものだ。
Web UIとAPIはECS(Fargate)を選んだ。コンテナで動かしており、スケールアウトが必要なタイミングも読めない。EC2では常時費用がかかり、Lambda ではリクエストのハンドリングが複雑になる。ECSのサービスとして複数タスクを立てることで、タスクが落ちても自動で再起動する仕組みも手に入った。
バッチ処理はLambdaを選んだ。1回の実行が5〜10分程度で、1日1〜2回しか動かない処理にEC2を24時間起動しておくのはコスト的に合わない。15分制限のLambdaで収まることを確認した上で移行した。
このとき一番考えたのが「落ちたときどうなるか」だ。ECSはタスクが落ちると数十秒で復旧するが、その間のリクエストが失われる可能性がある。治験システムでは「被験者データが消える」事態は許容できないため、ALBのリトライ設定とアプリ側の冪等性(同じデータを2回書き込んでも安全な設計)を徹底した。
まとめ
3つのコンピューティングサービスの使い分けを一言でまとめると次のとおりだ。
- Lambda: 短命・イベント駆動・コスト最優先
- ECS(Fargate): コンテナ・長時間実行・サーバー管理不要
- EC2: 長時間高負荷・既存移行・柔軟なカスタマイズが必要
「とりあえずEC2」ではなく、ワークロードの特性から逆算してサービスを選ぶ習慣をつけると、コストと運用負荷の両方を最適化できる。