Capstone: Soi Lại Theo Well-Architected, Dọn Dẹp và Mở Rộng
You've reached the end
Hai mươi bài trước dựng từng mảnh: từ một hàm Lambda đầu tiên tới một sản phẩm có API, dữ liệu, xác thực, sự kiện, realtime, điều phối, quan sát, bảo mật, CI/CD, và đã đo dưới tải. Bài cuối ghép lại bức tranh, soi nó bằng một khung chuẩn, rồi nói về dọn dẹp và những bước tiếp theo.
Toàn cảnh đã dựng
┌──────────── Cognito (JWT) ────────────┐
Trình duyệt ─HTTPS─▶ API Gateway HTTP API (throttle) │ xác thực
│ │ │ │
│ POST /links ───┼──▶ create-link ──▶ DynamoDB single-table (+GSI1, TTL)
│ GET /links ────┼──▶ list-links ──▶ ▲
│ DELETE /links ─┼──▶ delete-link ──────┘
│ GET /{code} ───┼──▶ resolve ──┬─▶ 301
│ │ │ └─▶ EventBridge ─▶ SQS(+DLQ) ─▶ aggregator
│ │ │ │
│ │ │ Step Functions (kiểm duyệt) ▼
│ │ │ đếm + push
└─WebSocket──────────────────────────────────────────◀── realtime dashboard
Quan sát: Powertools (log/trace/metric) · X-Ray · CloudWatch alarm + dashboard
Vận hành: SAM · CI (GitHub Actions) · CD canary + rollback (CodeDeploy)
Không có hộp nào là server phải nuôi. Lúc không ai dùng, hóa đơn về gần không.
Soi qua Well-Architected
AWS Well-Architected Framework đánh giá kiến trúc qua năm trụ cột. Đi qua từng cái cho thấy series đã chạm đến đâu, và còn gì để làm.
Operational Excellence. Toàn bộ hạ tầng là code trong một template SAM, phiên bản hóa cùng repo, dựng và xóa bằng một lệnh. CI build và validate mỗi push, CD dùng canary có cửa sổ quan sát và lối lui. Hệ thống quan sát được qua log có cấu trúc, trace X-Ray, metric và alarm. Còn thiếu: runbook cho sự cố và deploy tự động qua OIDC thay vì từ máy.
Security. Xác thực bằng Cognito JWT ngay tại gateway; dữ liệu tách theo người dùng và chống IDOR ở tầng ghi; IAM thu về least-privilege cho từng hàm; throttle chống dội; bí mật thuộc về Parameter Store. Còn thiếu: WAF (cần CloudFront ở trước cho HTTP API), và CORS nên thu từ * về đúng domain dashboard.
Reliability. Sự kiện qua SQS có retry và DLQ nên không mất; đếm idempotent nên không sai khi giao trùng; atomic counter an toàn dưới đồng thời; và bài load test cho thấy hệ thống degrade gracefully, gạt tải thừa thay vì sập. DynamoDB và Lambda vốn chạy trên nhiều Availability Zone (multi-AZ) trong một Region, do AWS quản lý sẵn. Còn thiếu: nâng quota concurrency để không gạt tải sớm như hiện tại.
Performance Efficiency. arm64 cho compute rẻ và nhanh; bộ nhớ chỉnh được để cắt cold start; single-table với GSI sparse cho truy vấn một lần thay vì nối bảng; on-demand co theo tải. Còn thiếu: với cold start gắt hơn thì cân nhắc provisioned concurrency (sau khi nâng quota) hoặc viết hàm nóng bằng runtime hỗ trợ SnapStart.
Cost Optimization. Trả theo lượng dùng, idle về không, và hóa đơn thật của cả series gần như bằng không nhờ free tier cùng các lựa chọn HTTP API, arm64, on-demand. Còn thiếu: gắn tag chi phí và budget alarm khi đưa vào production thật.
Khung này không phải để chấm điểm mà để lộ ra cái còn trống, và mỗi "còn thiếu" ở trên là một việc cụ thể cho lần lặp sau.
Dọn dẹp: một lệnh
Vì mọi thứ nằm trong một CloudFormation stack, xóa sạch toàn bộ sản phẩm chỉ là:
sam delete --stack-name url-shortener --no-prompts --region ap-southeast-1
Lệnh này xóa các hàm Lambda, HTTP API và WebSocket API, bảng DynamoDB, user pool, event bus, hàng đợi, state machine, alarm, dashboard, và các IAM role đi kèm. Sau đó kiểm lại không còn tài nguyên nào phát sinh tiền. Một bảng DynamoDB on-demand rỗng hay vài hàm Lambda không gọi tới gần như không tốn gì, nhưng thói quen xóa stack khi không cần là cách chắc chắn nhất để không nhận hóa đơn bất ngờ. Nếu muốn giữ lại để khám phá tiếp, cứ để nguyên; chi phí idle gần như bằng không.
Hướng mở rộng
Sản phẩm đã đủ chạy thật, nhưng có vài bước rõ ràng để đưa nó xa hơn.
Tên miền tùy chỉnh và WAF. Đặt một CloudFront distribution trước HTTP API, gắn tên miền sho.rt qua ACM certificate, và gắn WAF web ACL vào CloudFront. Việc này vừa cho link ngắn đẹp hơn vừa lấp đúng khoảng WAF còn thiếu ở phần security.
Một dashboard thật. Series dựng phần backend của realtime; phía trước cần một trang web nhỏ mở WebSocket lúc tải, hiển thị danh sách link và số click nhảy theo thời gian thực. Đây là chỗ ghép phần WebSocket (bài 11) với một giao diện.
Quét an toàn thật. State machine kiểm duyệt (bài 12) hiện dùng danh sách từ cấm; thay bằng một lời gọi tới dịch vụ quét URL thật (như Google Safe Browsing) là một nâng cấp gọn, và là chỗ áp dụng bí mật trong Parameter Store.
Đa vùng. Với yêu cầu sẵn sàng cao hơn, DynamoDB Global Tables nhân bản dữ liệu sang vùng khác, và Route 53 định tuyến theo độ trễ tới API ở mỗi vùng.
Mỗi hướng là một lần lặp, dựng trên đúng nền đã có, không phải làm lại.
Tổng kết series
Ta đi từ "Lambda chạy code ra sao" tới một sản phẩm serverless hoàn chỉnh, vận hành như production. Dọc đường, mỗi bài giải một bài toán thật và đo bằng số thật: cold start, single-table design, idempotency, realtime, điều phối, quan sát, bảo mật, deploy an toàn, chi phí, và hành vi dưới tải. Điểm xuyên suốt là cách nghĩ serverless: ghép những thành phần nhỏ do AWS quản lý bằng sự kiện, để cái mình viết co theo nhu cầu và gần như không tốn gì lúc nghỉ.
Cảm ơn bạn đã theo hết series. Code đầy đủ ở github.com/nghiadaulau/serverless-url-shortener-aws, dùng làm nền để dựng tiếp.
You've reached the end