Serverless Architecture: Kiến trúc không máy chủ và những chiếc bẫy chi phí
7/19/2026 · 12p đọc
title: "Serverless Architecture: Kiến trúc không máy chủ và những chiếc bẫy chi phí"
series: "Software Architecture Masterclass"
part: "Phần 2 — Cấu trúc & Patterns"
order: 14
audience: "Solutions Architect & Technical Lead"
reading_time: "13 phút"
tags:
- serverless
- faas
- cost-optimization
- cloud-architecture
- event-driven
- trade-off
Serverless Architecture: Kiến trúc không máy chủ và những chiếc bẫy chi phí
Một team fintech tôi từng tư vấn có một endpoint xử lý webhook thanh toán. Traffic thất thường — có ngày vài trăm request, có ngày (đợt khuyến mãi) vài triệu request dồn trong hai giờ. Họ chuyển từ EC2 sang AWS Lambda, hóa đơn compute giảm 70% ngay tháng đầu. CTO khoe thành tích trong buổi all-hands. Ai cũng vui.
Mười tám tháng sau, sản phẩm core của họ — một API xử lý transaction, chạy liên tục 24/7 với traffic ổn định 200 req/s — cũng được "di cư" sang serverless theo đúng tinh thần "cứ serverless hết cho đồng bộ kiến trúc". Hóa đơn AWS tháng đó tăng gấp 3 lần so với baseline EC2 trước đó. Không ai hiểu tại sao một kiến trúc "không cần quản lý hạ tầng" lại đắt hơn kiến trúc phải tự vá server.
Câu trả lời nằm ở chỗ không ai đọc kỹ: serverless không phải là "rẻ hơn". Serverless là một mô hình định giá khác, tối ưu cho một hình dạng traffic khác. Áp nó vào sai hình dạng traffic, và bạn trả tiền cho đúng thứ bạn tưởng mình đã bỏ qua.
The Problem
Ngộ nhận phổ biến nhất về serverless là: "không quản lý hạ tầng = không cần nghĩ về chi phí". Đây là một phép suy diễn sai lầm nguy hiểm, vì nó đánh tráo hai khái niệm khác nhau — operational overhead (gánh nặng vận hành) và cost model (mô hình chi phí).
Serverless (điển hình: AWS Lambda, Google Cloud Functions, Azure Functions — gọi chung là FaaS, Function-as-a-Service) loại bỏ gánh nặng vận hành: bạn không patch OS, không capacity-plan, không tự viết auto-scaling policy. Nhưng nó KHÔNG loại bỏ chi phí — nó thay đổi cách chi phí được tính, từ "trả cho tài nguyên đã cấp phát" (provisioned capacity) sang "trả cho từng lượt thực thi" (pay-per-invocation). Đây là hai đường cong chi phí có độ dốc khác nhau, và ở một điểm giao nhau nào đó, đường cong "trả theo lượt" sẽ vượt qua đường cong "trả theo cấp phát cố định".
Vấn đề thứ hai, tách biệt với vấn đề chi phí nhưng thường bị gộp chung: cold start latency. Khi một function không được gọi trong một khoảng thời gian, runtime của nó bị giải phóng. Lượt gọi tiếp theo phải khởi tạo lại toàn bộ execution environment — load runtime, load code, chạy initialization — trước khi xử lý request đầu tiên. Với ứng dụng Node.js đơn giản, cold start có thể chỉ thêm vài chục mili-giây. Với JVM (Java, Kotlin) hay ứng dụng có nhiều dependency nặng, cold start có thể lên đến vài giây. Với hệ thống yêu cầu latency p99 dưới 200ms, một cold start ngẫu nhiên là một SLA violation không báo trước.
Team trong câu chuyện trên không sai khi chọn Lambda cho webhook thanh toán — traffic thất thường, bùng nổ, không đoán trước được, đó chính xác là kịch bản serverless được sinh ra để giải quyết. Họ sai khi coi thành công đó là bằng chứng để tổng quát hóa serverless cho MỌI workload, kể cả workload có đặc tính traffic hoàn toàn ngược lại: ổn định, cao, liên tục, dự đoán được.
The Theory
Để hiểu khi nào serverless thắng và khi nào nó thua, cần hiểu bản chất kinh tế học của nó.
Mô hình chi phí truyền thống (server/container cấp phát cố định): bạn trả tiền cho capacity đã đặt trước, bất kể có dùng hết hay không. Một EC2 instance chạy 24/7 tốn cùng một số tiền dù nó phục vụ 10 request/giờ hay 10,000 request/giờ (cho đến khi chạm giới hạn CPU/memory và cần scale thêm). Chi phí là hàm bậc thang (step function) theo capacity, gần như không phụ thuộc vào traffic thực tế trong ngưỡng đó.
Mô hình chi phí serverless: bạn trả tiền theo số lượt thực thi × thời gian thực thi × tài nguyên cấp cho mỗi lượt (ví dụ AWS Lambda tính theo GB-giây cộng số request). Không có traffic, không tốn tiền. Traffic tăng gấp 10, chi phí tăng gần tuyến tính gấp 10. Đây là chi phí biến đổi thuần túy (variable cost), không có chi phí cố định (fixed cost) đáng kể ngoài một số dịch vụ đi kèm.
Hệ quả kinh tế học trực tiếp: hai đường cong chi phí này cắt nhau tại một điểm traffic nhất định.
- Dưới điểm cắt (traffic thấp, thất thường, có khoảng trống dài giữa các đợt tải): serverless rẻ hơn nhiều, vì hạ tầng cấp phát cố định phải trả tiền ngay cả khi "ngồi không" (idle capacity) — đây là chi phí chìm (sunk cost) không tạo ra giá trị. Serverless loại bỏ hoàn toàn chi phí idle.
- Trên điểm cắt (traffic cao, ổn định, gần như bão hòa capacity liên tục): mô hình cấp phát cố định rẻ hơn, vì bạn đang mua "buôn" (wholesale) capacity với chi phí biên giảm dần (economies of scale ở tầng hạ tầng), trong khi serverless vẫn tính bạn ở mức giá "bán lẻ" theo từng lượt gọi — không có discount cho volume cao liên tục (ngoại trừ các cam kết dài hạn dạng reserved/savings-plan mà bản chất lại đang biến serverless thành... capacity cố định).
Ngoài ra còn một biến số thứ ba ít được nhắc: workload nền/background thấp. Serverless đặc biệt hợp với các tác vụ chạy ngắn, không thường xuyên, kiểu cron job, xử lý file upload, gọi API bên thứ ba theo sự kiện — nơi mà việc duy trì một service chạy 24/7 chỉ để chờ sự kiện hiếm hoi là lãng phí rõ ràng.
Nguyên lý cốt lõi cần nhớ: serverless là một pricing strategy dịch chuyển rủi ro capacity planning từ bạn sang nhà cung cấp, và nhà cung cấp tính phí premium cho việc gánh rủi ro đó. Ở traffic thấp/thất thường, premium đó nhỏ hơn giá trị bạn tiết kiệm được từ việc không phải trả cho capacity nhàn rỗi. Ở traffic cao/ổn định, premium đó lớn hơn, vì rủi ro capacity gần như bằng không (bạn biết chắc mình cần bao nhiêu) nên bạn đang trả phí bảo hiểm cho một rủi ro không tồn tại.
The Trade-off
Đây là phần quan trọng nhất, và tôi sẽ đi thẳng vào từng cặp được-mất, không tô hồng.
Được: Không quản lý hạ tầng. Không patch OS, không capacity plan, không viết auto-scaling group config, không lo về server chết cần thay. Đội ngũ nhỏ có thể ship production service mà không cần một SRE chuyên trách.
Mất: Bạn đánh đổi quyền kiểm soát lấy sự tiện lợi đó. Khi có sự cố hiệu năng lạ (ví dụ p99 latency spike định kỳ), bạn không thể SSH vào máy để strace, không thể xem CPU steal time thực, không thể tối ưu kernel parameter. Bạn debug qua log và metric mà nhà cung cấp cho phép xem — và không phải lúc nào cũng đủ chi tiết.
Được: Tự động scale theo traffic, gần như vô hạn theo lý thuyết. Traffic tăng đột biến 100 lần trong 30 giây (viral post, flash sale) — serverless platform tự nhân bản instance function mà không cần bạn cấu hình gì thêm.
Mất: "Tự động" không có nghĩa là "miễn phí" hay "không giới hạn". Có concurrency limit theo tài khoản/theo region mà bạn phải xin nâng nếu traffic thật sự lớn. Và quan trọng hơn: khi scale tự động xảy ra, bạn cũng đang tự động nhân bản CHI PHÍ theo đúng tỷ lệ đó — không có cơ chế nào cảnh báo bạn trước khi hóa đơn đến, trừ khi bạn tự đặt.
Được: Trả tiền theo lượng dùng thực tế (pay-per-use), lý tưởng cho traffic thất thường hoặc tải nền thấp.
Mất: Ở traffic cao và ổn định liên tục, mô hình trả-theo-lượt trở thành ĐẮT HƠN so với mua capacity cố định theo lô lớn — đôi khi đắt hơn 2-5 lần tùy workload, vì bạn không được hưởng economies of scale của việc "mua sỉ" tài nguyên tính toán. Đây chính xác là cái bẫy chi phí ở quy mô lớn: cái đã cứu bạn ở traffic thấp sẽ ăn mòn biên lợi nhuận của bạn ở traffic cao.
Được: Không cần tự viết resilience/HA logic thấp cấp — nhà cung cấp lo việc chạy function trên nhiều AZ.
Mất: Vendor lock-in sâu hơn nhiều so với container hóa thông thường. Code function của bạn thường gắn chặt với event trigger format, IAM model, và runtime-specific SDK của một nhà cung cấp cụ thể. Di chuyển từ Lambda sang Cloud Functions không đơn giản như đổi base image Docker — bạn phải viết lại phần lớn glue code, đôi khi cả logic error-handling và retry vì mỗi platform có semantics khác nhau.
Được: Không cần lo về việc server "chết" giữa request — platform tự retry/route.
Mất: Cold-start latency không lường trước, đặc biệt nghiêm trọng với runtime nặng (JVM, .NET) hoặc function có nhiều dependency, VPC attachment. Với service yêu cầu SLA latency chặt (payment gateway, real-time bidding), một cold start ngẫu nhiên vài trăm mili-giây đến vài giây là rủi ro không thể chấp nhận nếu không có chiến lược "giữ ấm" (provisioned concurrency) — và provisioned concurrency, trớ trêu thay, lại là bạn trả tiền để MUA LẠI một phần capacity cố định, làm giảm bớt lợi thế chi phí ban đầu của serverless.
Được: Kiến trúc thiên hướng sự kiện tự nhiên — mỗi function là một đơn vị phản ứng với một event, dễ compose theo kiểu event-driven (xem Bài 13).
Mất: Khó test và debug cục bộ. Việc giả lập chính xác môi trường serverless (IAM permission, event payload thật, network policy, timeout behavior) trên máy local luôn là một xấp xỉ, không bao giờ hoàn hảo. Nhiều bug chỉ lộ ra khi đã deploy lên môi trường thật — vòng lặp phản hồi (feedback loop) chậm hơn đáng kể so với chạy monolith hay container cục bộ với debugger đầy đủ.
Tóm gọn bằng một câu: serverless bán cho bạn tốc độ triển khai và chi phí thấp ở traffic thất thường, đổi lại bạn trả bằng quyền kiểm soát, khả năng dự đoán chi phí ở quy mô lớn, và tính di động (portability).
The Architecture Diagram
Sơ đồ dưới đây so sánh đường cong chi phí giữa hai mô hình theo mức traffic — đây là công cụ ra quyết định quan trọng nhất của bài này.
graph LR
subgraph Cost_Model["Mô hình chi phí theo mức Traffic"]
direction TB
A["Traffic thấp / thất thường<br/>(vùng A)"] -->|"Serverless RẺ HƠN<br/>không trả phí idle capacity"| B["Điểm giao (break-even point)<br/>Chi phí Serverless = Chi phí Fixed-Capacity"]
B --> C["Traffic cao / ổn định liên tục<br/>(vùng B)"]
C -->|"Fixed-Capacity RẺ HƠN<br/>economies of scale"| D["Chi phí Serverless > Chi phí Fixed-Capacity<br/>bẫy chi phí xuất hiện ở đây"]
end
subgraph Decision["Quyết định kiến trúc"]
E["Ước tính traffic đỉnh dự kiến"] --> F{"Traffic ổn định<br/>và cao liên tục?"}
F -->|Không, thất thường/bùng nổ| G["Chọn Serverless (FaaS)<br/>Lambda / Cloud Functions"]
F -->|Có, dự đoán được & liên tục| H["Chọn Fixed-Capacity<br/>Container/VM cấp phát trước<br/>+ auto-scaling biên"]
F -->|Hỗn hợp| I["Kiến trúc lai (hybrid)<br/>Core service: fixed-capacity<br/>Burst/event handler: serverless"]
end
G -.->|áp dụng khi ở| A
H -.->|áp dụng khi ở| C
Đường break-even trong thực tế không phải là một con số cố định — nó phụ thuộc vào runtime, memory allocation, region, và cấu trúc giá của từng nhà cung cấp tại thời điểm bạn tính. Điều bất biến là NGUYÊN TẮC: luôn tồn tại một điểm giao, và vị trí của workload bạn so với điểm đó — chứ không phải xu hướng công nghệ — mới là căn cứ quyết định.
Implementation Guardrails
Mô hình hóa chi phí ở tải đỉnh dự kiến TRƯỚC KHI cam kết serverless cho bất kỳ luồng traffic cao nào. Không dựa vào ước tính traffic hiện tại — dùng traffic đỉnh dự kiến trong 12-18 tháng tới (kể cả kịch bản tăng trưởng lạc quan). Tính chi phí serverless ở mức đó và so sánh trực tiếp với chi phí container/VM cấp phát tương đương. Nếu chênh lệch trong khoảng 20% trở xuống, ưu tiên fixed-capacity vì tính dự đoán được cao hơn.
Đặt cảnh báo ngân sách (budget alert) theo NGƯỠNG TUYỆT ĐỐI, không chỉ theo phần trăm tăng trưởng. Vì chi phí serverless tuyến tính theo traffic, một sự kiện bất thường (bot traffic, retry storm do bug ở client, DDoS nhẹ) có thể nhân chi phí lên gấp nhiều lần trong vài giờ trước khi ai đó nhận ra. Cấu hình alert ở nhiều mức (50%, 80%, 100% ngân sách tháng dự kiến) và gắn action tự động (throttle, circuit breaker) ở mức cao nhất — không chỉ gửi email.
Không dùng serverless cho service lõi có SLA latency chặt trừ khi đã kiểm chứng cold-start bằng load test thực tế, hoặc đã ngân sách cho provisioned concurrency (và tính chi phí đó vào so sánh ở guardrail #1 — vì provisioned concurrency phá vỡ giả định "chỉ trả khi dùng").
Thiết kế function để có thể chạy độc lập với vendor-specific trigger binding ở phần lõi business logic. Tách rõ "adapter layer" (nhận event từ Lambda trigger, API Gateway, EventBridge...) khỏi "domain logic layer" thuần túy. Đây là ứng dụng trực tiếp của Hexagonal Architecture (xem Bài 16) — nó không loại bỏ vendor lock-in ở tầng hạ tầng, nhưng giảm đáng kể chi phí di chuyển logic nghiệp vụ nếu phải đổi nhà cung cấp.
Architect's Verdict
Serverless không phải là "kiến trúc hiện đại hơn" so với container hay VM — nó là một công cụ đúng cho một hình dạng traffic cụ thể: bùng nổ, thất thường, hoặc tải nền thấp theo sự kiện. Dùng nó cho đúng chỗ đó, nó xuất sắc và tiết kiệm thật.
Dùng nó cho service lõi có thông lượng cao, ổn định, chạy liên tục 24/7 — vì lý do "đồng bộ kiến trúc" hay "vì ai cũng đang serverless" — gần như luôn là một sai lầm tốn kém, chỉ là hóa đơn đến chậm vài tháng nên ít ai nối được nhân quả. Nghĩa vụ của kiến trúc sư không phải là chọn cái mới nhất, mà là đặt đúng workload lên đúng điểm trên đường cong chi phí — và điều đó đòi hỏi làm phép tính TRƯỚC khi ký hợp đồng kiến trúc, không phải sau khi nhận hóa đơn.
🔗 Bài viết liên quan: Event-Driven Architecture (EDA) — serverless thường là hạ tầng thực thi tự nhiên cho các event handler trong kiến trúc hướng sự kiện. Cost Optimization — đào sâu hơn về tư duy tài chính của kiến trúc sư, áp dụng cho mọi lựa chọn hạ tầng chứ không riêng serverless.
Bài trước: Event-Driven Architecture (EDA) · Bài tiếp theo: Service-Oriented Architecture (SOA) thời đại mới