·

Tiếng Việt: Load and stress test scenario generation

Load and stress test scenario generation

Trong 8 năm làm performance testing, tôi từng chứng kiến không ít lần một hệ thống "chạy êm" suốt cả tháng UAT rồi sập ngay ngày mở bán Black Friday — chỉ vì kịch bản load test được viết dựa trên cảm tính của tester, không dựa trên số liệu thực. Đây chính là lỗ hổng lớn nhất của performance testing truyền thống: việc thiết kế load profile, xác định critical path, hay chọn ngưỡng chịu tải thường phụ thuộc vào kinh nghiệm cá nhân, dễ bỏ sót và tốn rất nhiều thời gian viết script.

AI, đặc biệt là LLM (Large Language Model — mô hình ngôn ngữ lớn), thay đổi hoàn toàn cách chúng ta làm việc này. Nó có thể đọc requirement, phân tích access log, gợi ý load profile sát với hành vi người dùng thật, và sinh ra script k6/Gatling/Locust hoàn chỉnh trong vài phút. Bài viết này sẽ đi từ việc xác định đâu là performance-critical path, đến việc thiết kế stress test scenario, và cuối cùng là sinh code thực thi — tất cả với sự hỗ trợ của AI như một "pair performance engineer".

How to Identify Performance-Critical Paths from Requirements with AI? (Làm sao xác định các luồng quan trọng về hiệu năng từ requirement bằng AI?)

What "performance-critical" actually means (Performance-critical thực sự nghĩa là gì)

Nhiều team mới làm performance testing hay mắc lỗi: test tất cả API vì "cho chắc", dẫn đến báo cáo dài 40 trang nhưng không ai đọc, và không ai biết đâu là rủi ro thật. Theo kinh nghiệm thực tế, một luồng được coi là "performance-critical" khi thỏa ít nhất một trong ba tiêu chí: (1) tần suất truy cập cao (traffic volume), (2) tác động trực tiếp đến doanh thu hoặc trải nghiệm lõi (ví dụ luồng checkout, luồng đăng nhập), và (3) độ phức tạp kỹ thuật cao — gọi nhiều service, nhiều truy vấn DB, hoặc có external call (thanh toán, gửi SMS/OTP).

Một lỗi thường gặp là đánh đồng "critical path" trong functional testing (luồng nghiệp vụ quan trọng) với "critical path" trong performance testing. Một trang "Quên mật khẩu" có thể không quan trọng về nghiệp vụ nhưng nếu nó gọi email service đồng bộ (synchronous) và không có timeout, nó hoàn toàn có thể là điểm nghẽn (bottleneck) làm sập cả hệ thống khi traffic tăng — vì thread pool bị chiếm giữ. Vì vậy, việc xác định critical path cho performance test cần một góc nhìn kỹ thuật riêng, không thể chỉ dựa vào tài liệu BA.

Feeding requirements to AI for critical path extraction (Đưa requirement cho AI để trích xuất critical path)

Cách hiệu quả nhất tôi áp dụng là đưa cho AI (ChatGPT, Claude, hoặc bất kỳ LLM nào tích hợp trong công cụ nội bộ) toàn bộ tài liệu requirement (PRD, API spec, sequence diagram dạng text) và yêu cầu nó phân loại theo ma trận rủi ro hiệu năng. Điểm mạnh của AI ở đây là khả năng đọc nhanh một khối lượng lớn document và liên kết các luồng nghiệp vụ với các API endpoint tương ứng — việc mà một tester phải mất cả buổi để làm bằng tay.

Bạn là một Performance Test Architect có 10 năm kinh nghiệm.
Tôi sẽ cung cấp cho bạn tài liệu requirement (PRD) và OpenAPI spec của một
hệ thống e-commerce. Nhiệm vụ của bạn:

1. Đọc và liệt kê tất cả các luồng nghiệp vụ (user flow) được mô tả.
2. Với mỗi luồng, đánh giá mức độ "performance-critical" theo 3 tiêu chí:
   - Traffic volume (dự kiến số request/phút dựa trên context nếu có)
   - Business impact (ảnh hưởng doanh thu/UX nếu luồng bị chậm hoặc lỗi)
   - Technical complexity (số service phụ thuộc, DB query, external call,
     có transaction/lock không)
