Product Management
Đăng nhập
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Performance Test Automation — JMeter

Mở đầu — vì sao bài này quan trọng

Hãy tưởng tượng bạn là QA của một sàn thương mại điện tử ở Việt Nam. Toàn bộ chức năng chạy đúng: đăng nhập được, thêm giỏ hàng được, thanh toán được. Bạn tự tin release trước dịp sale 12/12. Nhưng khi 50.000 người đồng loạt vào lúc 0h, website treo cứng, trang chủ trả về lỗi 502, và đội kinh doanh mất hàng trăm triệu đồng doanh thu chỉ trong 20 phút.

Bài học đau đớn ở đây là: chức năng đúng không có nghĩa là hệ thống chịu tải được. Một ứng dụng chạy mượt với 10 người dùng có thể sụp đổ hoàn toàn với 10.000 người dùng. Đây chính là lãnh địa của Performance Testing (kiểm thử hiệu năng), và trong bài này chúng ta sẽ học công cụ kinh điển nhất cho việc đó: Apache JMeter.

JMeter là công cụ mã nguồn mở, viết bằng Java, ra đời từ năm 1998 và đến nay vẫn là "chuẩn vàng" (gold standard) trong ngành. Lý do nó tồn tại bền bỉ: miễn phí, chạy được trên mọi hệ điều hành, hỗ trợ nhiều giao thức (HTTP, HTTPS, SOAP, REST, JDBC, FTP, JMS...), và có hệ sinh thái plugin khổng lồ. Với vai trò một SDET hay QA automation, biết JMeter là kỹ năng gần như bắt buộc khi công ty bạn có bất kỳ hệ thống nào phục vụ số lượng người dùng lớn.

Bài này chỉ tập trung vào JMeter. Các công cụ hiện đại thay thế như k6 sẽ được nói ở bài riêng — ở đây ta đào sâu vào tư duy performance test và cách vận hành JMeter cho thật thành thạo.

Khái niệm cốt lõi

Các loại kiểm thử hiệu năng

Trước khi bấm nút chạy, bạn phải hiểu mình đang đo cái gì. "Performance test" không phải một thứ duy nhất mà là một họ các bài kiểm thử:

  • Load Testing (kiểm thử tải): Mô phỏng lượng người dùng dự kiến ở mức bình thường/cao điểm để xem hệ thống có đáp ứng đúng SLA không. Ví dụ: "Hệ thống phải phục vụ 5.000 người dùng đồng thời với thời gian phản hồi dưới 2 giây."
  • Stress Testing (kiểm thử áp lực): Đẩy tải vượt xa mức bình thường để tìm điểm gãy (breaking point) của hệ thống. Mục tiêu là biết hệ thống chết ở đâu và chết như thế nào.
  • Spike Testing (kiểm thử đột biến): Tăng tải đột ngột trong thời gian ngắn — đúng như kịch bản flash sale 0h.
  • Soak/Endurance Testing (kiểm thử ngâm): Chạy tải trung bình trong thời gian dài (vài giờ đến vài ngày) để phát hiện memory leak, kết nối DB rò rỉ, đầy ổ đĩa log...

Các chỉ số quan trọng phải nắm

Khi chạy xong, bạn sẽ đọc các con số này:

  • Response Time: Thời gian từ lúc gửi request đến lúc nhận đủ response. Nên nhìn percentile (P90, P95, P99) thay vì chỉ nhìn trung bình. Trung bình 200ms nhưng P99 là 8 giây nghĩa là cứ 100 người thì có 1 người phải chờ 8 giây — không chấp nhận được.
  • Throughput: Số request xử lý được trên một đơn vị thời gian (thường là requests/second hoặc transactions/second).
  • Error Rate: Tỉ lệ request lỗi. Dưới tải cao, error rate tăng vọt là dấu hiệu hệ thống đang gãy.
  • Latency: Thời gian đến khi nhận byte đầu tiên của response.

Kiến trúc và thành phần của JMeter

