Serverless vs container là quyết định kiến trúc lớn cho dự án mới. Bài này phân tích thực tế: khi nào Lambda thắng, khi nào Docker + K8s, khi nào Cloud Run là giữa đường.
Định nghĩa nhanh
- Serverless (FaaS): code chạy trong runtime managed. AWS Lambda, GCP Cloud Functions, Cloudflare Workers, Vercel Edge Functions.
- Container: app đóng gói trong Docker image, chạy trên K8s/ECS/Cloud Run. Anh quản lý image; cloud quản lý cluster.
- Serverless container: container nhưng billing serverless (scale-to-zero, pay-per-second). Cloud Run, App Runner, Fly.io.
Cold start — chi tiết quan trọng
| Platform | Cold start | Khi xảy ra |
|---|---|---|
| Lambda Node.js | ~200ms | Đầu tiên hoặc sau idle 15+ phút |
| Lambda Java/.NET | ~1-3s | Như trên |
| Cloud Run | ~500ms-2s | Scale 0 → 1, hoặc scale up new instance |
| Cloudflare Workers | ~5ms | Hầu như không có (V8 isolate) |
| Container (K8s) | 0ms (warm pool) | Không có khi replica đã chạy |
Provisioned concurrency Lambda loại bỏ cold start nhưng charge như reserved — gần như mất lợi thế "pay per use".
Pricing — tính break-even
Lambda: $0.20/1M request + $0.0000167 per GB-second.
1 function dùng 512MB RAM, chạy 200ms/request, 100M request/tháng:
- Request: 100M × $0.0000002 = $20
- Compute: 100M × 0.2s × 0.5GB × $0.0000167 = $167
- Tổng: ~$187/tháng
Container EC2 (t3.medium 2vCPU 4GB) chạy 24/7 = $30/tháng. Có thể serve hơn 100M request/tháng nếu app tối ưu. Container rẻ hơn 6 lần ở mức traffic này.
Nhưng nếu traffic chỉ 1M/tháng:
- Lambda: ~$2/tháng
- Container: $30/tháng (vẫn vậy)
Break-even tuỳ workload. Quy tắc thumb: utilization < 30% → serverless thắng. > 50% → container thắng.
Khi nào serverless thắng?
- Traffic spike rồi idle (e.g. webhook, batch processing)
- Event-driven (S3 trigger, queue consumer)
- Cron job ít chạy
- Prototype, MVP — focus code, không infra
- Edge compute (Workers, Vercel Edge) cho latency thấp toàn cầu
- Team nhỏ, không có DevOps
Khi nào container thắng?
- Long-running process (WebSocket, gRPC stream)
- Latency-sensitive — không chấp nhận cold start
- Stateful service — cache in-memory, connection pool
- Workload utilization cao > 50%
- Tránh vendor lock-in
- Compliance yêu cầu control hơn
- Custom kernel/lib không support trong runtime managed
Pattern hybrid phổ biến
- Container cho main API + Lambda cho cron, webhook, image processing
- Cloud Run cho service không quá hot + Workers cho edge route
- K8s production + Lambda cho bursty workload
Đa số production thực tế là hybrid — không one-size-fits-all.
Vendor lock-in: cảnh báo
Lambda + DynamoDB + SQS + EventBridge → app coupled chặt với AWS. Migrate sang GCP cần rewrite. Container chạy Docker — chỉ cần K8s/ECS, image portable.
Nếu giảm lock-in quan trọng: chọn Cloud Run (container) thay Lambda. Code đóng gói Docker → chạy trên Knative/K8s/Fly cũng được.
VPC, networking
Lambda kết nối VPC (DB private) khá phức tạp — ENI, NAT, cold start lâu hơn. Container trong K8s chạy trong VPC native. Nếu app cần kết nối nhiều resource private, container đơn giản hơn.
Kết luận
Serverless vs container không phải lựa chọn either/or. Nguyên tắc: bắt đầu với serverless (Cloud Run, Workers, Vercel) cho speed; migrate sang container khi traffic ổn định và cost vượt threshold. Đọc thêm Kubernetes nếu anh đang scale lớn cần control sâu.