Mở đầu — vì sao bài này quan trọng
Hãy hình dung một buổi tối 10 giờ, một sàn thương mại điện tử ở TP.HCM chạy flash sale. Lượng truy cập tăng gấp 8 lần trong vòng 3 phút. Nếu hệ thống chỉ có một số lượng server cố định, bạn sẽ đối mặt với hai kịch bản tồi tệ: hoặc là server quá tải, trang treo, khách bỏ giỏ hàng và doanh thu bay hơi; hoặc là bạn đã "phòng thủ" bằng cách chạy sẵn 50 server 24/7 cho một sự kiện chỉ diễn ra vài giờ mỗi tháng — nghĩa là đốt tiền vô nghĩa suốt 700 giờ còn lại.
Auto-scaling ra đời để giải quyết đúng bài toán này: hệ thống tự động thêm hoặc bớt tài nguyên theo nhu cầu thực tế, để bạn vừa chịu được đỉnh tải, vừa không lãng phí khi tải thấp. Đây là một trong những kỹ năng nền tảng của một kỹ sư vận hành hiện đại, đặc biệt trong thời đại cloud khi mà bạn trả tiền theo từng phút sử dụng.
Nhưng auto-scaling không phải là công tắc "bật là chạy". Cấu hình sai một tham số, hệ thống có thể dao động liên tục (scale lên rồi xuống rồi lên), hoặc phản ứng quá chậm khiến người dùng vẫn nếm trải sự cố trước khi instance mới kịp sẵn sàng. Bài này sẽ giúp bạn hiểu hai chiều scale, các pattern kích hoạt, và quan trọng nhất là những cái bẫy khiến auto-scaling phản tác dụng.
Khái niệm cốt lõi
Hai chiều scale: Vertical và Horizontal
Có đúng hai cách để làm cho hệ thống của bạn "khỏe hơn":
Vertical scaling (scale up/down) — tăng kích thước của chính một instance. Bạn thay một máy 4 vCPU / 8 GB RAM bằng máy 16 vCPU / 64 GB RAM. Đơn giản về mặt kiến trúc vì ứng dụng không cần biết gì cả, nó chỉ đơn giản có nhiều tài nguyên hơn. Nhưng vertical scaling có giới hạn cứng: không có cái máy nào lớn vô hạn. Trên AWS, dù bạn chọn instance to nhất cũng chỉ đến vài trăm vCPU. Và quan trọng hơn, việc scale up thường cần restart hoặc thay thế instance, gây gián đoạn dịch vụ trong giây lát. Vertical scaling phù hợp nhất cho những thành phần khó chia nhỏ như database chính (primary).
Horizontal scaling (scale out/in) — thêm nhiều instance giống hệt nhau và chia tải giữa chúng qua một load balancer. Thay vì một máy khổng lồ, bạn có 20 máy vừa phải. Đây là hướng đi chủ đạo của cloud-native vì nó gần như không có trần (bạn cứ thêm máy), và tăng cả khả năng chịu lỗi — một máy chết thì 19 máy còn lại vẫn phục vụ. Đổi lại, ứng dụng phải được thiết kế stateless: không lưu trạng thái phiên (session) trong bộ nhớ local, mà đẩy ra Redis/database chung, để bất kỳ request nào cũng có thể được xử lý bởi bất kỳ instance nào.
Một cách ghi nhớ: vertical là "làm con bò to hơn", horizontal là "nuôi thêm nhiều con gà". Cloud khuyến khích nuôi gà.
Cơ chế kích hoạt: scale theo cái gì?
Auto-scaling cần một tín hiệu để quyết định khi nào thêm/bớt. Có ba nhóm chính:
- Metric-based (theo chỉ số) — phổ biến nhất. Ví dụ: "nếu CPU trung bình của nhóm vượt 70% trong 3 phút, thêm 2 instance". Ngoài CPU còn có memory, số request mỗi giây, độ dài hàng đợi (queue depth). Với ứng dụng web, số request per target hoặc độ trễ (latency) thường là tín hiệu tốt hơn CPU.
- Schedule-based (theo lịch) — bạn biết trước quy luật. Ví dụ một ngân hàng số biết 8h sáng mỗi ngày là giờ cao điểm chuyển khoản, nên cứ 7h45 tự nâng số instance lên. Loại này chủ động, tránh được độ trễ phản ứng của metric-based.
- Predictive (dự báo) — dùng machine learning phân tích lịch sử tải để dự đoán và scale trước. AWS có Predictive Scaling; loại này mạnh nhưng cần dữ liệu lịch sử ổn định để dự báo chính xác.
Các tham số sống còn
Ba con số bạn phải nắm khi cấu hình một auto-scaling group:
- Min / Max / Desired — số lượng instance tối thiểu, tối đa và mong muốn hiện tại. Min bảo vệ bạn khỏi việc scale xuống 0 gây gián đoạn; Max là "phanh tay" chống chi phí bùng nổ.
- Cooldown / Stabilization window — khoảng thời gian chờ sau một hành động scale trước khi cho phép hành động tiếp theo. Nếu không có, hệ thống có thể "giật cục" liên tục.
- Warm-up time — thời gian một instance mới cần để khởi động, tải ứng dụng, làm nóng cache trước khi thực sự nhận tải. Đây là kẻ thù thầm lặng của auto-scaling — nếu instance mất 4 phút để sẵn sàng, thì phản ứng của bạn luôn trễ 4 phút so với nhu cầu.
Tình huống thực tế
Ví dụ 1 — Sàn TMĐT Đông Nam Á và cú flash sale 12.12
Một sàn thương mại điện tử giả định tên "ShopViet" chạy trên AWS với Auto Scaling Group cho tầng web. Cấu hình ban đầu: min 6, max 40 instance, scale khi CPU > 70%. Trong ngày sale 12.12, đúng 0h00 họ tung mã giảm giá. Traffic vọt lên gấp 10 lần chỉ trong 90 giây.
Vấn đề xảy ra: instance của họ chạy một image nặng, mất gần 5 phút từ lúc khởi tạo đến khi vào phục vụ (cài dependency, tải code, kết nối database). Trong 5 phút đó, 6 instance ban đầu bị quá tải, latency vọt lên 8 giây, nhiều khách nhận lỗi 503.
Bài học rút ra: metric-based scaling phản ứng đúng nhưng quá muộn vì warm-up quá dài. Sau sự cố, đội ShopViet làm hai việc. Thứ nhất, họ "nướng" (bake) sẵn một Golden AMI có đầy đủ dependency và code, giảm warm-up xuống còn 45 giây. Thứ hai, với sự kiện đã biết trước như 12.12, họ dùng scheduled scaling để nâng min lên 25 instance từ 23h30 hôm trước — không đợi metric phản ứng nữa. Kết quả sự kiện sau đó: không còn lỗi 503, latency giữ dưới 400ms.
Ví dụ 2 — Startup fintech và cái bẫy scale theo CPU
Một startup fintech ở Hà Nội xây dịch vụ chấm điểm tín dụng. Workload của họ là gọi API bên thứ ba rồi chờ phản hồi — tức là I/O-bound, phần lớn thời gian instance ngồi chờ mạng chứ không tính toán. Họ cấu hình auto-scaling theo CPU > 80%.
Kết quả: mỗi instance chỉ dùng 20% CPU nhưng đã "nghẹt" vì mở quá nhiều kết nối chờ. CPU không bao giờ chạm 80% nên auto-scaling không bao giờ kích hoạt, trong khi hàng đợi request phình to và người dùng chờ mòn mỏi. Hệ thống "khỏe" theo mắt CPU nhưng thực chất đang chết đứng.
Bài học rút ra: phải chọn tín hiệu phản ánh đúng điểm nghẽn thực. Đội chuyển sang scale theo số request đang xử lý đồng thời (in-flight requests) và độ dài hàng đợi. Sau khi đổi metric, hệ thống scale đúng lúc và độ trễ p99 giảm 60%. Nguyên tắc: CPU chỉ đúng cho workload CPU-bound; với I/O-bound hãy dùng queue depth, concurrency hoặc latency.
Ví dụ 3 — Thrashing vì cooldown quá ngắn
Một công ty game mobile khu vực Đông Nam Á cấu hình: scale out khi CPU > 60%, scale in khi CPU < 40%, không đặt cooldown hợp lý. Khi tải dao động quanh mức 50%, chuyện gì xảy ra? Thêm instance → tải phân bổ ra → CPU tụt xuống 38% → bớt instance → tải dồn lại → CPU vọt lên 62% → thêm lại. Vòng lặp này lặp mỗi vài phút, gọi là thrashing hay flapping.
Hậu quả kép: mỗi lần tạo instance mới đều tốn tiền (nhiều nhà cung cấp tính tối thiểu theo giờ), và mỗi lần terminate lại ngắt các kết nối đang phục vụ. Hệ thống bận rộn "co giãn" nhưng chẳng phục vụ tốt hơn.
Bài học rút ra: cần khoảng đệm (hysteresis) giữa ngưỡng lên và xuống đủ rộng, cộng thêm cooldown sau mỗi lần scale, và scale in chậm hơn scale out. Đội này đổi sang: scale out khi > 65%, scale in khi < 35%, cooldown 5 phút cho scale in. Thrashing biến mất.
Hướng dẫn từng bước
Đây là quy trình thiết lập một auto-scaling policy an toàn, áp dụng được cho hầu hết nền tảng (AWS ASG, GCP MIG, Kubernetes HPA):
- Đảm bảo ứng dụng stateless trước. Trước khi nghĩ đến horizontal scaling, kiểm tra rằng không có session, file upload tạm, hay cache quan trọng nằm trong bộ nhớ local của instance. Đẩy hết ra dịch vụ dùng chung (Redis, S3, database). Nếu bỏ qua bước này, thêm instance sẽ gây lỗi khó lường.
- Chọn đúng metric kích hoạt. Hỏi: điểm nghẽn thật của hệ thống là gì? CPU-bound thì dùng CPU; web thì dùng request-per-target hoặc latency; hệ thống xử lý hàng đợi thì dùng queue depth. Đừng mặc định chọn CPU.
- Đặt Min / Max / Desired có cơ sở. Min = số instance đủ chịu tải đáy vào lúc vắng nhất (đừng để 1, vì mất 1 là mất hết). Max = giới hạn ngân sách bạn chấp nhận được nếu bị tấn công hoặc lỗi. Tính thử: nếu Max instance chạy full 1 tháng thì hóa đơn là bao nhiêu?
- Rút ngắn warm-up. Bake sẵn image (Golden AMI / container image có sẵn code), tránh cài dependency lúc boot. Dùng health check đo đúng thời điểm instance thật sự sẵn sàng, không chỉ "máy đã bật".
- Cấu hình hysteresis và cooldown. Đặt ngưỡng scale out thấp hơn (nhạy hơn) và scale in cao hơn khoảng cách đủ rộng. Scale out nhanh, scale in chậm — thà thừa vài phút còn hơn ngắt dịch vụ.
- Bật graceful shutdown (connection draining). Khi scale in, load balancer phải ngừng gửi request mới tới instance sắp tắt và chờ các request đang chạy hoàn tất (thường 30–120 giây) trước khi terminate.
- Thử tải và quan sát. Chạy load test mô phỏng đỉnh tải, theo dõi xem instance mới lên kịp không, có thrashing không, latency trong lúc scale ra sao. Điều chỉnh tham số dựa trên dữ liệu thật.
- Đặt alert cho ranh giới. Cảnh báo khi chạm Max (có thể đang bị tấn công hoặc cấu hình sai), và khi số instance duy trì ở Min quá lâu (có thể đang lãng phí, nên hạ Min).
Lỗi thường gặp & mẹo
- Nhầm auto-scaling là thuốc chữa bách bệnh. Nếu điểm nghẽn nằm ở database chính (chỉ có một primary), thêm bao nhiêu web instance cũng vô ích — bạn chỉ đang dồn thêm áp lực lên database. Hãy xác định điểm nghẽn thật trước.
- Scale theo CPU cho workload I/O-bound. Như ví dụ fintech: CPU thấp nhưng hệ thống vẫn nghẽn. Luôn khớp metric với bản chất workload.
- Quên đặt Max hợp lý. Một vòng lặp lỗi hoặc một đợt tấn công DDoS có thể khiến auto-scaling thêm hàng trăm instance, tạo ra "hóa đơn kinh hoàng" cuối tháng. Max chính là phanh tay tài chính.
- Bỏ qua warm-up. Đây là lý do phổ biến nhất khiến auto-scaling "không cứu được" trong sự cố. Instance lên đúng nhưng quá muộn. Bake image và giữ một lượng dự phòng nóng (warm pool) cho các đỉnh đột ngột.
- Không có connection draining. Scale in mà cắt phăng instance đang phục vụ sẽ gây lỗi cho người dùng ngay giữa giao dịch. Luôn bật draining.
- Mẹo — scale out mạnh tay, scale in dè dặt. Chi phí của việc thiếu instance (mất khách, mất doanh thu) thường lớn hơn nhiều chi phí thừa vài instance trong ít phút. Cấu hình cho hệ thống "hào phóng" khi lên và "thận trọng" khi xuống.
- Mẹo — kết hợp với reserved/spot capacity. Giữ phần tải đáy (baseline) trên instance đặt trước (reserved, giá rẻ), và để auto-scaling xử lý phần đỉnh bằng on-demand hoặc spot. Vừa co giãn vừa tối ưu chi phí.
Bài tập thực hành
- Chọn metric. Cho ba dịch vụ sau, hãy chọn metric kích hoạt phù hợp và giải thích: (a) một API render ảnh (nén, resize) chạy nặng CPU; (b) một worker đọc message từ hàng đợi RabbitMQ rồi gọi API bên ngoài; (c) một trang web tin tức chủ yếu trả nội dung tĩnh. Gợi ý: lần lượt là CPU, queue depth, và request-per-target hoặc latency.
- Tính chi phí Max. Instance của bạn giá 0,10 USD/giờ. Bạn đặt Max = 60. Nếu một sự cố khiến hệ thống chạy full Max liên tục 3 ngày mà không ai phát hiện, hóa đơn phát sinh là bao nhiêu? Con số này có nằm trong ngưỡng bạn chấp nhận được không, và bạn sẽ đặt alert ở mức nào?
- Chẩn đoán thrashing. Bạn thấy đồ thị số instance dao động lên xuống mỗi 4 phút suốt cả ngày dù traffic khá ổn định quanh mức trung bình. Hãy liệt kê ba nguyên nhân khả dĩ và cách khắc phục tương ứng.
- Thiết kế cho sự kiện đã biết. Công ty bạn có livestream bán hàng vào 20h mỗi tối thứ Sáu, traffic tăng gấp 6 lần trong 15 phút. Hãy đề xuất cấu hình scaling kết hợp schedule-based và metric-based, nêu rõ mốc thời gian nâng min và ngưỡng metric làm lưới an toàn.
Tóm tắt
Auto-scaling là công cụ để hệ thống tự điều chỉnh tài nguyên theo nhu cầu, giúp vừa chịu được đỉnh tải vừa không lãng phí lúc tải thấp. Có hai chiều: vertical (làm instance to hơn, đơn giản nhưng có trần cứng và cần restart) và horizontal (thêm nhiều instance, gần như không trần và tăng chịu lỗi, nhưng đòi hỏi ứng dụng stateless) — cloud-native ưu tiên horizontal.
Kích hoạt scaling dựa trên metric, lịch, hoặc dự báo; đội mạnh thường kết hợp cả ba. Ba tham số sống còn là Min/Max/Desired, cooldown, và warm-up time. Những cái bẫy lớn nhất là: chọn sai metric cho workload (đặc biệt dùng CPU cho I/O-bound), bỏ qua warm-up khiến phản ứng quá trễ, thrashing do thiếu hysteresis/cooldown, và quên đặt Max khiến chi phí bùng nổ.
Nguyên tắc vàng để mang theo: xác định đúng điểm nghẽn trước khi scale, chọn metric phản ánh đúng bản chất workload, scale out mạnh tay và scale in dè dặt, luôn rút ngắn warm-up và bật connection draining. Làm đúng những điều này, auto-scaling sẽ là tấm lưới an toàn thật sự — chứ không phải một cấu hình đẹp trên giấy nhưng bó tay đúng lúc bạn cần nó nhất.