Một Test Plan trong JMeter được xây dựng từ các thành phần lồng nhau:

  • Thread Group: Trái tim của test. Định nghĩa số thread (mỗi thread = một người dùng ảo), ramp-up period (thời gian để khởi động dần các thread), và loop count (số vòng lặp).
  • Samplers: Thành phần gửi request thực tế, ví dụ HTTP Request Sampler.
  • Logic Controllers: Điều khiển luồng (loop, if, transaction...).
  • Config Elements: Cấu hình dùng chung như HTTP Header Manager, CSV Data Set Config, Cookie Manager.
  • Timers: Thêm thời gian chờ giữa các request để mô phỏng hành vi người thật (không ai click liên tục 0 giây).
  • Assertions: Kiểm tra kết quả (mã trả về 200, response chứa chuỗi mong muốn).
  • Listeners: Thu thập và hiển thị kết quả (Summary Report, Aggregate Report, View Results Tree).
Điều quan trọng bạn phải khắc cốt ghi tâm: JMeter dùng GUI để BUILD test, nhưng dùng CLI (non-GUI) để CHẠY test thật. GUI ngốn tài nguyên và làm sai lệch kết quả nếu chạy tải cao trong đó.

Tình huống thực tế

Tình huống 1: Sàn TMĐT chuẩn bị cho ngày 12/12

Một công ty thương mại điện tử giả định tên ShopViet dự kiến cao điểm sale sẽ có khoảng 30.000 người dùng đồng thời, với luồng chính là: mở trang chủ → tìm sản phẩm → xem chi tiết → thêm giỏ hàng.

Đội QA dựng một Test Plan JMeter với Thread Group 3.000 thread (họ chạy 10 máy JMeter phân tán để đạt 30.000), ramp-up 300 giây. Kết quả lần chạy đầu: khi vượt 12.000 người dùng đồng thời, response time của API /api/products/search nhảy từ 400ms lên 9 giây, error rate 18%.

Đội dev điều tra và phát hiện API search không có cache và mỗi request đều query full-text trực tiếp vào MySQL. Họ thêm Redis cache và một index full-text. Chạy lại: ShopViet chịu được 30.000 người dùng với P95 dưới 1,5 giây.

Bài học rút ra: JMeter không sửa lỗi cho bạn — nó chỉ ra chính xác endpoint nào là nút thắt cổ chai để dev tập trung tối ưu. Nếu không test trước, họ đã phát hiện vấn đề này ngay giữa đêm sale với khách hàng thật.

Tình huống 2: Ngân hàng số phát hiện memory leak nhờ soak test

Một fintech giả định tên PayNhanh làm ví điện tử. API chuyển tiền chạy rất nhanh trong load test 30 phút — response time ổn định 250ms. Đội QA suýt release, nhưng trưởng nhóm yêu cầu chạy thêm soak test 8 tiếng với tải trung bình 2.000 request/phút.

Đến giờ thứ 5, response time bắt đầu leo dần: 250ms → 600ms → 1,8 giây, và JVM của service bắt đầu ném lỗi OutOfMemory. Nguyên nhân: mỗi giao dịch mở một kết nối HTTP client mới đến cổng thanh toán mà không đóng, khiến connection pool cạn kiệt sau vài giờ.

Bài học rút ra: Nhiều lỗi hiệu năng nghiêm trọng (memory leak, connection leak) chỉ lộ ra sau thời gian dài chạy, không thể phát hiện bằng load test ngắn. Đây là lý do soak test tồn tại và tại sao đừng bao giờ chỉ chạy test 5 phút rồi tuyên bố "hệ thống ổn".

Tình huống 3: Startup dùng CSV Data để tránh kết quả sai

Một startup EdTech giả định tên HocOnline test API đăng nhập. Lần đầu, họ để 1.000 thread cùng đăng nhập bằng một tài khoản duy nhất. Kết quả throughput cực cao, response nhanh — ai cũng vui.

Nhưng khi lên production, hệ thống chậm bất ngờ. Lý do: khi test bằng một user, tầng cache và session của server "gian lận" — nó chỉ query DB một lần rồi trả cache cho 999 request còn lại. Kết quả test không phản ánh thực tế.

Họ sửa bằng CSV Data Set Config: nạp một file 10.000 tài khoản khác nhau, mỗi thread lấy một dòng. Lúc này mỗi request thực sự query DB riêng, và họ thấy con số thật: response time gấp 4 lần so với lần test giả.

Bài học rút ra: Dữ liệu test phải đa dạng và giống thật. Test với dữ liệu tĩnh, lặp lại sẽ cho kết quả "đẹp giả tạo" do hệ thống cache, dẫn đến quyết định sai lầm khi lên production.

Hướng dẫn từng bước

Bước 1: Cài đặt JMeter

