Kiểm Thử Hiệu Năng Web Với JMeter (Case Thực Tế)

Tôi lấy ví dụ quen thuộc của series: "Hệ thống đặt phòng họp nội bộ", với kịch bản 100 nhân viên cùng đặt phòng vào đầu giờ sáng. Nếu bạn chưa rõ công cụ, hãy đọc JMeter là gì trước; còn muốn nắm nền lý thuyết thì xem Performance testing là gì.

Bài toán: đo tải một website

Trước khi mở JMeter, phải chốt được đo tải website để làm gì. Trong case này, "Hệ thống đặt phòng họp nội bộ" hay bị chậm lúc 8h sáng khi cả công ty tranh nhau đặt phòng. Mục tiêu bài test hiệu năng website là trả lời ba câu: server chịu được bao nhiêu người cùng lúc, response time ở mức tải đó là bao nhiêu, và bắt đầu lỗi từ ngưỡng nào.

Một bài performance test web tử tế luôn bắt đầu bằng việc định nghĩa mục tiêu và ngưỡng chấp nhận (SLA) rõ ràng. Với hệ thống đặt phòng, tôi đặt tiêu chí:

Tiêu chí | Ngưỡng chấp nhận | Ý nghĩa
Tải mục tiêu | 100 user đồng thời | Số nhân viên cao điểm đầu giờ
Response time (95% Line) | ≤ 1.500 ms | 95% request phải nhanh hơn mốc này
Throughput | ≥ 50 request/giây | Sức xử lý tối thiểu chấp nhận được
Error rate | ≤ 1% | Tỷ lệ request lỗi tối đa cho phép

Có bảng ngưỡng này, việc kiểm thử hiệu năng web không còn là "chạy cho vui" mà thành một phép kiểm PASS/FAIL rõ ràng. API mục tiêu tôi test là POST /api/bookings — đặt một phòng họp.

Thiết lập kịch bản (số user, ramp-up)

Kịch bản tải nằm ở Thread Group — nơi khai báo số người dùng ảo. Với case 100 nhân viên, tôi tạo Thread Group (chuột phải Test Plan → Add → Threads (Users) → Thread Group) và điền ba thông số cốt lõi:

Number of Threads (users): 100 — mô phỏng 100 nhân viên.

Ramp-up period (seconds): 20 — JMeter thả dần 100 luồng trong 20 giây, tức mỗi 0,2 giây thêm một người dùng. Thả từ từ để mô phỏng người dùng đến rải rác, tránh dồn 100 request vào đúng một mili-giây (không thực tế).

Loop Count: 5 — mỗi luồng lặp 5 lần, tổng 500 request.

Ramp-up là thông số người mới hay đặt sai nhất. Đặt ramp-up = 0 nghĩa là bắn cả 100 người cùng một khoảnh khắc — tạo cú sốc giả tạo mà đời thực hiếm khi xảy ra. Ngược lại, ramp-up quá dài (vd 600 giây) thì tại một thời điểm chỉ có vài người đang hoạt động, không bao giờ đạt tải mục tiêu 100 đồng thời. Công thức tôi hay dùng: ramp-up (giây) ≈ số user chia cho tốc độ user đến mỗi giây mà bạn muốn mô phỏng.

Nếu mục tiêu là giữ tải ổn định trong một khoảng thời gian, hãy dùng thêm ô Scheduler hoặc plugin Ultimate Thread Group. Muốn hiểu vì sao 100 user "đều đều" khác hẳn kịch bản dồn tải đột ngột, đọc thêm load test vs stress test.

Ghi & tham số hóa request

Nếu API chỉ có một request thì gõ tay là xong, nhưng luồng đặt phòng thật gồm nhiều bước: đăng nhập → xem phòng trống → đặt phòng. Lúc này có hai kỹ thuật cần nắm cho một bài jmeter web test đúng nghĩa.

Ghi kịch bản (recording). Thay vì dựng tay từng request, bạn dùng HTTP(S) Test Script Recorder: JMeter đóng vai proxy, bạn thao tác trên trình duyệt và nó tự ghi lại toàn bộ request thành các HTTP Request Sampler. Cách này tiết kiệm thời gian với luồng dài, sau đó bạn dọn bớt request thừa (ảnh, CSS, tracking).

Tham số hóa (parameterization). Đây là điểm sống còn: nếu cả 100 luồng cùng đăng nhập một tài khoản và đặt cùng một phòng, kết quả không phản ánh thực tế (cache che mất tải, hoặc trùng dữ liệu gây lỗi giả). Giải pháp là CSV Data Set Config:

Tạo file users.csv chứa dữ liệu thật, mỗi dòng một bộ, ví dụ username,password,roomId.

Thêm Config Element → CSV Data Set Config, trỏ tới file và khai báo tên biến username,password,roomId.

