Tháng 11 vừa qua, một anh chàng dev tên Minh - chủ một cửa hàng thương mại điện tử bán đồ gia dụng - quyết định tích hợp chatbot AI vào website của mình. Kết quả? Hệ thống chạy ngon lành với 50 khách truy cập cùng lúc, nhưng ngay khi sự kiện flash sale bắt đầu với 500 người đổ vào, API sụp đổ hoàn toàn. 5 phút downtime trong đợt sale giá chỉ còn 99K đã khiến anh thiệt hại 30 triệu đồng doanh thu. Câu chuyện này là bài học đắt giá về tầm quan trọng của việc stress test trước khi ra mắt - và hôm nay, mình sẽ hướng dẫn các bạn cách thực hiện điều đó với Locust và k6.

Tại sao phải load test API AI?

Khác với API thông thường trả về JSON trong vài mili-giây, các mô hình ngôn ngữ lớn (LLM) có đặc thù riêng:

Với HolySheep AI, các bạn được hưởng chi phí cực kỳ cạnh tranh - chỉ từ $0.42/MTok với DeepSeek V3.2, rẻ hơn 85% so với các provider khác. Nhưng dù tiết kiệm đến đâu, việc stress test không kiểm soát vẫn có thể khiến credits bay nhanh hơn mong đợi.

Chuẩn bị môi trường

# Cài đặt Locust (Python)
pip install locust

Cài đặt k6 (macOS)

brew install k6

Hoặc download từ https://k6.io/docs/getting-started/installation/

Windows: choco install k6

# Kiểm tra cài đặt thành công
locust --version

Output: locust 2.20.0

k6 version

Output: k6 v0.48.0

Script Locust -压测 HolySheep AI

Locust là công cụ Python-based, dễ đọc và mở rộng. Mình khuyên dùng cho team có backend developer quen thuộc với Python.

# locustfile.py
import os
from locust import HttpUser, task, between, events
import json
import time

Cấu hình HolySheep AI

BASE_URL = "https://api.holysheep.ai/v1" API_KEY = os.getenv("HOLYSHEEP_API_KEY", "YOUR_HOLYSHEEP_API_KEY") class AIAgentUser(HttpUser): wait_time = between(1, 3) # Đợi 1-3 giây giữa các request host = BASE_URL def on_start(self): """Gọi 1 lần khi user bắt đầu""" self.headers = { "Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json" } # Test connection response = self.client.get( "/models", headers=self.headers, name="/models" ) if response.status_code == 200: print(f"[✓] Kết nối HolySheep AI thành công") else: print(f"[✗] Lỗi kết nối: {response.status_code}") @task(3) def chat_completion_short(self): """Task phổ biến nhất - hỏi đáp ngắn (trọng số 3)""" payload = { "model": "gpt-4.1", "messages": [ {"role": "user", "content": "Liệt kê 3 cách tiết kiệm chi phí khi sử dụng AI API trong doanh nghiệp"} ], "max_tokens": 150, "temperature": 0.7 } start_time = time.time() with self.client.post( "/chat/completions", json=payload, headers=self.headers, catch_response=True, name="/chat/completions [short]" ) as response: latency = (time.time() - start_time) * 1000 if response.elapsed.total_seconds() > 5: response.failure(f"Timeout! Latency: {latency:.0f}ms") elif response.status_code == 200: data = response.json() usage = data.get("usage", {}) input_tokens = usage.get("prompt_tokens", 0) output_tokens = usage.get("completion_tokens", 0) total_cost = (input_tokens * 8 + output_tokens * 8) / 1_000_000 response.success() print(f"[OK] {latency:.0f}ms | In:{input_tokens} Out:{output_tokens} | ~${total_cost:.6f}") else: response.failure(f"Lỗi HTTP {response.status_code}") @task(1) def chat_completion_long(self): """Task hiếm hơn - yêu cầu phân tích dài""" payload = { "model": "gpt-4.1", "messages": [ {"role": "system", "content": "Bạn là chuyên gia phân tích thị trường E-commerce"}, {"role": "user", "content": "Phân tích chi tiết xu hướng mua sắm online tại Việt Nam 2024-2025 và đưa ra chiến lược kinh doanh cho shop nhỏ"} ], "max_tokens": 800, "temperature": 0.5 } start_time = time.time() with self.client.post( "/chat/completions", json=payload, headers=self.headers, catch_response=True, name="/chat/completions [long]" ) as response: latency = (time.time() - start_time) * 1000 if response.elapsed.total_seconds() > 30: response.failure(f"Timeout nghiêm trọng! {latency:.0f}ms") elif response.status_code == 200: response.success() print(f"[OK] Phân tích dài: {latency:.0f}ms") else: response.failure(f"Lỗi HTTP {response.status_code}") @task(1) def embedding_document(self): """Test endpoint embeddings - quan trọng cho RAG""" payload = { "model": "text-embedding-3-small", "input": "Hướng dẫn sử dụng máy lọc nước Karofi 9 lõi cho gia đình 4 người" } with self.client.post( "/embeddings", json=payload, headers=self.headers, catch_response=True, name="/embeddings" ) as response: if response.status_code == 200: response.success() else: response.failure(f"Embedding lỗi: {response.status_code}") @events.test_start.add_listener def on_test_start(environment, **kwargs): print("🚀 Bắt đầu stress test HolySheep AI...") print(f"📍 Target: {BASE_URL}") print(f"💰 Rate limit: Kiểm tra response header X-RateLimit-*") @events.test_stop.add_listener def on_test_stop(environment, **kwargs): print("\n📊 Kết thúc stress test!") print("💡 Xem chi tiết tại http://localhost:8089")
# Chạy Locust với các tham số khác nhau

