Mới54 bài học mới được bổ sung từ 10/09!
Xem nhật ký cập nhật →
Software Development Atlas
Phán đoán kỹ thuậtHướng dẫn ra quyết định

Containers vs Serverless: Hướng dẫn ra quyết định kiến trúc

Khung tư duy kỹ thuật để lựa chọn giữa mô hình tính toán container và serverless dựa trên quyền kiểm soát tiến trình, độ trễ cold start, mô hình chi phí và backpressure.

Phát triểnĐã xác minh: 5 thg 11, 2026Đánh giá lại: 180 ngày

Bản đồ học tập phát triển phần mềm bởi Tran Trong Thuc · Về dự án Atlas · Cập nhật lần cuối: 5 thg 11, 2026

Tóm tắt nhanh (TL;DR)

Ví dụ giả định: Một nhóm phát triển thanh toán phát hiện độ trễ khởi động instance mới ảnh hưởng đến request có ngân sách thời gian thấp. Khi lưu lượng trở nên ổn định, nhóm cũng nhận thấy cần so sánh lại chi phí serverless với công suất được cấp phát trước. Không có một thời gian cold start hoặc tỷ lệ chênh lệch giá cố định cho mọi nền tảng; quyết định cần dựa trên số liệu đo, mức sử dụng và toàn bộ chi phí vận hành.

💡 Quy tắc bỏ túi: Container là cách đóng gói ứng dụng; serverless là mô hình giao trách nhiệm cấp phát và vận hành hạ tầng cho nền tảng. Hai khái niệm có thể cùng tồn tại, như Cloud Run. Hãy chọn dựa trên tải thực tế, ngân sách độ trễ, thời lượng kết nối, quyền kiểm soát runtime và tổng chi phí, thay vì coi một mô hình luôn rẻ hoặc nhanh hơn.

  • Ranh giới đóng gói khác biệt với mô hình vận hành: Container image đóng gói mã nguồn và môi trường thực thi; nền tảng serverless tự động quản lý hạ tầng và co giãn instance. Một ứng dụng hoàn toàn có thể vừa chạy container vừa mang tính chất serverless (như Google Cloud Run hoặc AWS Fargate).
  • Độ trễ khi khởi tạo ảnh hưởng request path: Nền tảng có thể phải tạo instance khi tăng tải hoặc sau giai đoạn scale-to-zero. Hãy đo p95/p99 theo sản phẩm và cân nhắc minimum instances hoặc provisioned concurrency nếu cần, cùng với chi phí giữ ấm.
  • Lưu lượng ảnh hưởng tổng chi phí: Scale-to-zero giúp giảm chi phí khi ít request, còn công suất cấp phát trước có thể hợp lý với tải ổn định. Phải đo chi phí compute, công suất giữ ấm, mạng, log và vận hành thay vì mặc định một mô hình luôn rẻ hơn.
  • Đánh giá hợp đồng kỹ thuật cụ thể của nền tảng được chọn: Tên gọi "serverless" không tự động đảm bảo hiệu năng; bắt buộc phải rà soát kỹ các cơ chế co giãn, khởi động, độ đồng thời (concurrency), vòng đời tiến trình và mô hình tính cước của nhà cung cấp.
  • Rủi ro cần kiểm soát: Một tầng compute co giãn nhanh hơn khả năng chịu tải của database có thể làm cạn connection pool. Hãy giới hạn concurrency hoặc sử dụng queue, connection proxy phù hợp với nền tảng và số liệu thực tế.

Hai ranh giới cốt lõi: Đóng gói vs Vận hành

Mô hình đóng gói so với mô hình vận hành
Phương ánCode / zipOCI image
VM tự quản lýTriển khai processContainer runtime
Cluster được quản lýÍt phổ biếnContainer được quản lý
Serverless executionFunctionsDịch vụ container serverless
“Container” mô tả ranh giới đóng gói; “serverless” mô tả mô hình vận hành. Hai khái niệm có thể giao nhau.
Cold start so với warm start
Cold start
Cấp phát
Nạp runtime
Khởi tạo app
Xử lý request
Warm start
Tái sử dụng môi trường
Xử lý request
Cold start thêm bước cấp phát và khởi tạo trước khi xử lý request; warm start tái sử dụng môi trường sẵn có.

Ma trận so sánh tiêu chí kỹ thuật