JMeter cần Java 8 trở lên. Kiểm tra bằng java -version trước.

macOS (dùng Homebrew)

brew install jmeter

Linux (tải bản binary)

wget https://archive.apache.org/dist/jmeter/binaries/apache-jmeter-5.6.3.tgz tar -xzf apache-jmeter-5.6.3.tgz cd apache-jmeter-5.6.3

Windows: tải file .zip từ jmeter.apache.org, giải nén, chạy bin/jmeter.bat

Khởi động GUI để dựng test:

macOS/Linux

jmeter # nếu cài qua brew ./bin/jmeter # nếu tải binary

Bước 2: Tạo Test Plan và Thread Group

  • Mở JMeter GUI, bạn sẽ thấy sẵn một node Test Plan.
  • Chuột phải vào Test Plan → Add → Threads (Users) → Thread Group.
  • Cấu hình Thread Group:
- Number of Threads (users): 100 (số người dùng ảo) - Ramp-up period (seconds): 20 (khởi động 100 thread trong 20 giây, tức 5 thread/giây) - Loop Count: 10 (mỗi thread lặp 10 lần) hoặc tick "Infinite" và đặt Duration.

Bước 3: Thêm HTTP Request Sampler

  • Chuột phải Thread Group → Add → Sampler → HTTP Request.
  • Điền:
- Protocol: https - Server Name or IP: api.shopviet.vn - Method: GET - Path: /api/products/search?keyword=laptop

Bước 4: Thêm Config Elements cần thiết

  • HTTP Header Manager (chuột phải Thread Group → Add → Config Element): thêm header như Authorization: Bearer <token> hoặc Content-Type: application/json.
  • CSV Data Set Config: trỏ tới file users.csv, khai báo tên biến (ví dụ username,password). Trong Sampler bạn dùng ${username} để tham chiếu.

Bước 5: Thêm Assertion và Timer

  • Response Assertion: kiểm tra Response Code = 200 hoặc response chứa chuỗi "success".
  • Constant Timer / Uniform Random Timer: thêm delay 1–3 giây giữa các request để mô phỏng người thật (gọi là "think time").

Bước 6: Thêm Listener để build/debug (nhưng tắt khi chạy thật)

  • Thêm View Results Tree để debug từng request khi build. Nhớ vô hiệu hóa (disable) listener này trước khi chạy tải thật vì nó cực tốn RAM.

Bước 7: Lưu và CHẠY bằng non-GUI mode

Đây là bước quan trọng nhất. Lưu test plan thành file .jmx, rồi chạy từ dòng lệnh:

jmeter -n -t test-plan.jmx -l results.jtl -e -o ./report

-n : non-GUI mode (bắt buộc khi chạy tải thật)

-t : file test plan .jmx

-l : file kết quả thô .jtl

-e : sinh HTML report sau khi chạy xong

-o : thư mục xuất HTML report (phải rỗng hoặc chưa tồn tại)

Sau khi chạy xong, mở report/index.html để xem dashboard đầy đủ: biểu đồ response time theo thời gian, throughput, phân bố percentile, tỉ lệ lỗi.

Bước 8: Chạy phân tải (distributed) khi cần tải lớn

Một máy JMeter thường chỉ đẩy được vài nghìn thread. Để đạt hàng chục nghìn, dùng chế độ master-slave: một máy master điều khiển nhiều máy slave (remote engines) qua RMI:

jmeter -n -t test-plan.jmx -R slave1_ip,slave2_ip,slave3_ip -l results.jtl

Lỗi thường gặp & mẹo

1. Chạy tải cao trong GUI mode. Đây là lỗi số một của người mới. GUI của JMeter ngốn RAM để vẽ đồ thị, khiến chính máy JMeter thành nút thắt cổ chai — bạn đo hiệu năng của JMeter chứ không phải của hệ thống đích. Luôn dùng -n non-GUI khi chạy thật.

2. Nhầm giữa "người dùng đồng thời" và "thread". 100 thread có think time 5 giây không tương đương 100 request/giây. Hãy tính throughput mong muốn và điều chỉnh số thread + timer cho khớp. Con số thread thô không nói lên tải thực.

3. Máy chạy JMeter yếu hơn hệ thống cần test. Nếu laptop của bạn hết CPU/RAM trước khi server đích chịu tải, kết quả vô nghĩa. Theo dõi CPU/RAM của chính máy JMeter trong lúc chạy; nếu nó quá tải, hãy dùng chế độ phân tải.

