Mở đầu — vì sao bài này quan trọng
Hãy tưởng tượng bạn là kỹ sư vận hành của một sàn thương mại điện tử Việt Nam. Đội marketing vừa chốt xong chiến dịch flash sale 12/12: giảm giá sốc lúc 0h, dự kiến lượng truy cập gấp 20 lần ngày thường. Câu hỏi mà sếp hỏi bạn — và bạn buộc phải trả lời trước khi chiến dịch chạy — rất đơn giản: "Hệ thống có chịu nổi không?"
Nếu bạn trả lời "chắc là được" mà không có số liệu, bạn đang đánh bạc với doanh thu của cả công ty. Load testing (kiểm thử tải) chính là công cụ để biến câu "chắc là được" thành một câu trả lời có bằng chứng: "Hệ thống chịu được 8.000 request/giây với thời gian phản hồi dưới 300ms; vượt 10.000 request/giây thì database bắt đầu nghẽn." Đó là sự khác biệt giữa một đội vận hành chuyên nghiệp và một đội chỉ biết cầu nguyện.
Trong khóa học này, bạn đã học về capacity planning (Bài 13) — cách ước lượng nhu cầu và headroom trên giấy. Load testing là bước đi tiếp theo và thực chiến hơn: bạn không đoán nữa, bạn đo. Bạn tạo ra tải nhân tạo, quan sát hệ thống phản ứng thế nào, và tìm ra điểm gãy trước khi người dùng thật tìm ra nó giúp bạn. Bài này tập trung riêng vào các loại kiểm thử tải, công cụ, và phương pháp thực hiện. Đây là kỹ năng mà bất kỳ SRE hay DevOps engineer nào cũng cần nắm vững.
Khái niệm cốt lõi
Load testing là gì và không phải là gì
Load testing là quá trình tạo ra lưu lượng truy cập nhân tạo (traffic mô phỏng người dùng thật) để đo lường cách hệ thống hoạt động dưới tải. Mục tiêu không phải là "làm sập hệ thống cho vui", mà là trả lời những câu hỏi cụ thể:
- Hệ thống phục vụ được bao nhiêu người dùng đồng thời với chất lượng chấp nhận được?
- Thời gian phản hồi (latency) thay đổi ra sao khi tải tăng?
- Điểm gãy (breaking point) nằm ở đâu, và bộ phận nào gãy trước?
- Sau khi quá tải, hệ thống có tự phục hồi được không?
Bốn loại kiểm thử tải phổ biến
Đây là phần quan trọng nhất cần nắm. Mỗi loại trả lời một câu hỏi khác nhau, và việc chọn nhầm loại test là lỗi kinh điển của người mới.
1. Load test (kiểm thử tải kỳ vọng). Bạn chạy đúng mức traffic dự kiến trong thực tế, kéo dài đủ lâu (thường 15–60 phút), để xem hệ thống có ổn định không. Ví dụ: nếu ngày cao điểm bạn dự kiến 5.000 request/giây, bạn bắn đúng 5.000 request/giây và quan sát latency, tỷ lệ lỗi, mức sử dụng CPU/RAM. Đây là loại test cơ bản nhất, trả lời câu hỏi: "Với tải bình thường, hệ thống có khỏe không?"
2. Stress test (kiểm thử quá tải). Bạn cố tình đẩy tải vượt quá ngưỡng kỳ vọng để tìm điểm gãy. Tăng dần từ 5.000 lên 8.000, 10.000, 15.000 request/giây cho tới khi hệ thống bắt đầu trả lỗi hoặc latency vọt lên không chấp nhận được. Stress test trả lời: "Giới hạn thật sự của tôi ở đâu, và cái gì gãy trước — database, application server, hay load balancer?" Nó cũng cho biết hệ thống gãy như thế nào: gãy êm (degrade dần) hay gãy đột ngột (sập hẳn).
3. Spike test (kiểm thử tải đột biến). Thay vì tăng dần, bạn tạo ra một cú tăng vọt tức thời — ví dụ từ 500 lên 10.000 request/giây trong vài giây. Đây là kịch bản của flash sale, mở bán vé concert, hay khi một bài đăng viral. Spike test kiểm tra khả năng auto-scaling phản ứng kịp không, và hệ thống có sống sót qua cú sốc ban đầu trước khi kịp mở rộng không.
4. Soak test (kiểm thử tải bền / endurance test). Bạn chạy tải vừa phải nhưng kéo dài rất lâu — vài giờ đến vài ngày. Mục đích là phát hiện những vấn đề chỉ lộ ra theo thời gian: memory leak (rò rỉ bộ nhớ tích lũy dần), connection pool cạn kiệt, disk đầy do log, hay database index phình to. Một hệ thống có thể vượt load test 30 phút hoàn hảo nhưng sập sau 18 giờ chạy liên tục vì rò rỉ bộ nhớ.
Các chỉ số cần quan sát
Chạy test mà không biết nhìn số liệu thì vô nghĩa. Những chỉ số cốt lõi:
- Throughput: số request xử lý được mỗi giây (RPS/QPS). Đây là "công suất".
- Latency theo percentile: đừng nhìn latency trung bình — nó lừa bạn. Hãy nhìn p50 (trung vị), p95, p99. Nếu p99 = 2 giây nghĩa là 1% người dùng của bạn phải chờ 2 giây, và 1% của một triệu người là mười nghìn người bực bội.
- Error rate: tỷ lệ request trả về lỗi (5xx, timeout).
- Tài nguyên hệ thống: CPU, RAM, disk I/O, network, số kết nối database.
Các công cụ phổ biến
- k6 (Grafana k6): viết kịch bản bằng JavaScript, nhẹ, hiện đại, tích hợp CI/CD tốt. Rất được ưa chuộng hiện nay.
- JMeter (Apache): lâu đời, có giao diện đồ họa, mạnh về giao thức đa dạng, nhưng nặng và tốn tài nguyên máy chạy.
- Locust: viết kịch bản bằng Python, dễ đọc, mở rộng phân tán tốt.
- Gatling: viết bằng Scala/Java, hiệu năng cao, báo cáo đẹp.
- wrk / vegeta / hey: công cụ dòng lệnh nhẹ, hợp cho test nhanh một endpoint.
Tình huống thực tế
Ví dụ 1: Sàn TMĐT chuẩn bị flash sale 12/12
Một sàn thương mại điện tử tại TP.HCM (gọi là "ShopViet") chuẩn bị flash sale. Ngày thường họ xử lý khoảng 1.200 request/giây. Đội marketing dự báo cú spike lúc 0h sẽ đạt đỉnh gấp 15 lần.
Đội SRE làm ba loại test. Load test ở mức 5.000 RPS: hệ thống ổn, p95 latency 210ms. Stress test đẩy dần lên: tới 9.000 RPS thì latency p95 vọt lên 1,8 giây và error rate chạm 4%. Đào sâu, họ phát hiện thủ phạm là database connection pool — chỉ cấu hình 100 kết nối, khi tải cao các request phải xếp hàng chờ kết nối. Spike test từ 1.000 lên 12.000 RPS trong 5 giây cho thấy auto-scaling mất tận 90 giây để bổ sung server — quá chậm, trong 90 giây đó hàng loạt khách bị lỗi.
Hành động khắc phục: tăng connection pool lên 300, thêm một tầng cache Redis cho trang sản phẩm hot, và pre-warm (khởi động sẵn) thêm server trước giờ G thay vì chờ auto-scaling. Đêm 12/12, hệ thống đạt đỉnh 11.500 RPS với p95 dưới 400ms, không sự cố.
Bài học: stress test giúp tìm ra "cổ chai" ẩn (connection pool) mà load test bình thường không lộ ra. Và đừng tin auto-scaling sẽ cứu bạn trong tình huống spike — hãy đo thời gian nó phản ứng.
Ví dụ 2: Ứng dụng gọi xe và cú soak test lộ memory leak
Một startup gọi xe ở Đông Nam Á (giả định "GoRide") ra mắt phiên bản mới của dịch vụ định vị tài xế. Test load 1 tiếng trước khi deploy: mọi thứ hoàn hảo. Họ tự tin phát hành.
Ba ngày sau, dịch vụ định vị sập vào lúc 6h chiều — giờ cao điểm. Điều tra cho thấy bộ nhớ của service tăng đều đặn suốt 60 tiếng cho tới khi bị hệ điều hành kill (OOM — out of memory). Đây là một memory leak: mỗi kết nối WebSocket của tài xế không được giải phóng đúng cách khi tài xế offline.
Vấn đề là loại test họ chọn sai. Load test 1 tiếng không đủ dài để lộ leak tích lũy trong 60 giờ. Sau sự cố, đội bổ sung soak test chạy 24 giờ vào quy trình release. Biểu đồ bộ nhớ theo thời gian trở thành tiêu chí bắt buộc: nếu đường bộ nhớ dốc lên đều mà không phẳng lại, release bị chặn.
Bài học: mỗi loại test bắt một loại lỗi khác nhau. Không có soak test, những lỗi phụ thuộc thời gian sẽ luôn được người dùng thật phát hiện giúp bạn — vào đúng lúc tệ nhất.
Ví dụ 3: Fintech và bài học "test nhầm môi trường"
Một công ty fintech tại Hà Nội chạy load test rất bài bản trên môi trường staging và ra kết quả đẹp: chịu được 6.000 RPS. Nhưng khi lên production trong đợt trả lương cuối tháng, hệ thống nghẽn ở chỉ 2.500 RPS.
Nguyên nhân: staging chỉ có 2 node database và cấu hình máy nhỏ hơn production, nhưng dataset chỉ có 10.000 bản ghi giả, trong khi production có 8 triệu bản ghi thật. Nhiều truy vấn quét bảng (full table scan) chạy tốt trên 10.000 dòng nhưng cực chậm trên 8 triệu dòng. Kết quả test staging hoàn toàn vô nghĩa vì dữ liệu không đại diện.
Bài học: kết quả load test chỉ đáng tin khi môi trường test gần giống production — cả về cấu hình phần cứng lẫn quy mô và hình dạng dữ liệu. Test trên dữ liệu tí hon là tự lừa mình.
Hướng dẫn từng bước
Đây là quy trình thực hiện một buổi load testing bài bản.
Bước 1 — Xác định mục tiêu và tiêu chí. Đừng test kiểu "cho biết". Viết rõ: "Xác nhận hệ thống chịu 5.000 RPS với p95 < 300ms và error rate < 1%." Con số này chính là SLO của bạn dưới tải. Không có tiêu chí thì bạn không biết test đậu hay rớt.
Bước 2 — Chọn loại test phù hợp mục tiêu. Muốn xác nhận tải kỳ vọng thì load test. Muốn tìm giới hạn thì stress test. Lo về flash sale thì spike test. Lo về ổn định dài hạn thì soak test. Thường bạn cần kết hợp vài loại.
Bước 3 — Chuẩn bị môi trường giống production. Cấu hình phần cứng tương đương, dữ liệu đủ lớn và thực tế, các dịch vụ phụ thuộc (payment, third-party API) được mô phỏng hợp lý. Tuyệt đối không chạy load test bắn vào API của bên thứ ba thật.
Bước 4 — Viết kịch bản mô phỏng hành vi thật. Người dùng thật không chỉ gọi một endpoint. Họ đăng nhập, duyệt sản phẩm, thêm giỏ hàng, thanh toán. Kịch bản nên phản ánh tỷ lệ này (ví dụ 70% xem, 20% tìm kiếm, 10% mua). Nhớ thêm "think time" — khoảng nghỉ giữa các thao tác như người thật.
Bước 5 — Chạy tăng dần (ramp-up), không bắn full ngay. Tăng tải theo bậc thang (ví dụ mỗi phút thêm 500 RPS). Điều này giúp bạn thấy chính xác latency bắt đầu xấu đi ở mức nào, thay vì chỉ biết "sập rồi".
Bước 6 — Quan sát cả hai phía. Vừa nhìn số liệu từ công cụ test (client-side), vừa nhìn dashboard giám sát của hệ thống (server-side: CPU, RAM, DB, queue). Điểm gãy nằm ở server-side, và bạn cần biết bộ phận nào gãy.
Bước 7 — Phân tích, khắc phục, test lại. Tìm cổ chai, sửa (tăng pool, thêm cache, tối ưu query, scale), rồi chạy lại để xác nhận. Load testing là vòng lặp, không phải làm một lần.
Bước 8 — Đưa vào quy trình định kỳ. Hệ thống thay đổi liên tục. Một lần đo tốt hôm nay không đảm bảo cho tháng sau. Lý tưởng nhất là tích hợp một bài test nhẹ vào CI/CD để phát hiện hồi quy hiệu năng sớm.
Lỗi thường gặp & mẹo
Lỗi 1 — Nhìn latency trung bình. Trung bình che giấu đuôi dài. Luôn nhìn p95, p99. Một hệ thống có trung bình 100ms nhưng p99 = 3 giây là một hệ thống có vấn đề nghiêm trọng.
Lỗi 2 — Máy chạy test trở thành nút thắt. Nếu bạn dùng một laptop yếu để bắn tải, chính laptop đó (CPU, băng thông mạng) hết công suất trước hệ thống mục tiêu, và bạn tưởng nhầm hệ thống khỏe. Với tải lớn, hãy dùng nhiều máy phát tải phân tán hoặc dịch vụ cloud (k6 Cloud, BlazeMeter).
Lỗi 3 — Test không có think time. Bắn request liên tục không nghỉ tạo ra mẫu tải phi thực tế, thường khắc nghiệt hơn thực tế và cho kết quả sai lệch.
Lỗi 4 — Bỏ qua bước warm-up. Nhiều hệ thống có cache lạnh, JIT chưa khởi động, connection pool chưa đầy lúc mới bắt đầu. Bỏ vài phút đầu tiên ra khỏi kết quả để tránh sai lệch.
Lỗi 5 — Test một endpoint, quên bức tranh tổng thể. Test riêng trang chủ có thể đẹp, nhưng nghẽn thật xảy ra ở luồng thanh toán khi mọi tầng cùng hoạt động.
Mẹo: Luôn chuẩn bị sẵn cách dừng test khẩn cấp, đặc biệt nếu (vì lý do nào đó) bạn test gần production. Và ghi lại mọi cấu hình test để lần sau tái lập được — kết quả không tái lập được thì không đáng tin.
Mẹo: Kết hợp load testing với chaos engineering (Bài 24) sau này để test không chỉ "tải cao" mà còn "tải cao khi một node chết".
Bài tập thực hành
- Xác định loại test. Với mỗi tình huống sau, hãy chọn loại test phù hợp và giải thích: (a) ra mắt bán vé một concert lớn lúc 10h sáng; (b) một service backend chạy nền 24/7 xử lý hàng đợi; (c) chuẩn bị cho lượng truy cập ngày Black Friday tăng đều; (d) muốn biết giới hạn tuyệt đối của một API mới.
- Viết tiêu chí đậu/rớt. Cho một API đăng nhập, hãy viết một câu tiêu chí load test đầy đủ gồm throughput mục tiêu, ngưỡng latency percentile, và ngưỡng error rate.
- Thực hành với k6. Cài k6, viết một kịch bản đơn giản bắn tải vào một endpoint công khai của chính bạn (hoặc một app demo bạn tự dựng). Cho ramp-up từ 10 lên 100 VU (virtual user) trong 2 phút. Ghi lại p95 latency và error rate. Tìm mức tải mà p95 bắt đầu vượt 500ms.
- Phân tích tình huống. Đọc lại ví dụ 3 (fintech). Hãy liệt kê 3 điểm khác biệt giữa staging và production có thể làm sai lệch kết quả load test, ngoài số lượng bản ghi dữ liệu.
Tóm tắt
Load testing biến câu "chắc là chịu được" thành một câu trả lời có bằng chứng, và đó là kỹ năng cốt lõi của vận hành chuyên nghiệp. Điểm quan trọng nhất cần nhớ là bốn loại test trả lời bốn câu hỏi khác nhau: load test xác nhận tải kỳ vọng, stress test tìm điểm gãy, spike test kiểm tra cú sốc đột biến, soak test phát hiện lỗi tích lũy theo thời gian. Chọn sai loại test đồng nghĩa bỏ lỡ đúng lớp lỗi bạn cần tìm — như GoRide bỏ lỡ memory leak vì không soak test.
Để kết quả đáng tin, môi trường và dữ liệu test phải gần giống production (bài học từ fintech Hà Nội), phải nhìn latency theo percentile chứ không phải trung bình, phải quan sát cả client lẫn server để biết bộ phận nào gãy, và phải coi load testing là một vòng lặp định kỳ chứ không phải việc làm một lần. Bắt đầu với k6, viết tiêu chí đậu/rớt rõ ràng trước khi bấm chạy, và luôn tăng tải dần để thấy được điểm hệ thống bắt đầu xấu đi. Làm được những điều này, bạn sẽ không bao giờ phải trả lời sếp bằng câu "chắc là được" nữa.