3. Chấm điểm mỗi tiêu chí theo thang 1-5, tính tổng điểm.
4. Xếp hạng Top 10 luồng có tổng điểm cao nhất, giải thích ngắn gọn lý do.
5. Với mỗi luồng Top 10, map sang endpoint API cụ thể (method + path) từ
   OpenAPI spec đính kèm.

Output dạng bảng Markdown với các cột: Rank | User Flow | Endpoint |
Traffic Score | Business Score | Complexity Score | Total | Ghi chú.

--- PRD ---
[dán nội dung PRD]

--- OpenAPI SPEC ---
[dán nội dung spec]

Kết quả trả về không phải là "chân lý" — nó là điểm khởi đầu để team review cùng Product Owner và Tech Lead. Nhưng nó giúp rút ngắn buổi họp xác định scope từ 2 giờ xuống 30 phút, vì mọi người đã có sẵn một bản đề xuất có lý luận rõ ràng để tranh luận thay vì bắt đầu từ tờ giấy trắng.

Using access log samples for data-driven path prioritization (Dùng mẫu access log để ưu tiên luồng dựa trên dữ liệu thật)

Requirement chỉ nói lên "ý định thiết kế", còn access log (Nginx, CloudFront, hoặc APM — Application Performance Monitoring, như New Relic/Datadog) nói lên "hành vi thật của người dùng". Tôi từng gặp trường hợp PRD ghi rõ luồng "so sánh sản phẩm" là tính năng chủ lực, nhưng khi phân tích log thực tế thì chưa đến 0.3% traffic chạm vào nó — trong khi endpoint /api/search chiếm 38% tổng request. Nếu chỉ dựa vào tài liệu, ta sẽ lãng phí effort test sai chỗ.

Cách làm: export một mẫu access log (thường 100k–500k dòng trong giờ cao điểm) ra file CSV/JSON, sau đó nhờ AI tổng hợp phân phối traffic theo endpoint, theo response time trung bình, và theo tỷ lệ lỗi.

Đây là mẫu access log Nginx trong 1 giờ cao điểm (format: timestamp | method
| path | status | response_time_ms). Hãy:

1. Tổng hợp Top 20 endpoint theo số lượng request, kèm % trên tổng traffic.
2. Với mỗi endpoint, tính response_time trung bình, p95, p99 (ước lượng
   nếu log không đủ chi tiết, ghi rõ giả định).
3. Liệt kê các endpoint có status >= 500 xuất hiện, tính tỷ lệ lỗi.
4. Đề xuất Top 8 endpoint nên đưa vào load test scenario, sắp xếp theo
   độ ưu tiên, dựa trên công thức: priority = traffic_share * 0.5 +
   error_rate * 0.3 + (response_time_p95 / 1000) * 0.2.
5. Giải thích ngắn gọn lý do chọn từng endpoint.

--- LOG SAMPLE ---
[dán log]

Kết hợp kết quả từ requirement (bước trên) và kết quả từ access log (bước này) chính là cách xác định critical path đáng tin cậy nhất — một bên cho biết "nên test gì theo thiết kế", một bên cho biết "cần test gì theo thực tế vận hành".

Mapping user journeys to technical paths (Ánh xạ hành trình người dùng sang luồng kỹ thuật)

Một critical path về nghiệp vụ (ví dụ: "Người dùng tìm sản phẩm → thêm vào giỏ → thanh toán") thường trải qua 5-10 API call khác nhau, có thể chạy song song hoặc tuần tự, và có những dependency ngầm (ví dụ: token phải được refresh trước khi gọi API thanh toán). Nếu không map rõ ràng, script load test sẽ test sai thứ tự hoặc bỏ sót bước quan trọng như tạo session, dẫn đến kết quả không phản ánh đúng tải thật.

Tôi thường yêu cầu AI dựng sequence diagram dạng text (Mermaid) từ mô tả nghiệp vụ, sau đó review lại với dev để chốt đúng thứ tự gọi API, những giá trị cần correlation (kỹ thuật trích xuất một giá trị động từ response rồi tái sử dụng ở request sau — ví dụ session id, cart id, CSRF token), và điểm nào có thể chạy song song để mô phỏng đúng hành vi trình duyệt (ví dụ: load ảnh sản phẩm song song với gọi API giá).

Mẹo: Đừng chỉ dựa vào một nguồn dữ liệu duy nhất. Kết hợp cả requirement (ý định thiết kế) và access log thực tế (hành vi thật) khi hỏi AI — nếu chỉ đưa PRD, bạn sẽ nhận về một danh sách "đẹp trên giấy" nhưng có thể lệch hoàn toàn so với traffic pattern thật của production.