Ma trận so sánh Containers và Serverless
Tiêu chíContainer truyền thống (K8s/ECS)Serverless (Lambda/Cloud Run)
Khả năng kiểm soát Runtime & OSToàn quyền cấu hình OS kernel flags, sidecars, file system nềnBị giới hạn trong sandbox do nhà cung cấp đám mây quy định
Độ trễ khởi động (Startup Latency)Instance luôn sẵn sàng (0ms trễ khởi động)Tiềm ẩn Cold Start khi có đột biến lưu lượng mới
Mô hình thanh toánTrả phí theo tài nguyên cấp phát tĩnh (Provisioned Capacity)Chỉ trả tiền theo thời gian xử lý thực tế (Pay-per-request)
Quản lý trạng thái & Kết nối dài hạnHỗ trợ tuyệt vời cho WebSockets, hàng đợi bộ nhớ, nền tảng statefulƯu tiên kiến trúc Stateless; ngắt kết nối khi hết thời gian chờ

Khung quyết định: điều gì thực sự thay đổi lựa chọn?

Trước khi chọn sản phẩm, xác định năm ràng buộc: hình thái lưu lượng (đều hay đột biến), ngân sách độ trễ (kể cả cold start), vòng đời công việc (request ngắn hay kết nối dài), những tài nguyên cần kiểm soát và khả năng vận hành của đội ngũ.

  • Compute theo container được cấp phát trước có thể phù hợp khi cần kiểm soát runtime, đường đi mạng và công suất ổn định. Đổi lại, đội ngũ chịu nhiều trách nhiệm hơn về cluster, capacity, nâng cấp và sự cố.
  • Dịch vụ serverless quản lý theo nhu cầu phù hợp khi ưu tiên giảm gánh nặng vận hành hoặc lưu lượng không đều. Đổi lại, phải hiểu rõ giới hạn thời gian chạy, đồng thời, startup, state và chính sách tính cước.
  • Serverless chạy container là lựa chọn giao nhau, không phải trường hợp ngoại lệ: Cloud Run nhận container image nhưng Google quản lý vòng đời instance theo hợp đồng dịch vụ.

Cả hai mô hình có thể dùng chung một hệ thống

Ví dụ, API nhận yêu cầu có thể chạy trên nền tảng serverless container, worker xử lý dài chạy trên cụm container, còn event xử lý ngắn dùng function. Quyết định cần theo từng workload, không nhất thiết chọn một công nghệ duy nhất cho toàn hệ thống.

Khi so chi phí, hãy thử nhiều kịch bản: giờ ít tải, giờ cao điểm, mức capacity phải giữ sẵn, concurrency mỗi instance, chi phí mạng, kết nối tới database và thời gian xử lý sự cố. Đừng kết luận “serverless đắt gấp nhiều lần” chỉ từ một ví dụ giả định.

Những failure mode cần đưa vào đánh giá

  • Cold start: đo p95/p99 theo môi trường cụ thể; dùng minimum instance hoặc provisioned concurrency nếu cần và tính cả chi phí giữ ấm.
  • Downstream overload: scale compute không đồng nghĩa database, quota API hoặc connection pool cũng scale cùng tốc độ. Cần backpressure, queue và giới hạn concurrency.
  • State và kết nối: kết nối WebSocket dài có thể được hỗ trợ trên một số nền tảng serverless container, nhưng phải tính timeout, reconnect, chi phí active instance và cơ chế truyền thông điệp giữa các instance.
  • Khả năng di chuyển: dùng OCI image không làm IAM, networking, event trigger và cơ chế autoscaling trở nên giống nhau giữa các nhà cung cấp.

Tình huống minh họa (giả định): quá tải kết nối database

Một công ty thương mại điện tử chuyển đổi webhook xử lý đơn hàng từ cụm container cố định sang các serverless functions để "tiết kiệm chi phí và tự động co giãn":

Avalanche xuống downstream từ serverless
  1. Traffic burst
    Sự kiện vào tăng 40×
  2. 1.500 workers
    Platform scale thành công
  3. 150 kết nối DB
    Giới hạn downstream cố định
  4. Chuỗi timeout
    Cạn connection pool