4. Quên tắt các Listener nặng. View Results Tree và các listener đồ thị lưu toàn bộ dữ liệu vào RAM. Với hàng triệu request, chúng sẽ làm JMeter crash. Chỉ dùng chúng lúc debug, tắt khi chạy tải.

5. Bỏ qua think time. Người thật không bấm liên tục. Không có timer, bạn tạo ra tải phi thực tế và có thể tự "DDoS" hệ thống của mình một cách sai lệch.

6. Không tăng heap của JMeter khi tải lớn. Sửa biến HEAP trong file bin/jmeter (hoặc jmeter.bat), ví dụ -Xms1g -Xmx4g, để JMeter đủ bộ nhớ.

7. Chỉ nhìn giá trị trung bình. Trung bình che giấu vấn đề. Luôn đọc P95, P99 và error rate. Một hệ thống có average tốt nhưng P99 tệ vẫn khiến nhiều người dùng thực bực bội.

Mẹo hay: Dùng JMeter Proxy Recorder (HTTP(S) Test Script Recorder) để "quay lại" luồng thao tác trên trình duyệt thật thành các HTTP Sampler tự động, thay vì gõ tay từng request. Sau đó dọn dẹp lại (bỏ request static như ảnh, CSS nếu không cần) và tham số hóa bằng CSV.

Bài tập thực hành

  • Cài đặt & chạy đầu tiên: Cài JMeter, tạo Test Plan test một API public bất kỳ (ví dụ https://jsonplaceholder.typicode.com/posts) với 50 thread, ramp-up 10 giây, loop 5. Chạy bằng non-GUI và sinh HTML report.
  • Tham số hóa dữ liệu: Tạo file users.csv với 20 dòng gồm username,password. Dùng CSV Data Set Config để mỗi thread đăng nhập bằng một tài khoản khác nhau. Thêm Response Assertion kiểm tra mã 200.
  • So sánh các loại test: Với cùng một API, chạy 3 kịch bản: (a) load test 100 thread trong 5 phút, (b) spike test tăng đột ngột lên 500 thread, (c) soak test 100 thread trong 30 phút. So sánh response time và error rate của cả ba, viết một đoạn ngắn nhận xét sự khác biệt.
  • Phân tích percentile: Từ HTML report của bài 1, tìm giá trị P90, P95, P99. Giải thích tại sao P99 lại quan trọng hơn average khi đánh giá trải nghiệm người dùng thực.

Tóm tắt

JMeter là công cụ mã nguồn mở, viết bằng Java, kinh điển cho kiểm thử hiệu năng — và nó vẫn là chuẩn vàng nhờ miễn phí, đa giao thức, đa nền tảng và hệ sinh thái plugin phong phú.

Những điểm cốt lõi cần nhớ:

  • Chức năng đúng không đảm bảo chịu tải tốt — performance test là một loại kiểm thử riêng biệt, không thể bỏ qua với hệ thống nhiều người dùng.
  • Hiểu rõ các loại test: load, stress, spike, soak — mỗi loại trả lời một câu hỏi khác nhau.
  • Nắm các chỉ số: response time (đặc biệt P95/P99), throughput, error rate — và đừng bao giờ chỉ nhìn trung bình.
  • Kiến trúc Test Plan xoay quanh Thread Group, Sampler, Config Element, Timer, Assertion, Listener.
  • Build test bằng GUI, chạy test bằng non-GUI (-n) — nguyên tắc vàng để có kết quả chính xác.
  • Dùng CSV Data Set cho dữ liệu đa dạng, thêm think time cho thực tế, và dùng distributed mode khi cần tải lớn.
Ba tình huống ShopViet, PayNhanh và HocOnline cho thấy: JMeter không sửa lỗi giúp bạn, nhưng nó chỉ đúng nút thắt cổ chai, phát hiện memory leak ẩn sau nhiều giờ, và cảnh báo khi dữ liệu test của bạn đang "gian lận". Nắm chắc JMeter, bạn sẽ tự tin cho hệ thống ra trận trong những đêm sale khốc liệt nhất.

Học xong bài này rồi? Tạo tài khoản miễn phí để lưu lại — lần sau vào là biết ngay đang dở ở đâu, và học hết khóa thì có chứng chỉ. Lưu tiến độ của tôi