Test nhẹ - 10 users, spawn 2 users/giây

locust -f locustfile.py \ --headless \ --users 10 \ --spawn-rate 2 \ --run-time 60s \ --host https://api.holysheep.ai/v1

Test trung bình - 50 users

locust -f locustfile.py \ --headless \ --users 50 \ --spawn-rate 5 \ --run-time 2m \ --host https://api.holysheep.ai/v1 \ --html report.html # Xuất báo cáo HTML

Test nặng - 200 users, spawn 10 users/giây

locust -f locustfile.py \ --headless \ --users 200 \ --spawn-rate 10 \ --run-time 5m \ --host https://api.holysheep.ai/v1 \ --html report_heavy.html \ --csv results # Xuất CSV cho phân tích Excel

Chạy với Web UI (mở tab trình duyệt http://localhost:8089)

locust -f locustfile.py --host https://api.holysheep.ai/v1

Script k6 - JavaScript-based load testing

k6 được viết bằng Go, performace cao hơn Locust, phù hợp cho CI/CD pipeline và automated testing.

// load-test.js
import http from 'k6/http';
import { check, sleep } from 'k6';
import { Rate, Trend } from 'k6/metrics';

// Custom metrics
const errorRate = new Rate('errors');
const latencyTrend = new Trend('latency_ms');
const tokenCost = new Trend('token_cost_usd');

// Cấu hình
const BASE_URL = 'https://api.holysheep.ai/v1';
const API_KEY = __ENV.HOLYSHEEP_API_KEY || 'YOUR_HOLYSHEEP_API_KEY';

// Giá token HolySheep 2026 (USD per million tokens)
const TOKEN_PRICES = {
  'gpt-4.1': { input: 8, output: 8 },           // $8/MTok
  'claude-sonnet-4.5': { input: 15, output: 15 }, // $15/MTok
  'gemini-2.5-flash': { input: 2.5, output: 2.5 }, // $2.50/MTok
  'deepseek-v3.2': { input: 0.42, output: 0.42 }   // $0.42/MTok
};

export const options = {
  // Các cấu hình test phổ biến
  scenarios: {
    // Smoke test - xác nhận hệ thống hoạt động
    smoke: {
      executor: 'constant-vus',
      vus: 1,
      duration: '30s',
      tags: { test_type: 'smoke' }
    },
    
    // Load test - mô phỏng production bình thường
    load: {
      executor: 'ramping-vus',
      startVUs: 0,
      stages: [
        { duration: '1m', target: 20 },   // Tăng lên 20 users trong 1 phút
        { duration: '3m', target: 20 },   // Giữ 20 users trong 3 phút
        { duration: '1m', target: 0 }     // Giảm về 0
      ],
      tags: { test_type: 'load' }
    },
    
    // Stress test - vượt ngưỡng bình thường
    stress: {
      executor: 'ramping-arrival-rate',
      startRate: 1,
      timeUnit: '1s',
      preAllocatedVUs: 50,
      stages: [
        { duration: '2m', target: 5 },    // 5 requests/giây
        { duration: '3m', target: 15 },    // 15 requests/giây
        { duration: '5m', target: 30 },    // 30 requests/giây
        { duration: '2m', target: 0 }       // Cool down
      ],
      tags: { test_type: 'stress' }
    },
    
    // Spike test - đột biến đột ngột
    spike: {
      executor: 'spike',
      vus: 10,
      duration: '2m',
      preAllocatedVUs: 100,
      stages: [
        { duration: '30s', target: 10 },   // Bình thường
        { duration: '30s', target: 100 },  // SPIKE!
        { duration: '2m', target: 100 },   // Giữ spike
        { duration: '30s', target: 10 },   // Trở về
        { duration: '30s', target: 0 }     // Cool down
      ],
      tags: { test_type: 'spike' }
    }
  },
  
  // Ngưỡng cho CI/CD pass/fail
  thresholds: {
    'http_req_duration': ['p(95)<2000'],      // 95% requests phải < 2s
    'http_req_failed': ['rate<0.05'],          // Error rate < 5%
    'errors': ['rate<0.1'],                     // Custom error rate < 10%
    'latency_ms': ['p(99)<5000']               // P99 latency < 5s
  }
};

const headers = {
  'Authorization': Bearer ${API_KEY},
  'Content-Type': 'application/json'
};

export default function () {
  // Test với nhiều model
  const models = ['deepseek-v3.2', 'gemini-2.5-flash'];
  const model = models[Math.floor(Math.random() * models.length)];
  
  const payload = JSON.stringify({
    model: model,
    messages: [
      { 
        role: 'user', 
        content: 'Tóm tắt các tính năng nổi bật của iPhone 16 Pro Max và so sánh với Samsung S24 Ultra'
      }
    ],
    max_tokens: 200,
    temperature: 0.7
  });
  
  const startTime = Date.now();
  
  const response = http.post(
    ${BASE_URL}/chat/completions,
    payload,
    { headers }
  );
  
  const latency = Date.now() - startTime;
  latencyTrend.add(latency);
  
  // Parse response
  const success = check(response, {
    'status is 200': (r) => r.status === 200,
    'has content': (r) => r.json('choices') !== undefined,
    'has usage': (r) => r.json('usage') !== undefined
  });
  
  errorRate.add(!success);
  
  if (success) {
    const usage = response.json('usage');
    const inputTokens = usage.prompt_tokens;
    const outputTokens = usage.completion_tokens;
    
    // Tính chi phí
    const prices = TOKEN_PRICES[model] || TOKEN_PRICES['deepseek-v3.2'];
    const cost = (inputTokens * prices.input + outputTokens * prices.output) / 1_000_000;
    tokenCost.add(cost);
    
    console.log(
      ✅ Model: ${model} | Latency: ${latency}ms |  +
      Tokens: ${inputTokens}+${outputTokens} | Cost: $${cost.toFixed(6)}
    );
    
    // Kiểm tra rate limit headers
    const rateLimitRemaining = response.headers['X-RateLimit-Remaining'];
    if (rateLimitRemaining) {
      console.log(⚡ Rate limit remaining: ${rateLimitRemaining});
    }
  } else {
    console.error(❌ Lỗi: ${response.status} - ${response.body});
  }
  
  sleep(Math.random() * 2 + 1);  // Đợi 1-3 giây
}

// Hook để log tổng chi phí sau test
export function handleSummary(data) {
  const totalTokenCost = data.metrics.token_cost_usd?.values?.sum || 0;
  
  return {
    stdout: textSummary(data),
    'summary.json': JSON.stringify({
      total_requests: data.metrics.http_reqs?.values?.count || 0,
      total_errors: data.metrics.errors?.values?.count || 0,
      avg_latency_ms: data.metrics.latency_ms?.values?.avg || 0,
      p99_latency_ms: data.metrics.latency_ms?.values['99'] || 0,
      total_token_cost_usd: totalTokenCost,
      estimated_cost_per_hour: totalTokenCost * 3600 / (data.state.testRunDurationMs / 1000)
    })
  };
}

function textSummary(data) {
  return `
========================================
📊 STRESS TEST RESULTS - HolySheep AI
========================================
Total Requests: ${data.metrics.http_reqs?.values?.count || 0}
Failed Requests: ${data.metrics.http_req_failed?.values?.passes || 0}
Error Rate: ${((data.metrics.errors?.values?.rate || 0) * 100).toFixed(2)}%

⏱️ Latency:
  - Average: ${(data.metrics.latency_ms?.values?.avg || 0).toFixed(0)}ms
  - P95: ${(data.metrics.latency_ms?.values['95'] || 0).toFixed(0)}ms
  - P99: ${(data.metrics.latency_ms?.values['99'] || 0).toFixed(0)}ms

💰 Token Cost:
  - Total: $${(data.metrics.token_cost_usd?.values?.sum || 0).toFixed(6)}
  - Est. Cost/Hour at this rate: $${((data.metrics.token_cost_usd?.values?.sum || 0) * 3600 / (data.state.testRunDurationMs / 1000)).toFixed(2)}

========================================
`;
}

Tài nguyên liên quan

Bài viết liên quan