How to Generate Realistic Load Profiles and User Journey Simulations with AI? (Làm sao tạo load profile và mô phỏng hành trình người dùng thực tế bằng AI?)

Understanding load profile components (Hiểu các thành phần của load profile)

Load profile không đơn giản là "bao nhiêu user đồng thời". Một load profile đầy đủ cần có: số virtual user (VU — người dùng ảo) đồng thời, tỷ lệ phân bổ giữa các luồng nghiệp vụ (traffic mix — ví dụ 60% browse, 25% search, 15% checkout), think time (thời gian người dùng thật "dừng lại" giữa các hành động), pattern theo thời gian (giờ cao điểm buổi tối, spike vào giờ flash sale), và tỷ lệ thiết bị/khu vực địa lý nếu hệ thống có CDN đa vùng.

Một lỗi kinh điển tôi từng mắc phải khi mới vào nghề: set think time = 0 để "test cho nhanh". Kết quả là 500 VU tạo ra tải tương đương 50,000 người dùng thật vì không ai gõ nhanh đến mức 0 giây giữa các click. Con số RPS (request per second) bị thổi phồng giả tạo, khiến team hoảng loạn tối ưu sai chỗ trong khi hệ thống thực ra chưa gặp vấn đề gì ở tải thật.

Prompting AI to derive realistic profiles from business data (Prompt AI để suy ra load profile thực tế từ dữ liệu kinh doanh)

Để có load profile sát thực tế, tôi cung cấp cho AI các số liệu kinh doanh có sẵn: số đơn hàng/ngày, giờ cao điểm theo Google Analytics, tỷ lệ conversion funnel, và dữ liệu mùa vụ (ví dụ tăng 5x vào ngày sale 11/11). AI sẽ giúp quy đổi các số liệu "kinh doanh" này thành số liệu "kỹ thuật" như VU, RPS, arrival rate (tốc độ user mới bắt đầu hành trình mỗi giây) — vốn là bước quy đổi rất dễ tính sai nếu làm tay.

Bạn là Performance Test Lead. Dựa trên dữ liệu kinh doanh sau, hãy tính
toán load profile cho load test:

- Tổng số đơn hàng thành công trung bình/ngày: 12,000
- Giờ cao điểm: 19h-22h, chiếm 40% tổng traffic trong ngày
- Conversion funnel: 100 lượt xem sản phẩm -> 30 thêm giỏ hàng ->
  8 vào trang thanh toán -> 5 đặt hàng thành công
- Ngày sale (11/11, Black Friday): traffic tăng gấp 6 lần so với ngày
  thường, tập trung trong khung 2 giờ mở bán
- Think time trung bình người dùng thật: 3-8 giây giữa các hành động
  (browse), 10-20 giây ở trang nhập thông tin thanh toán

