Product Management
Đăng nhập
ESC

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

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

Project 2: JMeter Stress Test

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

Cho tới lúc này, bạn đã học JMeter đủ để tạo Thread Group, thêm Sampler, chạy Non-GUI mode, dùng CSV Data Set và đọc kết quả. Nhưng biết dùng công cụ chưa đồng nghĩa với biết làm một dự án. Trong thực tế, khi sếp hỏi "Hệ thống của mình chịu được bao nhiêu người?", bạn không thể trả lời bằng một con số chép từ tài liệu marketing. Bạn phải đi tìm câu trả lời bằng một cuộc stress test có phương pháp — ép hệ thống tới điểm gãy, quan sát nó gãy như thế nào, rồi báo cáo lại điểm gãy đó một cách thuyết phục.

Đây chính là mục tiêu của Project 2. Khác với load test (Bài 5 đã phân biệt kỹ) — nơi bạn mô phỏng tải "bình thường" hoặc "cao điểm dự kiến" — thì stress test đi xa hơn tải kỳ vọng, cố tình đẩy hệ thống vượt ngưỡng để tìm breaking point (điểm gãy). Bạn muốn biết: khi nào latency bắt đầu phình lên? Khi nào error rate vọt qua 1%? Khi nào server trả về 503? Và quan trọng nhất — cái gì gãy trước: CPU, RAM, connection pool, hay database?

Trong bài này, ta sẽ làm một dự án hoàn chỉnh: stress test một order-service (dịch vụ đặt hàng REST). Bạn sẽ đi từ lúc dựng kế hoạch, thiết kế profile tăng tải, chạy phân tán (distributed) khi một máy không đủ sức tạo tải, cho tới lúc chốt được con số breaking point và viết nó vào báo cáo. Đây là kỹ năng lõi mà một Performance Engineer phải làm thành thạo — không phải "biết JMeter" mà là "dùng JMeter để trả lời một câu hỏi kinh doanh".

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

Breaking point là gì và trông như thế nào

Breaking point không phải là khoảnh khắc server tắt ngúm. Nó là điểm mà tại đó hệ thống không còn đáp ứng đúng SLA nữa — dù server vẫn "sống". Có ba dấu hiệu kinh điển bạn cần nhận ra khi tăng dần tải:

  • Throughput chững lại rồi tụt. Ban đầu, càng thêm user thì requests/second (RPS) càng tăng tuyến tính. Tới một điểm, đường throughput đi ngang (bão hòa) — thêm user cũng không xử lý được nhiều hơn. Sau điểm đó nếu vẫn ép, throughput còn tụt xuống vì server bận tranh chấp tài nguyên.
  • Latency phình theo cấp số nhân. Trước điểm gãy, thời gian phản hồi tăng nhẹ. Sau điểm gãy, p95/p99 latency nhảy vọt từ vài trăm ms lên vài giây, rồi hàng chục giây.
  • Error rate leo thang. Timeout, connection refused, HTTP 500/503 bắt đầu xuất hiện và nhân lên nhanh.
Điểm gãy thường được định nghĩa là mức tải cao nhất mà hệ thống vẫn giữ error rate < 1% và p95 latency dưới ngưỡng SLA (ví dụ 2 giây). Vượt qua mốc đó là "đã gãy".

Vì sao stress test cần profile tăng dần (ramp-up profile)

Nếu bạn thả 5.000 user vào ngay giây đầu tiên, bạn sẽ chỉ thấy hệ thống sập — nhưng không biết nó sập ở mức nào. Đó là dữ liệu vô dụng. Nghệ thuật của stress test là tăng tải theo bậc thang (step load): giữ mỗi mức tải đủ lâu để hệ thống ổn định (steady state), ghi lại metrics, rồi mới nâng lên bậc tiếp theo. Ví dụ: 100 → 300 → 600 → 1.000 → 1.500 → 2.000 concurrent users, mỗi bậc giữ 5 phút. Khi vẽ đồ thị, bạn sẽ thấy rõ bậc thang nào là nơi throughput ngừng tăng và latency bắt đầu vỡ.

