無伺服器運算 (Serverless / FaaS)
Serverless 不是「沒有伺服器」,是你不需要管它。你只提供程式碼,告訴系統「當某事發生時執行這段」。
本質是一個取捨,不是萬用解:用很低的成本和維運負擔,換取近乎無限的自動擴展 —— 代價是執行時間上限、Cold Start、嚴格無狀態、vendor lock-in。
兩個形態
| 形態 | 說明 | 代表產品 |
|---|---|---|
| FaaS(Function-as-a-Service) | 程式碼以「函式」為單位,由事件觸發,執行完立刻釋放,按毫秒計費 | AWS Lambda、GCF、Azure Functions |
| BaaS(Backend-as-a-Service) | 資料庫/驗證/儲存等以 API 呼叫,不管伺服器 | Firebase、DynamoDB、Auth0、S3 |
面試提到 Serverless 通常指 FaaS。
事件驅動的執行模型
函式不是一直跑的 process,而是被事件喚醒 → 執行 → 消失:
HTTP 請求 → API Gateway 觸發 Lambda 處理訂單
訊息 Queue → SQS 新訊息觸發函式
排程 → 每天凌晨 2 點觸發批次報告
資料庫變更 → DynamoDB Stream 有寫入觸發下游
檔案上傳 → S3 有新圖片觸發縮圖函式
沒有流量時真的什麼都不跑、什麼都不花。對峰谷明顯的工作負載是巨大優勢。
Cold Start vs Warm Start(最常被深挖的點)
第一次(或閒置太久後)呼叫函式,雲端供應商要:① 分配容器/microVM ② 載入程式碼 ③ 初始化 runtime ④ 跑你的初始化程式碼(建 DB 連線)。
Cold Start:
請求 → 分配容器 → 初始化環境 → 執行函式 → 回傳
[──── 額外延遲 300ms ~ 3s ────] ← Java/.NET 較久,Python/Node 較快
Warm Start:
請求 → 執行函式 → 回傳 (無額外延遲)
函式執行完,容器保溫 5–15 分鐘,期間有新請求直接重用 → Warm Start。
- 減少時間本身:選快語言(Python/Node ≫ Java)、部署包越小越好、把初始化(DB 連線、設定)放在 handler 外面讓 Warm Start 重用
- Provisioned Concurrency:預留「熱」實例完全消除 Cold Start,代價是為閒置容量付費(失去 Serverless 一大優勢)
- Warm-up:排程定期觸發保持熱(土方法)
- 非同步場景完全不必擔心:SQS 觸發、排程執行多幾百毫秒無所謂;只有同步 API(P99 SLA) 才需認真考慮
嚴格無狀態
每次執行是獨立的世界,函式不能假設上次留下了什麼。本地記憶體、臨時檔案下次都可能消失。任何跨請求狀態必須外部化到 DB / 快取 / 物件儲存。比容器更嚴格,因為執行環境短暫且不可預測。
三方部署模式對照
| 維度 | 傳統伺服器 / VM | 容器(K8s) | Serverless(Lambda) |
|---|---|---|---|
| 管理複雜度 | 高(OS/runtime) | 中(K8s 設定) | 低(只管程式碼) |
| 啟動速度 | 分鐘級 | 秒級 | 毫秒~秒(含 cold start) |
| 擴展方式 | 手動 / Auto Scaling | HPA 自動 | 完全自動、近乎無限 |
| 執行時間 | 無限制 | 無限制 | 15 分鐘上限 |
| 閒置成本 | 高(永遠付費) | 中(需底層節點) | 零(沒執行就沒費用) |
| 計費粒度 | 按小時 / 月 | 按 CPU/記憶體 | 按毫秒 |
| 延遲穩定性 | 穩定 | 穩定 | Cold start 時不穩定 |
| 狀態管理 | 可本地狀態 | 通常無狀態 | 嚴格無狀態 |
沒有一個方案在所有場景下最好,選擇關鍵是工作負載特性。
適合 vs 不適合
| ✅ 適合 Serverless | ❌ 不適合 Serverless |
|---|---|
| 流量不穩(每天幾小時有流量) | 長任務 > 15 分(影片轉碼、ML 訓練) |
| 事件驅動管線(與 queue / 事件流組合) | 低延遲 P99 < 100ms(cold start 不確定性) |
| 排程任務(EventBridge cron 觸發) | 持續高流量(按毫秒計費比容器貴) |
| 邊緣計算(Lambda@Edge、CF Workers) | 複雜狀態(WebSocket 長連線、連線池) |
核心架構模式
API Gateway + Lambda(最常見)
Client → API Gateway → Lambda 函式 → DynamoDB / RDS
(認證、限流)
DB 連線爆炸(Serverless 最惡名昭彰的痛點)
Lambda 無狀態,每實例各自建 DB 連線,又可瞬間擴展到幾千並發 → PostgreSQL(預設幾百連線)被打掛。
解法:Lambda × 1000 → RDS Proxy / PgBouncer(連線池)→ RDS(50 個連線)
或用 DynamoDB(原生 Serverless DB,無連線概念、按請求計費,天然適合 Lambda)。
Fan-out 模式
新訂單 → SNS Topic → Lambda A(更新庫存)
→ Lambda B(發確認信)
→ Lambda C(通知物流)
SNS 把一個訊息 fan-out 給多個 Lambda 平行執行,某個失敗不影響其他(各有自己的 DLQ)。本質與 Pub/Sub 相同。
面試話術
而是「我在這個部分用 Lambda,因為它事件觸發、流量峰谷明顯;但這個需要長時間執行的部分用 EC2 Worker,因為 Lambda 的 15 分鐘上限不夠。」展示你在為每個工作負載選最合適的工具。
常見情境:
- 訂單通知:SNS fan-out 到三個 Lambda 平行處理,各有 DLQ,只在有新訂單時跑
- 圖片處理:S3 Upload 事件觸發 Lambda → 分丟三個 SQS → 縮圖/NSFW/EXIF 平行處理
- 定期清理:EventBridge 每天觸發 Lambda 批次清理刪除超過 30 天的帳號
常見 Deep Dive
先承認問題存在,再說清楚何時是問題(同步 API、P99 < 100ms)何時不是(非同步)。緩解:選快語言、小部署包、初始化移到 handler 外、Provisioned Concurrency、warm-up。非同步場景完全不必擔心。
兩個維度:請求次數(每百萬約 $0.2)+ 執行時間 × 記憶體(每 GB-秒約 $0.000016)。
例:每天 100 萬請求、每次 200ms、512MB → 請求費 $6/月 + 執行費 $48/月 ≈ $54/月。對比 EC2 t3.small ≈ $15/月不限請求量。流量大且穩定 → 傳統機器更便宜;一天 12 小時近零流量 → Serverless 更划算。
函式短暫,出問題無法 SSH。① 結構化日誌帶 correlation ID(從 header 傳入)串起完整鏈路 ② 分散式追蹤(AWS X-Ray、Datadog APM)跨 Lambda/SQS/DynamoDB ③ DLQ 監控(CloudWatch 對 DLQ 深度設告警)。
有,比容器明顯得多(事件格式、DynamoDB API、EventBridge 語法都是 AWS 特定)。緩解:在 handler 裡加一層抽象,把雲端特定邏輯(解析 event / 格式化回應)和純業務邏輯分開,業務邏輯可本地測試/理論上可移植。但這只是緩解不是根治 —— 面試直接說「接受這個取捨,換取免管基礎設施 + 自動擴展」。
影片轉碼、大型資料集、複雜 ML 訓練不能用 Serverless。改用跑在 EC2 / Spot Instance 上的 worker 接 SQS。
自我測驗重點
| 問題 | 重點 |
|---|---|
| FaaS vs BaaS | 函式按事件 vs 託管後端服務 API |
| Cold vs Warm Start | 保溫 5–15 分;非同步不必擔心 |
| 三方對照硬限制 | Lambda 15 分鐘上限、嚴格無狀態 |
| DB 連線爆炸 | RDS Proxy / PgBouncer 或 DynamoDB |
| 成本何時划算 | 流量峰谷明顯划算、持續高流量容器便宜 |
| vendor lock-in | 比容器明顯;handler 抽象層緩解 |
Related Notes
- 11-Infrastructure/03-Container — 容器與 Serverless 同屬無狀態自動擴展;三方部署模式對照
- 11-Infrastructure/01-API-Gateway — API Gateway + Lambda 是經典 Serverless 入口
- 06-Database-Tech/03-DynamoDB — 原生 Serverless DB,無連線概念,天然配 Lambda
- 07-Caching-Storage/02-Blob-Storage — S3 事件觸發 Lambda 是事件驅動管線的核心
- 10-Design-Patterns/03-Long-Running-Tasks — 長任務超過 15 分要改用 worker + queue
- 10-Design-Patterns/05-Real-time-Updates — SNS fan-out 與 Pub/Sub 本質相同