
從「永遠在線」到「按次計費」:伺服器架構的典範轉移
在雲端運算出現之前,部署一個應用程式意味著購買或租用實體伺服器,24 小時運行、24 小時付費,不論有沒有人在使用。這個模型簡單直覺,但存在本質性的浪費——凌晨三點沒有流量時,伺服器仍然全速消耗資源。
雲端 IaaS(EC2、GCE)將硬體虛擬化了,但計費邏輯沒有根本改變:你啟動一台虛擬機,就開始按小時計費。真正的典範轉移發生在 2014 年 AWS Lambda 問世:不再為「伺服器運行時間」付費,而是為「程式碼實際執行時間」付費。這就是 Serverless 的核心理念。
但 Serverless 不是銀彈。它在某些場景下成本極低、開發效率極高,但在另一些場景下可能比傳統伺服器更貴、更難除錯。這篇文章完整比較三種主流架構——傳統伺服器、Serverless、Container-as-a-Service(CaaS),幫助你在不同場景下做出正確的選擇。
架構概覽
flowchart TD Start{{"流量特性?"}} -->|穩定高吞吐| Q1{{"需要長連線\n或有狀態?"}} Start -->|極低或極不穩定| Q2{{"已有 Docker Image?"}} Start -->|中等、可預測| Q3{{"團隊有 DevOps?"}} Q1 -->|是| Server["傳統伺服器\nEC2 / GCE\n完全控制 + RI 折扣"] Q1 -->|否| Q4{{"已有 Docker Image?"}} Q4 -->|是| CaaS["CaaS\nCloud Run / Fargate\n容器化 + 自動擴展"] Q4 -->|否| Server Q2 -->|是| CaaS Q2 -->|否| Serverless["Serverless\nLambda / Cloud Functions\n按次計費 + 縮至零"] Q3 -->|是| CaaS Q3 -->|否| Serverless Server ---|"適合:高吞吐 API\nWebSocket / 遊戲\nML 訓練"| S_note[ ] Serverless ---|"適合:事件驅動\nWebhook / 排程\nMVP 原型"| SL_note[ ] CaaS ---|"適合:微服務\n避免 Vendor Lock-in\n自訂 Runtime"| C_note[ ] style S_note fill:none,stroke:none style SL_note fill:none,stroke:none style C_note fill:none,stroke:none
架構比較總覽
flowchart LR subgraph Traditional["傳統伺服器架構"] direction TB Client1[Client] --> LB[Load Balancer] LB --> S1[Server 1\nEC2 / GCE] LB --> S2[Server 2\nEC2 / GCE] LB --> S3[Server 3\nEC2 / GCE] S1 --> DB1[(Database)] S2 --> DB1 S3 --> DB1 end subgraph Serverless["Serverless 架構"] direction TB Client2[Client] --> APIGW[API Gateway] APIGW --> F1["Function A\n(Lambda)"] APIGW --> F2["Function B\n(Lambda)"] APIGW --> F3["Function C\n(Lambda)"] F1 --> DB2[(Database)] F2 --> DB2 F3 --> DB2 F1 -.->|auto-scale\n0 → N| F1 end subgraph CaaS["Container-as-a-Service"] direction TB Client3[Client] --> CLB[Cloud Load Balancer] CLB --> C1["Container A\n(Cloud Run)"] CLB --> C2["Container B\n(Cloud Run)"] C1 --> DB3[(Database)] C2 --> DB3 C1 -.->|auto-scale\n0 → N| C1 end
傳統伺服器維持固定數量的實例;Serverless 以 function 為單位自動擴展(含縮至零);CaaS 則以 container 為單位,兼具容器化的靈活性與自動擴展能力。
核心概念解析
1. 傳統伺服器(EC2 / GCE / VPS)
傳統伺服器架構的特點是完全控制。你擁有作業系統、網路設定、磁碟配置的完整權限,可以安裝任何軟體、開任何 port、跑任何 daemon。
優勢:
- 完全控制運行環境,可以自訂核心參數
- 大規模穩定流量下成本可預測,搭配 Reserved Instance 更便宜
- 支援長時間執行的任務(無執行時間限制)
- 支援 WebSocket、gRPC 等有狀態連線
- 不受限於特定雲端供應商的 runtime
代價:
- 需要自行處理 OS patch、安全更新、監控告警
- 必須預估容量(capacity planning),低估不夠用、高估浪費錢
- 擴展速度受限於新實例啟動時間(通常數分鐘)
- 即使零流量,仍然持續計費
2. Serverless(Lambda / Cloud Functions / Azure Functions)
Serverless 的核心理念是「只管程式碼,不管基礎設施」。你上傳一個 function,平台負責部署、執行、擴展、維運。
優勢:
- 零維運負擔:不用管 OS、patch、scaling
- 按次計費:沒有請求就不收錢,適合低流量或流量極不穩定的場景
- 自動擴展:從 0 到數千個並行實例,毫秒級回應流量暴增
- 內建高可用:平台本身就是多可用區部署
代價:
- Cold Start 問題(後詳)
- 執行時間限制:Lambda 最長 15 分鐘、Cloud Functions 最長 60 分鐘
- 無狀態限制:function 之間不共享記憶體,必須靠外部儲存
- Vendor lock-in:程式碼綁定特定平台的 event 格式和 SDK
- 除錯困難:本地環境難以完全模擬雲端行為
3. Container-as-a-Service(AWS Fargate / Cloud Run / Azure Container Apps)
CaaS 是 Serverless 和傳統伺服器之間的中間路線。你提供一個 Docker image,平台負責執行和擴展。
優勢:
- 使用標準 Docker image,可攜性高
- 支援任意語言和框架(不受 runtime 限制)
- 可以縮至零(Cloud Run),也可以設定最小實例數
- 比 Lambda 更長的執行時間(Cloud Run 最長 60 分鐘,Fargate 無限制)
- 相對低的 vendor lock-in(Docker image 可以在任何平台跑)
代價:
- 需要自行建立 Docker image 和 CI/CD pipeline
- 成本通常高於純 Lambda(因為以 container 為計費單位)
- Cold Start 可能比 Lambda 更長(需要拉取和啟動整個 container)
Cold Start 問題深入解析
Cold Start 是 Serverless 架構中最常被討論的問題之一。當一個 function 一段時間沒有被呼叫後,平台會回收其執行環境。下一次請求進來時,平台需要重新配置環境、載入程式碼、初始化 runtime,這個過程就是 Cold Start。
Cold Start 的延遲組成:
- 容器配置(Container provisioning):50-200ms
- Runtime 初始化(Node.js/Python/Go):10-100ms
- 程式碼載入與相依套件初始化:50ms-數秒(取決於套件大小)
- VPC 網路介面配置(若有啟用 VPC):額外 1-10 秒
不同 Runtime 的 Cold Start 延遲(概略):
- Go / Rust:< 100ms
- Python / Node.js:100-500ms
- Java / .NET:500ms-5s(JVM 啟動和 class loading)
Cold Start 緩解策略:
- Provisioned Concurrency(Lambda):預先保持指定數量的 warm 實例,完全消除 Cold Start,但要為預留的實例持續付費。
- Keep-warm 定時觸發:每隔幾分鐘用 CloudWatch Event / Cloud Scheduler 發一個空請求,讓 function 保持 warm 狀態。成本低但不能保證在流量暴增時所有實例都是 warm 的。
- 最小實例數(Cloud Run):設定
min-instances為 1 或更多,確保始終有 warm 的 container 等待請求。 - 減少套件體積:使用 tree-shaking、layer、slim image 減少載入時間。
- 選擇輕量 runtime:Go 和 Rust 的 Cold Start 遠低於 Java。
計費模型比較
傳統伺服器計費方式
| 計費方式 | 說明 | 折扣幅度 | 適用場景 |
|---|---|---|---|
| On-Demand | 按小時/秒計費,隨開隨停 | 0%(基準價) | 測試環境、短期專案 |
| Reserved Instance | 預付 1-3 年,換取折扣 | 30%-60% | 長期穩定負載 |
| Spot Instance | 使用閒置容量,價格浮動 | 60%-90% | 可中斷的批次處理 |
| Savings Plan | 承諾最低用量,換取折扣 | 20%-40% | 有穩定基礎用量 |
Serverless 計費方式
以 AWS Lambda 為例:
- 請求次數:$0.20 / 百萬次請求
- 執行時間:$0.0000166667 / GB-秒(128MB 記憶體基準)
- 免費額度:每月 100 萬次請求 + 40 萬 GB-秒
成本試算範例
# === Serverless vs Traditional Server 成本比較試算 ===
# 情境:一個 API 服務,每月處理不同的請求量
# Lambda: 256MB 記憶體,平均執行時間 200ms
# EC2: t3.medium (2 vCPU, 4GB RAM) On-Demand = $0.0416/hr
def lambda_monthly_cost(requests_per_month: int) -> float:
"""計算 Lambda 每月成本"""
free_requests = 1_000_000
free_gb_seconds = 400_000
memory_gb = 256 / 1024 # 0.25 GB
exec_time_sec = 0.2 # 200ms
billable_requests = max(0, requests_per_month - free_requests)
total_gb_seconds = requests_per_month * memory_gb * exec_time_sec
billable_gb_seconds = max(0, total_gb_seconds - free_gb_seconds)
request_cost = billable_requests * 0.20 / 1_000_000
compute_cost = billable_gb_seconds * 0.0000166667
return round(request_cost + compute_cost, 2)
def ec2_monthly_cost(instance_type: str = "t3.medium") -> float:
"""計算 EC2 每月成本(On-Demand)"""
hourly_rate = 0.0416 # t3.medium us-east-1
hours_per_month = 730
return round(hourly_rate * hours_per_month, 2)
# 不同流量下的成本比較
scenarios = [
("低流量", 100_000),
("中等流量", 1_000_000),
("中高流量", 10_000_000),
("高流量", 50_000_000),
("超高流量", 100_000_000),
]
ec2_cost = ec2_monthly_cost()
print(f"{'場景':<12} {'月請求數':>14} {'Lambda 成本':>12} {'EC2 成本':>10} {'較便宜的':<10}")
print("-" * 65)
for name, requests in scenarios:
lc = lambda_monthly_cost(requests)
cheaper = "Lambda" if lc < ec2_cost else "EC2"
print(f"{name:<12} {requests:>14,} ${lc:>10.2f} ${ec2_cost:>8.2f} {cheaper:<10}")
# 輸出結果(概略):
# 場景 月請求數 Lambda 成本 EC2 成本 較便宜的
# -----------------------------------------------------------------
# 低流量 100,000 $0.00 $30.37 Lambda
# 中等流量 1,000,000 $0.00 $30.37 Lambda
# 中高流量 10,000,000 $18.13 $30.37 Lambda
# 高流量 50,000,000 $109.63 $30.37 EC2
# 超高流量 100,000,000 $222.93 $30.37 EC2結論: 在大約 2,000-3,000 萬次請求/月 的交叉點之後,EC2 的固定成本模型開始比 Lambda 的按次計費更划算。但實際的交叉點會因 function 的記憶體需求、執行時間、以及是否使用 Reserved Instance 而大幅變動。
Vendor Lock-in 考量
| 面向 | 鎖定程度 | 說明 |
|---|---|---|
| AWS Lambda | 高 | Event 格式(API Gateway proxy event)、Layer、Extensions 都是 AWS 專屬 |
| Cloud Functions | 高 | GCP event 格式、與 Firestore/Pub/Sub 的整合方式是 GCP 專屬 |
| Cloud Run | 低 | 標準 Docker image + HTTP,幾乎可以無痛搬到任何平台 |
| EC2 / GCE | 中 | 若使用 cloud-specific SDK(如 AWS SDK)則有鎖定,但 VM 本身可搬遷 |
| Serverless Framework | 低 | 抽象層,理論上可以切換 provider(實務上仍有差異) |
降低鎖定的策略:
- 使用 Hexagonal Architecture / Ports & Adapters,將業務邏輯與雲端 SDK 解耦
- 使用 Serverless Framework 或 SST 等抽象層
- 將核心邏輯包裝成獨立的 npm package / Python module,handler 只做 event 轉換
- 考慮 Cloud Run 等基於 Docker 的方案,可攜性最高
詳細比較表
| 維度 | 傳統伺服器 (EC2/GCE) | Serverless (Lambda/CF) | CaaS (Cloud Run/Fargate) |
|---|---|---|---|
| 控制程度 | 完全控制 OS、網路、磁碟 | 僅控制程式碼和設定 | 控制 container 內容,不管 host |
| 擴展方式 | 手動或 Auto Scaling Group(分鐘級) | 自動(毫秒級,含縮至零) | 自動(秒級,可縮至零) |
| 成本模型 | 按時計費(可 RI/Spot 折扣) | 按請求次數 + 執行時間 | 按 container 運行時間(可縮至零) |
| Cold Start | 無(常駐) | 有(100ms-10s) | 有(1s-30s,取決於 image 大小) |
| 最長執行時間 | 無限制 | Lambda 15 分鐘 / CF 60 分鐘 | Cloud Run 60 分鐘 / Fargate 無限制 |
| 狀態管理 | 可在本地記憶體/磁碟保存狀態 | 無狀態,必須用外部儲存 | 單一請求內有狀態,跨請求無狀態 |
| 除錯方式 | SSH 進去、看 log、用 debugger | CloudWatch Logs + X-Ray | Cloud Logging + 本地 Docker 測試 |
| Vendor Lock-in | 中(VM 可搬,但 cloud SDK 有鎖定) | 高(event 格式、SDK 綁定) | 低(標準 Docker image) |
| 適合的團隊 | 有 DevOps/SRE 能力的團隊 | 小團隊、快速原型 | 有 Docker 經驗、需要彈性的團隊 |
適用場景指南
Serverless 最適合的場景
- 事件驅動處理:S3 檔案上傳後觸發縮圖、影片轉檔
- Webhook Handler:接收 LINE Bot / Slack / GitHub webhook
- 排程任務:每天凌晨跑報表、同步資料、清理過期 session
- 低流量 API:內部工具、後台管理 API
- 原型驗證:快速上線 MVP,不花時間在 infra
傳統伺服器最適合的場景
- 長時間執行的任務:影片轉碼、ML 模型訓練
- WebSocket / 即時通訊:需要維持長連線的場景
- 有狀態應用:遊戲伺服器、需要 in-memory cache 的應用
- 高吞吐量 API:每秒數千請求的核心 API,固定成本更划算
- 合規需求:需要特定 OS 設定、磁碟加密、網路隔離
CaaS 最適合的場景
- 容器化應用需要自動擴展:已經有 Docker image,想要自動 scaling
- 比 Lambda 需要更多控制:需要自訂 runtime、安裝特殊套件
- 避免 vendor lock-in:同一個 Docker image 可以跑在任何雲端
- 微服務架構:每個服務一個 container,獨立部署和擴展
程式碼範例
範例一:AWS Lambda Function(Node.js)
// handler.js — 處理 API Gateway 請求的 Lambda function
import { DynamoDBClient, GetItemCommand } from "@aws-sdk/client-dynamodb";
const ddb = new DynamoDBClient({ region: "ap-northeast-1" });
export const handler = async (event) => {
const { httpMethod, pathParameters, body } = event;
const userId = pathParameters?.id;
try {
if (httpMethod === "GET" && userId) {
// 從 DynamoDB 取得使用者資料
const result = await ddb.send(
new GetItemCommand({
TableName: process.env.USERS_TABLE,
Key: { userId: { S: userId } },
})
);
if (!result.Item) {
return {
statusCode: 404,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ error: "User not found" }),
};
}
return {
statusCode: 200,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
userId: result.Item.userId.S,
name: result.Item.name.S,
email: result.Item.email.S,
}),
};
}
return {
statusCode: 400,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ error: "Invalid request" }),
};
} catch (error) {
console.error("Error:", error);
return {
statusCode: 500,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ error: "Internal server error" }),
};
}
};範例二:AWS SAM Template 部署設定
# template.yaml — AWS SAM (Serverless Application Model) 部署範本
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: User API with Lambda + API Gateway + DynamoDB
Globals:
Function:
Runtime: nodejs20.x
MemorySize: 256
Timeout: 10
Environment:
Variables:
USERS_TABLE: !Ref UsersTable
Resources:
# API Gateway
UserApi:
Type: AWS::Serverless::Api
Properties:
StageName: prod
Cors:
AllowOrigin: "'*'"
AllowMethods: "'GET,POST,OPTIONS'"
# Lambda Function
GetUserFunction:
Type: AWS::Serverless::Function
Properties:
Handler: handler.handler
CodeUri: ./src
Description: "取得使用者資料"
Events:
GetUser:
Type: Api
Properties:
RestApiId: !Ref UserApi
Path: /users/{id}
Method: GET
# Provisioned Concurrency 以避免 Cold Start
ProvisionedConcurrencyConfig:
ProvisionedConcurrentExecutions: 2
Policies:
- DynamoDBReadPolicy:
TableName: !Ref UsersTable
# DynamoDB Table
UsersTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: users
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: userId
AttributeType: S
KeySchema:
- AttributeName: userId
KeyType: HASH
Outputs:
ApiEndpoint:
Description: "API Gateway endpoint URL"
Value: !Sub "https://${UserApi}.execute-api.${AWS::Region}.amazonaws.com/prod"範例三:Cloud Run 部署(Docker Image)
#!/bin/bash
# deploy-cloud-run.sh — 從 Docker image 部署到 Cloud Run
PROJECT_ID="my-project"
SERVICE_NAME="user-api"
REGION="asia-east1"
IMAGE="gcr.io/${PROJECT_ID}/${SERVICE_NAME}"
# 1. 建置 Docker image
docker build -t "${IMAGE}:latest" .
# 2. 推送到 Google Container Registry
docker push "${IMAGE}:latest"
# 3. 部署到 Cloud Run
gcloud run deploy "${SERVICE_NAME}" \
--image "${IMAGE}:latest" \
--region "${REGION}" \
--platform managed \
--allow-unauthenticated \
--port 8080 \
--memory 512Mi \
--cpu 1 \
--min-instances 1 \
--max-instances 10 \
--concurrency 80 \
--set-env-vars "NODE_ENV=production,DB_HOST=10.0.0.5" \
--vpc-connector "my-vpc-connector" \
--timeout 300
# 4. 取得服務 URL
SERVICE_URL=$(gcloud run services describe "${SERVICE_NAME}" \
--region "${REGION}" \
--format "value(status.url)")
echo "Service deployed at: ${SERVICE_URL}"
# 5. 驗證部署
curl -s "${SERVICE_URL}/health" | jq .混合部署模式:核心 API 在伺服器,背景任務用 Serverless
在實務中,很少有團隊全部使用一種架構。最常見的做法是混合部署:將核心 API 部署在傳統伺服器或 CaaS 上,而將背景任務、事件處理等交給 Serverless。
flowchart TD Client[Client App] --> ALB[Application Load Balancer] ALB --> CoreAPI["Core API\n(ECS Fargate / EC2)\n高吞吐、低延遲"] CoreAPI --> DB[(PostgreSQL RDS)] CoreAPI --> Redis[(Redis ElastiCache)] CoreAPI -->|publish event| SQS[SQS / SNS] CoreAPI -->|upload file| S3[S3 Bucket] SQS -->|trigger| Worker["Background Worker\n(Lambda)\n圖片縮放、email 寄送"] S3 -->|trigger| Processor["File Processor\n(Lambda)\n影片轉檔、CSV 匯入"] CW[CloudWatch Events] -->|schedule| Cron["Scheduled Tasks\n(Lambda)\n報表、清理、同步"] Worker --> DB Processor --> DB Cron --> DB subgraph "穩定流量 → 固定成本" CoreAPI DB Redis end subgraph "突發/低頻 → 按次計費" Worker Processor Cron end
混合部署的原則:
- 核心路徑(使用者直接互動的 API)放在伺服器或 CaaS,確保低延遲和穩定性
- 背景任務(非同步、可容忍延遲)放在 Serverless,節省成本
- 排程任務(Cron job)放在 Serverless,不需要 24 小時跑一台機器只為了每天執行一次的任務
- 透過 Message Queue(SQS/SNS/Pub/Sub)解耦核心 API 與背景處理
常見問題與風險
1. Lambda 記憶體與 CPU 的連動性
Lambda 的 CPU 分配是和記憶體綁定的。128MB 記憶體只給很少的 CPU,1,769MB 才等於一個完整 vCPU。如果你的 function 是 CPU 密集型(如加解密、壓縮),增加記憶體可能反而降低總成本,因為執行時間大幅縮短。
2. Timeout 與重試風暴
Lambda 預設會在失敗時重試(非同步呼叫重試 2 次)。如果你的 function 因為下游服務超時而失敗,重試可能造成下游更大的壓力(retry storm)。務必設定合理的 timeout、配合 Dead Letter Queue (DLQ) 處理失敗的事件。
3. 並發限制
Lambda 每個 region 預設 1,000 並發限制(可申請提高)。如果一個 function 吃掉太多並發,可能影響同帳號下其他 function。建議為關鍵 function 設定 Reserved Concurrency。
4. Serverless 的隱藏成本
- API Gateway 的費用($3.50 / 百萬次請求)往往比 Lambda 本身更貴
- CloudWatch Logs 的儲存費用會隨著 function 數量增長而快速累積
- NAT Gateway 費用:如果 Lambda 在 VPC 內需要存取外部服務,NAT Gateway 的費用可能是最大的開支
5. 本地開發體驗
Serverless 的本地開發體驗通常不如傳統伺服器。雖然有 SAM Local、Serverless Offline 等工具,但它們無法完全模擬雲端環境(IAM 權限、Event Source Mapping 等)。建議搭配整合測試環境,在真實雲端環境中驗證行為。
6. 監控與除錯
分散式的 function 架構讓除錯變得更困難。一個請求可能經過 API Gateway → Lambda A → SQS → Lambda B → DynamoDB,要追蹤完整的請求鏈路需要使用分散式追蹤工具(AWS X-Ray、OpenTelemetry)。
7. 部署與版本管理
Serverless function 的部署頻率通常很高(因為每個 function 可以獨立部署),但也因此更容易出現版本不一致的問題。建議使用 Infrastructure as Code(SAM/CDK/Terraform)管理所有 function 的版本和設定。
常見服務 × 架構對照表
以下整理常見服務適合哪種架構。記住,沒有絕對正確的答案——關鍵是理解你的流量特性、延遲需求和團隊能力。
| 服務類型 | 範例 | 推薦架構 | 原因 |
|---|---|---|---|
| 即時聊天 | Slack / Discord | Server | 需要 WebSocket 長連線 |
| 靜態網站 + API | 個人部落格、Landing Page | Serverless | 低流量、event-driven |
| 電商平台 | Shopify 自建、PChome | Server or CaaS | 穩定高流量、需要 session 管理 |
| LINE Bot / Webhook | 聊天機器人、GitHub Webhook | Serverless | event-driven,低頻觸發 |
| 圖片/影片處理 | 縮圖產生、影片轉檔 | Serverless | 非同步處理、突發流量 |
| ML 推論 API | 圖像辨識、NLP 服務 | CaaS | 自訂 runtime、需要 GPU |
| 排程報表 | 每日銷售報表、資料同步 | Serverless | Cron trigger,不需常駐 |
| 內部管理後台 | Admin Dashboard、CMS | CaaS or Serverless | 低流量、使用者數少 |
| IoT 資料收集 | 感測器數據上傳、裝置回報 | Serverless | 突發流量、事件驅動 |
| 串流服務 | Netflix、Twitch | Server | 高頻寬、長連線 |
| CI/CD Runner | GitHub Actions Self-hosted | CaaS | 需要 Docker、自訂環境 |
| 認證服務 (OAuth) | SSO、第三方登入 | Server or CaaS | 穩定需求、有狀態 session |
| 搜尋引擎 | Elasticsearch、站內搜尋 | Server | 高記憶體、常駐索引 |
| 通知推播 | Email 通知、App Push | Serverless | event-driven、突發流量 |
| 資料 ETL Pipeline | 資料倉儲匯入、日誌分析 | Serverless or CaaS | 批次處理、非同步執行 |
看到規律了嗎? 長連線/高流量/有狀態 → Server,事件驅動/突發/無狀態 → Serverless,需要容器化/自訂 Runtime → CaaS。
決策流程圖
當你在選擇架構時,可以依照以下問題逐步判斷:
- 流量是否穩定且高吞吐? → 是 → 考慮 EC2 + Reserved Instance
- 需要長連線或有狀態? → 是 → 考慮 EC2 / ECS
- 已經有 Docker image? → 是 → 考慮 Cloud Run / Fargate
- 流量極低或極不穩定? → 是 → 考慮 Lambda / Cloud Functions
- 是事件驅動的背景任務? → 是 → 考慮 Lambda + SQS
- 需要快速原型驗證? → 是 → 考慮 Serverless(開發速度最快)
大多數生產環境最終會走向混合架構。關鍵不是選擇「一個最好的」,而是為每個工作負載選擇最適合的部署方式。
延伸閱讀
- Serverless(Infra 系列):從自架 Infra 的角度分析 Serverless 的適用場景、成本模型與限制
- Container Runtime:Docker + Portainer 的標準化部署基座,理解容器化的基礎