JMeter hỗ trợ điều này qua plugin Concurrency Thread Group hoặc Ultimate Thread Group (cài từ Plugins Manager). Nếu chỉ dùng Thread Group mặc định, bạn dựng nhiều Thread Group nối tiếp với thời gian bắt đầu lệch nhau (staggered start) để mô phỏng bậc thang.

Vì sao cần Distributed Testing cho stress test

Đây là điểm mấu chốt khiến stress test khác với các test nhỏ. Một máy tính (đặc biệt là laptop chạy JMeter GUI) chỉ tạo được vài trăm tới khoảng 1.000 luồng trước khi chính máy tạo tải bị nghẽn — CPU 100%, JVM GC liên tục, socket cạn kiệt. Lúc đó con số latency bạn đo được là latency của cái laptop đang thở dốc, không phải của server. Đây là bẫy phổ biến số một: đo nhầm nghẽn của công cụ thành nghẽn của hệ thống.

Giải pháp là Distributed Testing (Master/Slave) mà Bài 23 đã giới thiệu về cơ chế. Ở dự án này ta áp dụng nó: một máy Controller (master) điều phối, nhiều máy Load Generator (slave/worker) thực sự bắn request. Master gom kết quả về. Với 3-4 máy generator cấu hình vừa phải, bạn dễ dàng tạo 5.000-10.000 concurrent users mà bản thân bộ tạo tải vẫn "khỏe".

Nguyên tắc vàng: luôn giám sát cả load generator lẫn server đích. Nếu CPU của generator vượt 70-80%, kết quả không còn đáng tin — cần thêm máy.

Các metrics phải quan sát trong lúc stress

Ở phía server, bạn cần một dashboard theo dõi song song (thường là Grafana + node_exporter, sẽ nói kỹ ở các bài sau): CPU, memory, disk I/O, network, số connection tới database, độ dài queue của connection pool. Bởi vì mục tiêu cuối không chỉ là "gãy ở 1.800 user" mà là "gãy ở 1.800 user VÌ database connection pool cạn (max 100 connection)". Con số cộng với nguyên nhân mới là báo cáo có giá trị.

Tình huống thực tế

Tình huống 1 — Sàn TMĐT ở TP.HCM đo nhầm breaking point vì thiếu distributed

Một team QA tại sàn thương mại điện tử (giả định là "ShopFast") ở Quận 1, TP.HCM được giao stress test order-service trước mùa sale. Bạn QA chạy JMeter GUI ngay trên laptop MacBook của mình, thả 2.000 threads. Kết quả: latency trung bình 8 giây, kết luận "hệ thống chỉ chịu được 500 user". Team dev hoảng loạn, xin thêm 2 tuần để tối ưu.

May thay, một senior nhìn vào và hỏi: "Lúc test, CPU laptop em bao nhiêu?". Câu trả lời: 100%, quạt gào thét. Họ chuyển sang distributed test với 4 máy EC2 làm load generator, mỗi máy tạo 1.500 user. Kết quả thật: hệ thống chịu tốt tới 4.200 concurrent users, breaking point ở ~4.500 khi database connection pool (đặt max 200) cạn.

Bài học: Con số "500" ban đầu là latency của cái laptop, không phải của server. Nếu không phát hiện, team đã lãng phí 2 tuần tối ưu sai chỗ. Luôn giám sát load generator, và khi cần tải lớn thì bắt buộc distributed.

Tình huống 2 — Fintech phát hiện breaking point ẩn ở tầng downstream

Một ví điện tử (giả định "PayViet") stress test API create-order bằng JMeter phân tán, 3 slave, tăng dần từ 500 tới 3.000 TPS. Đồ thị đẹp cho tới 2.400 TPS thì error rate đột ngột nhảy lên 12%, nhưng CPU và RAM của order-service vẫn chỉ 45%. Rất khó hiểu — server còn dư tài nguyên mà lại lỗi.

Đào sâu log, họ phát hiện lỗi là timeout khi gọi payment-gateway. Order-service khỏe, nhưng nó phụ thuộc một service thanh toán downstream chỉ chịu được 2.400 TPS. Breaking point thật của chuỗi dịch vụ nằm ở mắt xích yếu nhất, không phải ở service mình đang test trực tiếp.