Trong HTTP Request, tham chiếu biến bằng cú pháp ${username}, ${roomId} — mỗi luồng sẽ đọc một dòng khác nhau.

Ngoài ra, với luồng có token, bạn dùng JSON Extractor để bắt token từ response đăng nhập rồi tái sử dụng ở request đặt phòng — giống cách xử lý biến khi test API thủ công. Đừng quên thêm Response Assertion để kiểm tra response chứa đúng dữ liệu (vd "status":"confirmed"), và Duration Assertion để đánh dấu FAIL nếu một request vượt ngưỡng thời gian. Nhanh mà trả sai thì con số đẹp cũng vô nghĩa.

Chạy test & đọc report (response time, error %)

Dựng xong, tôi không chạy tải thật bằng giao diện đồ họa (GUI) — GUI ngốn RAM và làm sai lệch số liệu. Cách chuẩn là chạy chế độ non-GUI bằng dòng lệnh:

bash jmeter -n -t booking.jmx -l ketqua.jtl -e -o report/

Trong đó -n là non-GUI, -t trỏ file kịch bản .jmx, -l ghi kết quả thô ra .jtl, còn -e -o report/ sinh sẵn một HTML dashboard report trực quan sau khi chạy. Khi debug kịch bản thì vẫn mở GUI với Summary Report hoặc Aggregate Report cho nhanh mắt.

Đọc report mới là phần quyết định. Bảng dưới là các chỉ số cốt lõi của một bài kiểm thử hiệu năng web và cách diễn giải:

Chỉ số | Ý nghĩa | Cách đọc
Samples | Tổng request đã gửi | Đối chiếu với 500 kỳ vọng (100×5)
Average | Response time trung bình (ms) | Tham khảo, nhưng dễ bị che bởi ngoại lệ
90% / 95% Line | 90–95% request nhanh hơn mốc này | Chỉ số chính để so với SLA
Throughput | Số request/giây server xử lý | Càng cao càng khỏe; so với ngưỡng ≥50/s
Error % | Tỷ lệ request lỗi (không phải 2xx) | Vượt 1% là báo động

Nguyên tắc vàng: đừng chỉ nhìn Average. Ví dụ trong lần chạy đầu, hệ thống đặt phòng cho Average = 480 ms nghe êm tai, nhưng 95% Line = 4.200 ms và Error % = 6% — nghĩa là phần đông người dùng vẫn phải chờ hơn 4 giây và cứ 16 người thì có 1 người gặp lỗi. Con số Average đã "trung bình hóa" che mất sự thật. Luôn nhìn percentile (95% Line) và Error % trước tiên.

Phân tích nghẽn & báo cáo

Có số xấu rồi, việc tiếp theo là tìm nghẽn ở đâu — đây mới là giá trị thật của performance test web. Error % cao và percentile tăng vọt chỉ là triệu chứng; nguyên nhân thường nằm ở tầng dưới. Quy trình khoanh vùng tôi hay áp dụng:

Đọc loại lỗi trong .jtl: lỗi 500 là server sập/exception, 503 là quá tải, Connection timeout là server không kịp nhận kết nối. Mỗi mã chỉ về một tầng khác nhau.

Xem đường cong theo tải: trong HTML dashboard, nhìn biểu đồ Response Time Over Time. Nếu response time tăng tuyến tính theo số user rồi "gãy" tại một mốc (vd 70 user), đó chính là ngưỡng bão hòa.

Đối chiếu tài nguyên server: song song với JMeter, theo dõi CPU, RAM và database ở phía server (dùng công cụ giám sát). CPU chạm 100% hay connection pool database cạn thường là thủ phạm phổ biến nhất của nghẽn.

Bảng đối chiếu triệu chứng — nguyên nhân giúp bạn đọc nhanh:

Triệu chứng quan sát | Nghi vấn nghẽn | Hướng xử lý gợi ý
Response time tăng vọt sau ngưỡng X user | Server bão hòa CPU/RAM | Tối ưu code, tăng tài nguyên
Nhiều lỗi 503 / timeout | Web server hết luồng xử lý | Chỉnh thread pool, thêm instance
Chậm ở request có truy vấn DB | Nghẽn database, thiếu index | Tối ưu query, thêm index/cache
Throughput không tăng dù thêm user | Đã chạm trần một tài nguyên | Xác định tài nguyên giới hạn

Cuối cùng là báo cáo. Một report tốt không dừng ở ảnh chụp Summary. Nó nêu rõ: mục tiêu và ngưỡng SLA ban đầu, cấu hình test (100 user, ramp-up 20s, 5 vòng), kết quả đo (95% Line, throughput, error %), kết luận PASS/FAIL so với SLA, và điểm nghẽn tìm được kèm đề xuất. Đây chính là bộ kỹ năng được luyện sâu trong khóa Performance JMeter của IT LEARN, trên dự án thật.