Compute co giãn có thể scale nhanh hơn nhiều so với database hoặc dependency có giới hạn cố định.
  • Hậu quả: Trong đợt Flash Sale, lưu lượng tăng vọt 40 lần. Nền tảng Serverless co giãn mượt mà lên 1,500 functions đồng thời — và ngay lập tức làm tràn ngưỡng giới hạn 150 kết nối tối đa của PostgreSQL chính. Toàn bộ cơ sở dữ liệu rơi vào tình trạng treo nghẽn, kéo sập cả luồng thanh toán chính của website.
  • Nguyên nhân cốt lõi: Đội ngũ kỹ thuật quên rằng: khả năng co giãn của compute không đồng nghĩa với khả năng chịu tải của database hạ tầng. Trong mô hình container, connection pool được duy trì cố định (ví dụ 10 container x 10 connection = 100 connection). Khi chuyển sang serverless, mỗi invocation độc lập mở một kết nối mới trực tiếp.
  • Cách khắc phục chuẩn: Bắt buộc phải đặt một tầng proxy quản lý kết nối (như AWS RDS Proxy, PgBouncer) hoặc giới hạn Concurrency tối đa của function để áp dụng áp lực ngược (Backpressure).

Điểm giao thoa chi phí (Cost Crossover Point)

Điểm giao chi phí minh họa
Compute tính theo mức dùngContainer / VM có capacity cố định
Đường cong chi phí thực tế phụ thuộc giá nhà cung cấp và hình dạng workload; hãy so sánh mô hình đo được thay vì khẩu hiệu.

Rèn luyện mô hình tư duy

Tình huống: Một đội ngũ xây dựng dịch vụ thông báo nội bộ. Ứng dụng web của client duy trì kết nối WebSocket thường trực để nhận thông báo đẩy thời gian thực. Lưu lượng dự kiến chỉ vài tin nhắn mỗi giờ trên mỗi kết nối, với 50,000 client kết nối ở trạng thái chờ (idle) vào giờ cao điểm.

Kỹ sư trưởng đề xuất: "Hãy dùng serverless functions theo nhu cầu mà không cần hạ tầng container, vì lượng tin nhắn rất ít và chúng ta chỉ trả tiền khi tin nhắn thực sự được xử lý."

Mô hình compute này có phù hợp với khối lượng công việc này không?

Xem giải thích chi tiết

Tại sao đề xuất này chứa rủi ro lớn:

Dù việc chuyển phát tin nhắn mang tính rải rác và hướng sự kiện (event-driven), nhưng mô hình kết nối lại mở liên tục và có trạng thái (stateful):

  1. Thời lượng kết nối và chi phí: Không có giới hạn thời gian chạy 15 phút áp dụng cho mọi serverless. AWS Lambda thông thường có giới hạn 15 phút; một số chế độ bất đồng bộ của Lambda Managed Instances hỗ trợ lâu hơn. Cloud Run hỗ trợ WebSocket nhưng kết nối vẫn chịu request timeout (tối đa 60 phút theo cấu hình) và chi phí khi instance đang hoạt động. 50.000 client không đồng nghĩa 50.000 instance: cần đo số kết nối mỗi instance, yêu cầu reconnect và ngân sách chi phí.
  2. Quyền sở hữu kết nối và định tuyến: Mỗi socket đang mở được một instance cụ thể giữ; lần kết nối lại có thể tới instance khác. Cần cơ chế pub/sub, chia sẻ trạng thái hoặc WebSocket gateway để đưa thông báo đến đúng client, không phụ thuộc địa chỉ tiến trình cố định.

Kiến trúc phù hợp hơn:

  • Dùng worker chạy bằng container được tối ưu cho I/O concurrency cao (nơi hàng nghìn socket chờ chỉ tiêu tốn lượng RAM/CPU rất nhỏ trong Node.js hoặc Go).
  • Hoặc chọn nền tảng serverless container hỗ trợ WebSocket như Cloud Run và thiết kế timeout, reconnect, concurrency, backplane phát thông điệp. Một WebSocket gateway quản lý kết nối kết hợp function ngắn hạn cũng là lựa chọn hợp lý.

Checklist rà soát kiến trúc cho Kỹ sư

  • Mô hình kết nối: Có cần WebSocket hoặc TCP lâu dài không? Nền tảng cụ thể có hỗ trợ, giới hạn timeout, reconnect và billing nào?
  • Bảo vệ hệ thống hạ tầng (Backpressure): Đã thiết lập giới hạn concurrency hoặc connection pooler giữa serverless compute và database chưa?
  • Giới hạn thời gian: Đã kiểm tra timeout theo sản phẩm, loại invocation và chế độ triển khai thực tế thay vì giả định mọi serverless đều giới hạn 15 phút?
  • Độ nhạy cảm với Cold Start: Các endpoint API then chốt có chịu được độ trễ phát sinh vài trăm mili-giây khi scale từ 0 lên không?
  • Khả năng quan sát (Observability): Đã thiết lập hệ thống trace phân tán (Distributed Tracing) để theo dõi các function có vòng đời ngắn chưa?

Nguồn tham khảo

Mục lục bài học