Bài học: Breaking point của một service hiếm khi do chính nó. Trong kiến trúc microservices, phải theo dõi cả downstream. Báo cáo đúng phải là: "order-service gãy ở 2.400 TPS do downstream payment-gateway bão hòa", chứ không phải "order-service yếu".

Tình huống 3 — Startup logistics và cú vỡ connection pool

Một startup giao hàng ở Hà Nội stress test service theo dõi đơn. Mỗi bậc thang tăng 300 user, mọi thứ ổn tới 1.500 user (p95 = 1,2s), rồi ở bậc 1.800 user, latency vọt thẳng lên 15 giây và hàng loạt request treo. Điều lạ: throughput không tăng chút nào từ 1.500 lên 1.800 — cứ đứng yên ở ~900 RPS dù thêm user.

Nguyên nhân: đường throughput đi ngang là dấu hiệu bão hòa. Server đã dùng hết 50 connection trong pool tới database; user thứ 1.501 trở đi phải xếp hàng chờ một connection rảnh, thế là latency phình. Họ nâng pool lên 150, breaking point đẩy lên 3.200 user.

Bài học: Throughput đi ngang trong khi latency tăng là chữ ký kinh điển của cạn tài nguyên (resource saturation). Đây là lúc bạn đã chạm breaking point, và nguyên nhân thường là một pool/queue có giới hạn.

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

Bước 1 — Xác định mục tiêu và SLA. Viết ra rõ ràng: dịch vụ đích là order-service, endpoint POST /api/v1/orders. Định nghĩa breaking point = mức tải cao nhất giữ được error rate < 1% VÀ p95 latency < 2s. Không có SLA thì không biết đâu là "gãy".

Bước 2 — Chuẩn bị dữ liệu và kịch bản. Tạo file orders.csv với dữ liệu đầu vào đa dạng (user_id, product_id, quantity, token) để mỗi request khác nhau, tránh cache che giấu vấn đề. Dùng CSV Data Set Config (Bài 9). Thêm HTTP Header Manager cho AuthorizationContent-Type: application/json.

Bước 3 — Dựng profile bậc thang. Cài Concurrency Thread Group qua Plugins Manager. Cấu hình các mốc: 100, 300, 600, 1.000, 1.500, 2.000... users; mỗi mốc giữ (hold) 5 phút, ramp-up giữa các mốc 30 giây. Đặt Duration đủ dài để đi hết các bậc.

Bước 4 — Thêm Assertion và Timer. Response Assertion kiểm tra HTTP 201 (hoặc field order_id trong response). Thêm một Timer nhỏ (Constant/Uniform Random Timer 200-500ms) để mô phỏng think time thực tế, tránh bắn dồn dập phi thực tế.

Bước 5 — Chuẩn bị máy phân tán. Trên mỗi máy slave, cài JMeter cùng phiên bản với master, mở jmeter-server. Sửa remote_hosts trong jmeter.properties của master để trỏ tới IP các slave. Đảm bảo firewall mở port RMI, và mạng giữa các máy đủ nhanh. Với JMeter dùng cấu hình SSL cho RMI hoặc tắt SSL trong môi trường test nội bộ.

Bước 6 — Chạy Non-GUI phân tán. Luôn chạy stress test ở Non-GUI mode (Bài 11) để master không tốn tài nguyên vẽ GUI:

jmeter -n -t order_stress.jmx -R slave1,slave2,slave3 -l results.jtl -e -o report/

-R liệt kê slave, -l ghi kết quả thô, -e -o sinh HTML dashboard sau khi chạy.

Bước 7 — Giám sát song song. Trong lúc test, mở dashboard theo dõi (1) CPU/RAM/network của TỪNG load generator — phải dưới 70%; (2) CPU/RAM/DB-connections của order-service và các downstream. Ghi lại số liệu tại mỗi bậc thang.

Bước 8 — Xác định breaking point. Sau khi chạy, vẽ đồ thị throughput vs users và latency vs users. Điểm gãy là bậc thang cuối cùng còn thỏa SLA. Ghi lại: mức tải, error rate tại đó, và metric tài nguyên nào chạm trần (đó là nguyên nhân).