Yêu cầu:
1. Tính RPS trung bình và RPS đỉnh (peak) cho ngày thường và ngày sale.
2. Quy đổi RPS đỉnh thành số Virtual User (VU) cần thiết, giải thích công
   thức sử dụng (Little's Law: VU = RPS * avg_response_time_including_think_time).
3. Đề xuất traffic mix (%) cho 4 luồng: browse, search, add-to-cart,
   checkout, dựa trên funnel trên.
4. Đề xuất think time cho từng luồng (min-max giây), có giải thích.
5. Xuất kết quả dưới dạng bảng có thể copy trực tiếp vào tài liệu test plan.

Một điểm cần lưu ý: AI có thể tính sai nếu bạn không cung cấp đủ ngữ cảnh về response time trung bình hiện tại của hệ thống (dùng trong công thức Little's Law). Vì vậy, luôn double-check công thức và số liệu đầu ra bằng tay ít nhất một lần trước khi đưa vào test plan chính thức — AI giỏi tính toán logic nhưng không "biết" hệ thống của bạn nếu không được cung cấp dữ liệu thật.

Generating user journey simulations (Sinh mô phỏng hành trình người dùng)

Sau khi có load profile, bước tiếp theo là mô phỏng hành trình người dùng chi tiết — không chỉ là gọi API theo thứ tự, mà còn phải có sự "ngẫu nhiên hóa" hợp lý (randomization) để tránh tạo ra pattern giả (ví dụ tất cả VU cùng search một từ khóa, gây cache hit 100% và làm sai lệch kết quả test). AI khá mạnh trong việc sinh ra bộ dữ liệu test đa dạng (search keyword, SKU, địa chỉ giao hàng) đi kèm với logic phân nhánh (branching) — ví dụ 70% VU tìm kiếm rồi rời đi, 30% tiếp tục thêm vào giỏ.

Tôi thường yêu cầu AI viết ra hành trình (journey) dưới dạng pseudocode trước, review cùng team, rồi mới chuyển thành code thật cho k6/Locust — cách này giúp phát hiện lỗi logic sớm (ví dụ quên xử lý trường hợp giỏ hàng trống khi checkout) trước khi tốn thời gian debug script.

Mẹo: Luôn yêu cầu AI giải thích rõ công thức quy đổi từ số liệu kinh doanh sang RPS/VU (đừng chỉ lấy con số cuối). Việc này giúp bạn phát hiện ngay nếu AI dùng sai giả định (ví dụ tính RPS trung bình cả ngày thay vì RPS đỉnh trong giờ cao điểm) — sai lầm này rất phổ biến và có thể làm load test của bạn thấp hơn thực tế 5-10 lần.

How to Design Stress Test Scenarios — Thresholds, Ramp-Up, and Break-Point — with AI? (Làm sao thiết kế stress test — ngưỡng chịu tải, ramp-up và điểm gãy — bằng AI?)

Stress test design dimensions (Các khía cạnh cần thiết kế trong stress test)

Stress test khác load test ở mục tiêu: load test trả lời câu hỏi "hệ thống có đáp ứng SLO ở tải kỳ vọng không", còn stress test trả lời câu hỏi "hệ thống sẽ gãy ở đâu, và gãy như thế nào". Ba yếu tố quan trọng nhất cần thiết kế là: threshold (ngưỡng SLO — Service Level Objective, mục tiêu mức dịch vụ — để biết khi nào coi là "vượt ngưỡng chấp nhận được" — ví dụ p95 latency < 300ms), ramp-up strategy (tăng tải theo bước nào, mỗi bước giữ bao lâu để hệ thống ổn định trước khi tăng tiếp), và break-point detection (dấu hiệu nào cho biết hệ thống đã "gãy" — error rate tăng vọt, latency tăng phi tuyến, hay hệ thống crash hoàn toàn).

Theo kinh nghiệm thực tế, ramp-up quá nhanh (ví dụ tăng từ 0 lên 5000 VU trong 30 giây) thường tạo ra "false break-point" — hệ thống báo lỗi không phải vì hết khả năng chịu tải, mà vì auto-scaling (tự động mở rộng) chưa kịp phản ứng. Ngược lại, ramp-up quá chậm sẽ tốn rất nhiều thời gian chạy test mà không phát hiện thêm insight gì mới.

Prompting AI to design a complete stress test scenario (Prompt AI thiết kế một stress test scenario hoàn chỉnh)

Bạn là Performance Engineer chuyên về stress testing. Tôi cần thiết kế
stress test cho API checkout của một hệ thống e-commerce với các thông
số sau:

- Baseline traffic hiện tại: 200 RPS, response time p95 hiện tại: 250ms
- Hạ tầng: auto-scaling group, thời gian scale-out mất khoảng 90 giây
- SLO mong muốn: p95 < 500ms, error rate < 1%
- Mục tiêu: tìm break-point (điểm hệ thống bắt đầu vi phạm SLO liên tục)

Hãy thiết kế một stress test scenario đầy đủ gồm:
1. Ramp-up strategy: các bước tăng VU cụ thể (ví dụ bắt đầu từ đâu, mỗi
   bước tăng bao nhiêu %, giữ ổn định (steady state) bao lâu ở mỗi bước
   để tránh false break-point do auto-scaling delay).
2. Danh sách chỉ số cần theo dõi realtime trong lúc test (không chỉ
   latency và error rate, mà cả các chỉ số hạ tầng liên quan).
3. Tiêu chí dừng test (abort criteria) - khi nào nên chủ động dừng để
   tránh gây sự cố thật cho production hoặc staging chung.
4. Kịch bản recovery test sau khi tìm được break-point: giảm tải xuống
   bao nhiêu %, theo dõi trong bao lâu để xác nhận hệ thống hồi phục
   (self-healing) đúng như kỳ vọng.

Trình bày dưới dạng timeline theo bảng: Phase | Duration | Target VU |
Expected Behavior | Abort Condition.

Kết quả từ AI thường rất chi tiết và có cấu trúc, nhưng cần lưu ý: AI không biết giới hạn thực tế của hạ tầng bạn (ví dụ connection pool DB tối đa, hay giới hạn của gateway thanh toán bên thứ 3 dùng sandbox). Luôn review với DevOps/SRE trước khi chạy thật, đặc biệt là abort criteria (điều kiện dừng khẩn cấp) — vì chạy stress test không kiểm soát trên môi trường chia sẻ có thể ảnh hưởng đến các team khác.

Sau khi có SLO được AI gợi ý và team chốt lại, bước quan trọng là đưa vào thresholds trong k6 để test tự động "pass/fail" theo tiêu chí khách quan, không cần đọc report bằng mắt. Đây là cách tôi cấu hình options cho k6 dựa trên SLO vừa thiết kế ở trên:

// k6-checkout-stress.js
export const options = {
  scenarios: {
    stress_ramp: {
      executor: 'ramping-vus',
      startVUs: 0,
      stages: [
        { duration: '2m', target: 50 },   // warm-up
        { duration: '3m', target: 200 },  // baseline traffic
        { duration: '3m', target: 400 },  // 2x baseline
        { duration: '3m', target: 600 },  // 3x baseline
        { duration: '3m', target: 800 },  // find the break-point
        { duration: '2m', target: 0 },    // ramp-down, verify recovery
      ],
    },
  },
  thresholds: {
    // p95 latency must stay under 500ms per the agreed SLO
    http_req_duration: ['p(95)<500', 'p(99)<1200'],
    // error rate must stay under 1%
    http_req_failed: ['rate<0.01'],
    // dedicated threshold for the checkout step (using a custom tag)
    'http_req_duration{step:checkout}': ['p(95)<500'],
  },
};

Điểm hay của k6 là bạn có thể gắn threshold theo từng "tag" cụ thể (ví dụ step:checkout) — điều này rất hữu ích khi stress test có nhiều luồng khác nhau và bạn muốn SLO riêng cho từng luồng thay vì một ngưỡng chung cho toàn bộ traffic.

Mẹo: Luôn thiết kế abort criteria trước khi chạy stress test ở môi trường staging chia sẻ hoặc gần giống production. AI có thể gợi ý ngưỡng SLO rất chuẩn, nhưng không "cảm" được rủi ro chính trị/vận hành nếu bạn vô tình làm sập môi trường mà team khác đang dùng để demo cho khách hàng.

How to Generate k6, Gatling, or Locust Scripts with AI? (Làm sao sinh script k6, Gatling, hoặc Locust bằng AI?)

Generating a complete k6 script (Sinh một script k6 hoàn chỉnh)

Khi đã có đầy đủ critical path, load profile, và threshold, bước cuối là chuyển hóa thành code thực thi. Đây là bước AI tiết kiệm thời gian nhiều nhất, vì viết script performance test bằng tay rất tốn effort — đặc biệt là phần correlation giữa các request (token, session id) và checks (kiểm tra response hợp lệ).

Prompt tôi thường dùng để sinh k6 script:

Viết một script k6 (JavaScript) hoàn chỉnh để test luồng checkout của
một API e-commerce, với các bước sau:
1. POST /api/auth/login -> lấy access_token từ response JSON
2. GET /api/cart -> dùng access_token trong header Authorization
3. POST /api/cart/items -> thêm 1 sản phẩm ngẫu nhiên (product_id lấy
   từ danh sách 20 SKU giả định)
4. POST /api/checkout -> dùng cart_id từ bước 2, kiểm tra response
   status 200 và có trường "order_id"

Yêu cầu kỹ thuật:
- Dùng http module của k6, có check() cho mỗi bước để validate response
- Thêm think time ngẫu nhiên 2-5 giây giữa các bước bằng sleep()
- Dùng Trend để đo riêng response time của bước checkout
- Dùng Counter để đếm số order thành công
- Có options.thresholds cho p95 < 500ms và error rate < 1%
- Có stages ramp-up từ 0 lên 200 VU trong 5 phút, giữ 10 phút, ramp-down
  2 phút

Script AI trả về thường cần chỉnh sửa nhỏ (tên field JSON đúng theo API thật, xử lý lỗi 401 khi token hết hạn), nhưng đã tiết kiệm 70-80% thời gian viết boilerplate. Ví dụ một bản rút gọn sau khi review:

import http from 'k6/http';
import { check, sleep } from 'k6';
import { Trend, Counter } from 'k6/metrics';

const checkoutDuration = new Trend('checkout_duration');
const successfulOrders = new Counter('successful_orders');
const BASE_URL = 'https://staging-api.example.com';

export const options = {
  stages: [
    { duration: '5m', target: 200 },
    { duration: '10m', target: 200 },
    { duration: '2m', target: 0 },
  ],
  thresholds: {
    http_req_duration: ['p(95)<500'],
    http_req_failed: ['rate<0.01'],
  },
};

export default function () {
  const loginRes = http.post(`${BASE_URL}/api/auth/login`, JSON.stringify({
    username: `user_${__VU}`,
    password: 'Test@1234',
  }), { headers: { 'Content-Type': 'application/json' } });

  check(loginRes, { 'login status 200': (r) => r.status === 200 });
  const token = loginRes.json('access_token');
  const authHeaders = { headers: { Authorization: `Bearer ${token}` } };

  sleep(Math.random() * 3 + 2);

  const cartRes = http.get(`${BASE_URL}/api/cart`, authHeaders);
  check(cartRes, { 'cart status 200': (r) => r.status === 200 });
  const cartId = cartRes.json('cart_id');

  const productId = `SKU-${Math.floor(Math.random() * 20) + 1}`;
  http.post(`${BASE_URL}/api/cart/items`, JSON.stringify({
    cart_id: cartId, product_id: productId, quantity: 1,
  }), authHeaders);

  sleep(Math.random() * 3 + 2);

  const start = Date.now();
  const checkoutRes = http.post(`${BASE_URL}/api/checkout`, JSON.stringify({
    cart_id: cartId,
  }), authHeaders);
  checkoutDuration.add(Date.now() - start);

  const ok = check(checkoutRes, {
    'checkout status 200': (r) => r.status === 200,
    'has order_id': (r) => r.json('order_id') !== undefined,
  });
  if (ok) successfulOrders.add(1);

  sleep(1);
}

Generating a Gatling simulation with AI (Sinh Gatling simulation bằng AI)

Với các team Java/Scala, Gatling vẫn là lựa chọn phổ biến nhờ khả năng report chi tiết và DSL (Domain Specific Language) dễ đọc. Prompt cho AI cần nêu rõ bạn muốn dùng Scala DSL (không phải Java DSL mới của Gatling 3.7+) nếu team đang dùng phiên bản cũ, tránh AI trả về cú pháp không tương thích.

Viết một Gatling simulation (Scala DSL) test luồng search sản phẩm cho
một API e-commerce:
1. GET /api/products/search?q={keyword} với keyword random từ feeder
   CSV có 50 từ khóa
2. Kiểm tra response status 200 và JSON path $.results tồn tại
3. Pause 2-4 giây
4. GET /api/products/{id} lấy chi tiết 1 sản phẩm đầu tiên trong kết quả

Yêu cầu: dùng feeder từ file CSV "keywords.csv", cấu hình
injection profile rampUsersPerSec từ 10 lên 100 trong 3 phút rồi giữ
constantUsersPerSec 100 trong 5 phút, có assertion global response
time p95 < 400ms và failed request < 1%.

Kết quả sau khi review kỹ:

import io.gatling.core.Predef._
import io.gatling.http.Predef._
import scala.concurrent.duration._

class ProductSearchSimulation extends Simulation {

  val httpProtocol = http
    .baseUrl("https://staging-api.example.com")
    .acceptHeader("application/json")

  val keywordFeeder = csv("keywords.csv").random

  val searchScenario = scenario("Product Search Flow")
    .feed(keywordFeeder)
    .exec(
      http("Search Products")
        .get("/api/products/search")
        .queryParam("q", "${keyword}")
        .check(status.is(200))
        .check(jsonPath("$.results[0].id").saveAs("firstProductId"))
    )
    .pause(2.seconds, 4.seconds)
    .exec(
      http("Get Product Detail")
        .get("/api/products/${firstProductId}")
        .check(status.is(200))
    )

  setUp(
    searchScenario.inject(
      rampUsersPerSec(10).to(100).during(3.minutes),
      constantUsersPerSec(100).during(5.minutes)
    )
  ).protocols(httpProtocol)
    .assertions(
      global.responseTime.percentile(95).lt(400),
      global.failedRequests.percent.lt(1.0)
    )
}

Generating a Locust script for Python teams (Sinh script Locust cho team dùng Python)

Locust phù hợp với các team Python vì cú pháp gần giống viết test case thông thường, và dễ mở rộng logic phức tạp (ví dụ tính toán động, gọi thư viện xử lý dữ liệu có sẵn). Khi prompt AI viết Locust, tôi luôn nhấn mạnh yêu cầu dùng HttpUser, khai báo wait_time, và tổ chức task theo trọng số (@task(weight)) để mô phỏng đúng traffic mix đã tính ở phần load profile.

Viết một Locust script (Python) mô phỏng traffic mix cho hệ thống
e-commerce với 3 loại hành vi:
- 60% người dùng chỉ browse sản phẩm (GET /api/products)
- 30% người dùng search rồi xem chi tiết (GET /api/products/search,
  sau đó GET /api/products/{id})
- 10% người dùng thực hiện checkout đầy đủ (login -> add to cart ->
  checkout)

Yêu cầu: dùng HttpUser, wait_time giữa 2-6 giây, dùng @task(weight) để
set trọng số theo tỷ lệ trên, có on_start() để login trước cho user
checkout, dùng self.client với catch_response=True để custom validate.

Script hoàn chỉnh sau khi tinh chỉnh:

import random
from locust import HttpUser, task, between

class EcommerceUser(HttpUser):
    wait_time = between(2, 6)
    token = None

    def on_start(self):
        response = self.client.post("/api/auth/login", json={
            "username": f"user_{random.randint(1, 10000)}",
            "password": "Test@1234",
        })
        if response.status_code == 200:
            self.token = response.json().get("access_token")

    @task(60)
    def browse_products(self):
        self.client.get("/api/products")

    @task(30)
    def search_and_view(self):
        keyword = random.choice(["shoes", "laptop", "watch", "backpack"])
        with self.client.get(
            f"/api/products/search?q={keyword}", catch_response=True
        ) as resp:
            if resp.status_code != 200:
                resp.failure(f"Search failed: {resp.status_code}")
                return
            results = resp.json().get("results", [])
            if results:
                product_id = results[0]["id"]
                self.client.get(f"/api/products/{product_id}")

    @task(10)
    def full_checkout(self):
        if not self.token:
            return
        headers = {"Authorization": f"Bearer {self.token}"}
        cart = self.client.get("/api/cart", headers=headers).json()
        self.client.post("/api/cart/items", json={
            "cart_id": cart.get("cart_id"),
            "product_id": f"SKU-{random.randint(1, 20)}",
            "quantity": 1,
        }, headers=headers)
        with self.client.post(
            "/api/checkout",
            json={"cart_id": cart.get("cart_id")},
            headers=headers,
            catch_response=True,
        ) as resp:
            if resp.status_code == 200 and "order_id" in resp.json():
                resp.success()
            else:
                resp.failure("Checkout did not return order_id")

Mẹo: Đừng bao giờ copy script AI sinh ra và chạy thẳng vào môi trường gần production. Luôn chạy thử với số VU rất nhỏ (5-10) trước, kiểm tra log request/response, đảm bảo correlation (token, cart_id, id) hoạt động đúng — vì AI thường "đoán" tên field JSON dựa trên convention phổ biến, có thể không khớp 100% với API thực tế của bạn.

Tóm lại, AI không thay thế được vai trò tư duy của performance engineer — nó không tự biết ngưỡng chịu tải hợp lý của hạ tầng bạn, không tự biết khi nào dừng test để tránh sự cố. Nhưng nó là một trợ lý cực kỳ hiệu quả ở ba việc: phân tích dữ liệu lớn (requirement, log) để xác định đúng nơi cần test, tính toán chuyển đổi số liệu kinh doanh sang thông số kỹ thuật, và sinh code boilerplate cho k6/Gatling/Locust nhanh gấp nhiều lần viết tay. Kỹ năng quan trọng nhất của một QA hiện đại không còn là "nhớ cú pháp k6" mà là biết đặt đúng câu hỏi, đúng ngữ cảnh cho AI, và biết review kết quả với con mắt của một người hiểu hệ thống thật.