Bước 9 — Chốt và tái kiểm chứng. Chạy lại quanh vùng breaking point (ví dụ 1.700-1.900 user với bước nhỏ 50) để có con số chính xác. Chạy 2-3 lần để loại trừ nhiễu.

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

  • Đo nghẽn của load generator thay vì server. Lỗi phổ biến nhất. Nếu CPU generator > 80%, thêm máy. Đây là lý do gốc để dùng distributed.
  • Chạy GUI mode khi stress. GUI ăn RAM và CPU khủng khiếp, làm sai lệch kết quả và dễ treo. Luôn Non-GUI cho stress test thật.
  • Không có think time. Bắn request liên tục không nghỉ tạo ra tải phi thực tế, làm breaking point thấp giả tạo. Thêm Timer.
  • Slave khác phiên bản/khác plugin với master. Gây lỗi khó hiểu hoặc thiếu kết quả. Đồng bộ phiên bản JMeter và plugin trên mọi máy.
  • Bỏ qua downstream. Như tình huống PayViet, server khỏe nhưng chuỗi vẫn gãy. Luôn hỏi: "service này phụ thuộc ai?".
  • Test trên dữ liệu tĩnh một dòng. Mọi request giống hệt nhau bị cache đỡ, che giấu breaking point thật. Dùng CSV đa dạng.
  • Mẹo: đặt sẵn cảnh báo (alert) ở dashboard server để tự bắt được khoảnh khắc CPU/DB-connection chạm trần — bạn sẽ biết ngay nguyên nhân gãy mà không phải dò log thủ công.
  • Mẹo: ghi log JTL ở mức tối giản (tắt các field không cần) để giảm I/O trên master, tránh chính việc ghi log thành nút thắt cổ chai.

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

  • Dựng profile bậc thang. Với order-service (dùng bất kỳ REST API mock nào, ví dụ một app Node/Spring Boot local), tạo Concurrency Thread Group 6 bậc: 100/300/600/1.000/1.500/2.000, mỗi bậc hold 3 phút. Chạy Non-GUI, xuất HTML report.
  • Tìm breaking point. Từ report, vẽ đồ thị throughput và p95 latency theo số user. Xác định bậc thang nào là điểm gãy theo SLA (error < 1%, p95 < 2s). Ghi lại con số.
  • Distributed. Nếu có 2 máy (hoặc 2 container/VM), cấu hình 1 master + 1 slave, chạy lại cùng kịch bản. So sánh: breaking point có cao hơn không? CPU máy tạo tải giảm bao nhiêu?
  • Truy nguyên nhân. Trong lúc chạy, theo dõi CPU/RAM/DB-connections của service. Viết một câu kết luận đúng chuẩn báo cáo: "order-service gãy ở ___ users vì ___ chạm trần."

Tóm tắt

Project 2 dạy bạn biến kỹ năng JMeter rời rạc thành một cuộc stress test có phương pháp để tìm breaking point của một dịch vụ thật. Bốn ý cốt lõi cần nhớ: (1) Breaking point là mức tải cao nhất còn thỏa SLA, nhận ra qua ba dấu hiệu — throughput bão hòa rồi tụt, latency phình cấp số nhân, error rate leo thang. (2) Phải tăng tải theo bậc thang (step load) chứ không thả một cục, để đọc được đường cong. (3) Với tải lớn, distributed testing là bắt buộc — nếu không bạn sẽ đo nhầm nghẽn của công cụ thành nghẽn của server, cái bẫy đã hại team ShopFast. (4) Con số breaking point chỉ có giá trị khi đi kèm nguyên nhân — pool cạn, downstream bão hòa, CPU trần — mà bạn chỉ tìm được nhờ giám sát song song cả generator lẫn server. Làm chủ được dự án này, bạn đã có trong tay một kỹ năng cốt lõi của nghề Performance Engineer: trả lời câu hỏi "hệ thống chịu được bao nhiêu?" bằng dữ liệu, không phải phỏng đoán.

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