nkds

导航

 

MonkeyCode 性能基准测试体系建设:从零打造可量化的性能保障体系

引言

在软件开发生命周期中,性能基准测试(Performance Benchmarking) 是确保系统在真实负载下稳定运行的关键实践。作为一款支持私有化部署的 AI 编程工具,MonkeyCode 面临着高并发 API 调用、大模型推理延迟、实时代码分析等多重性能挑战。本文将全面分享 MonkeyCode 的性能基准测试体系建设经验。

GitHub Issue 邀请:如果您在性能测试、基准测试框架或性能优化方面有任何问题或建议,欢迎前往 MonkeyCode GitHub 仓库 提交 Issue 或参与讨论!


一、为什么需要性能基准测试体系?

1.1 没有基准测试的后果

┌─────────────────────────────────────────────────────────────┐
│           ❌ 缺乏性能基准测试的典型症状                        │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  📈 功能上线 → 用户量增长 → 系统变慢                          │
│       ↓                                                      │
│  🔍 开始排查 → 发现瓶颈 → 紧急优化                           │
│       ↓                                                      │
│  🐛 修复引入新问题 → 回归无感知 → 再次出问题                   │
│       ↓                                                      │
│  😤 用户投诉 → 团队加班 → 技术债务累积                        │
│                                                             │
│  💥 核心问题:                                               │
│  • 不知道"快"的标准是什么                                     │
│  • 无法量化性能退化                                           │
│  • 优化效果无法验证                                          │
│  • 回归问题发现太晚                                          │
│                                                             │
└─────────────────────────────────────────────────────────────┘

1.2 基准测试的核心价值

维度 无基准测试 有基准测试
性能目标 模糊("尽量快") 明确(P99 < 200ms)
回归检测 用户投诉后才发现 提交时自动检测
优化决策 凭直觉 数据驱动
容量规划 盲目扩容 基于数据预测
团队协作 各自为战 统一标准

二、MonkeyCode 性能基准测试体系概览

2.1 四层测试金字塔

                    ┌─────────────────────────────────┐
                    │   MonkeyCode 性能测试金字塔        │
                    └──────────────┬──────────────────┘
                                   │
              ┌────────────────────┼────────────────────┐
              ▼                    ▼                    ▼
     ┌────────────────┐  ┌────────────────┐  ┌────────────────┐
     │  🏗️ L4 生产    │  │  ⚡ L3 集成    │  │  🔬 L2 组件    │
     │  环境全链路    │  │  测试         │  │  基准测试      │
     ├────────────────┤  ├────────────────┤  ├────────────────┤
     │• 全链路压测    │  │• API 性能测试  │  │• 核心函数基准  │
     │• 混沌工程      │  │• 端到端场景    │  │• 算法性能对比  │
     │• 容量规划      │  │• 数据库查询    │  │• 内存/CPU 分析 │
     │• 故障演练      │  │• 缓存命中率    │  │• 单元级性能    │
     └────────────────┘  └────────────────┘  └────────────────┘
                                   │
                                   ▼
                         ┌────────────────┐
                         │  📊 L1 微基准   │
                         │  测试          │
                         ├────────────────┤
                         │• 单函数耗时    │
                         │• 内存分配      │
                         │• 热路径优化    │
                         │• 编译器对比    │
                         └────────────────┘

2.2 各层职责与工具

performance_testing_layers:

  micro_benchmarks:
    layer: "L1 - 微基准测试"
    scope: "单个函数/方法级别"
    tools:
      - "Benchmark.js (JavaScript)"
      - "pytest-benchmark (Python)"
      - "criterion (Rust)"
      - "go test -bench (Go)"
    metrics:
      - "ops/sec (吞吐量)"
      - "mean/median/p99 latency"
      - "memory allocation per op"
      - "CPU cycles per op"
    frequency: "每个 PR / 关键函数变更时"
    
  component_benchmarks:
    layer: "L2 - 组件基准测试"
    scope: "独立模块/组件级别"
    tools:
      - "k6 (负载测试)"
      - "Artillery (HTTP 基准)"
      - "JMeter (综合测试)"
      - "自定义 Benchmark Runner"
    metrics:
      - "request throughput (RPS)"
      - "response time percentiles"
      - "error rate under load"
      - "resource utilization"
    frequency: "每次合并到 develop 分支"

  integration_performance:
    layer: "L3 - 集成性能测试"
    scope: "多组件交互场景"
    tools:
      - "Locust (Python 负载)"
      - "k6 (脚本化测试)"
      - "Gatling (Scala)"
      - "wrk (HTTP 基准)"
    scenarios:
      - "用户注册登录流程"
      - "代码提交→分析→建议 完整流程"
      - "AI 对话多轮交互"
      - "并发文件编辑"
    frequency: "每周 / 版本发布前"

  production_simulation:
    layer: "L4 - 生产环境模拟"
    scope: "全链路、真实负载模式"
    tools:
      - "Prometheus + Grafana (监控)"
      - "K6 Cloud (云端压测)"
      - "Chaos Mesh (混沌工程)"
      - "自定义流量回放"
    scenarios:
      - "峰值流量模拟 (3x 正常)"
      - "故障注入测试"
      - "容量极限探测"
      - "长时间稳定性 (Soak Test)"
    frequency: "季度 / 大版本发布前"

三、核心指标定义

3.1 MonkeyCode 关键性能指标(KPI)

performance_kpis:
  
  api_latency:
    name: "API 响应延迟"
    endpoints:
      - endpoint: "/api/v1/code/analyze"
        description: "代码分析接口"
        targets:
          p50: "< 200ms"
          p95: "< 500ms"
          p99: "< 1000ms"
        baseline:
          p50: "150ms"
          p95: "400ms"
          p99: "850ms"
          
      - endpoint: "/api/v1/ai/chat"
        description: "AI 对话接口(含 LLM 调用)"
        targets:
          p50: "< 1500ms"
          p95: "< 3000ms"
          p99: "< 5000ms"
        baseline:
          p50: "1200ms"
          p95: "2500ms"
          p99: "4200ms"
          
      - endpoint: "/api/v1/auth/login"
        description: "用户登录"
        targets:
          p50: "< 100ms"
          p95: "< 200ms"
          p99: "< 400ms"
        baseline:
          p50: "80ms"
          p95: "160ms"
          p99: "320ms"

  throughput:
    name: "系统吞吐量"
    targets:
      concurrent_users: "> 10,000"
      requests_per_second: "> 5,000 RPS"
      ai_conversations_per_minute: "> 500 CPM"
      
  resource_efficiency:
    name: "资源利用率"
    targets:
      cpu_per_request: "< 10ms CPU time"
      memory_per_user_session: "< 50MB"
      db_connection_pool_utilization: "< 80%"
      cache_hit_rate: "> 90%"
      
  reliability:
    name: "可靠性指标"
    targets:
      availability: "> 99.9%"
      error_rate: "< 0.1%"
      mean_time_to_recovery: "< 5 minutes"

3.2 SLO 定义与告警阈值

service_level_objectives:
  
  monkeycode_api_slo:
    name: "MonkeyCode API Service Level Objective"
    target: "99.5% of requests within SLA"
    measurement_window: "30 rolling days"
    
    error_budget:
      total_allowed_error_rate: "0.5%"
      burn_rate_alerts:
        slow: "2x normal consumption (24h to exhaust)"
        fast: "14x normal consumption (4h to exhaust)"
        
    latency_sli:
      name: "Request Latency"
      good_event: "request duration < SLA threshold"
      bad_event: "request duration >= SLA threshold"
      sla_by_tier:
        free: "p99 < 2000ms"
        pro: "p99 < 1000ms"
        enterprise: "p99 < 500ms"
        
    availability_sli:
      name: "Service Availability"
      good_event: "HTTP status 2xx or 4xx (client error)"
      bad_event: "HTTP status 5xx (server error)"

四、基准测试实施

4.1 微基准测试示例

// benchmarks/code-parser.bench.js — MonkeyCode 代码解析微基准
import benchmark from 'benchmark';
import { parseJavaScript, parseTypeScript, parsePython } from '@/parsers';

const suite = new Suite('Code Parser Benchmarks');

const sampleJS = `
function fibonacci(n) {
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

class Calculator {
  constructor(initial = 0) { this.value = initial; }
  add(n) { this.value += n; return this; }
  subtract(n) { this.value -= n; return this; }
  multiply(n) { this.value *= n; return this; }
  getResult() { return this.value; }
}
`;

const sampleTS = `
interface User {
  id: string;
  name: string;
  email: string;
  role: 'admin' | 'user' | 'guest';
  createdAt: Date;
  preferences?: Record<string, unknown>;
}

async function fetchUser(id: string): Promise<User | null> {
  const response = await fetch(\`/api/users/\${id}\`);
  if (!response.ok) return null;
  return response.json();
}
`;

// JavaScript 解析基准
suite.add('Parse JavaScript (small)', () => {
  parseJavaScript(sampleJS);
});

suite.add('Parse TypeScript (medium)', () => {
  parseTypeScript(sampleTS);
});

// 不同规模输入
const largeFileContent = generateLargeTSFile(10000); // 10000 行 TS 文件
suite.add('Parse TypeScript (large, 10K lines)', () => {
  parseTypeScript(largeFileContent);
});

// 内存分配追踪
if (process.env.MEMORY_PROFILE) {
  suite.add('Parse JS (with memory tracking)', {
    fn() { parseJavaScript(sampleJS); },
    onStart(event) { event.target.memoryBefore = process.memoryUsage(); },
    onComplete(event) {
      const after = process.memoryUsage();
      const delta = after.heapUsed - event.target.memoryBefore.heapUsed;
      console.log(`Memory delta: ${(delta / 1024 / 1024).toFixed(2)} MB`);
    },
  });
}

// 运行并输出结果
suite
  .on('cycle', (event) => {
    console.log(String(event.target));
  })
  .on('complete', function() {
    console.log('\nFastest is ' + this.filter('fastest').map('name'));
    
    // 输出 JSON 格式供 CI 使用
    const results = this.map(result => ({
      name: result.name,
      ops: result.hz,
      margin: result.stats.rme,
      samples: result.stats.sample.length,
    }));
    console.log('\n=== JSON Results ===');
    console.log(JSON.stringify(results, null, 2));
  })
  .run({ async: true });
# benchmarks/test_ai_inference.py — MonkeyCode AI 推理基准测试
import pytest
import asyncio
import statistics
import time
from datetime import datetime


class AIBenchmarkResult:
    """AI 推理基准测试结果"""
    def __init__(self):
        self.latencies: list[float] = []
        self.token_counts: list[int] = []
        self.errors: int = 0
        
    @property
    def avg_latency_ms(self) -> float:
        return statistics.mean(self.latencies) if self.latencies else 0
    
    @property
    def p50_latency_ms(self) -> float:
        sorted_lat = sorted(self.latencies)
        idx = len(sorted_lat) // 2
        return sorted_lat[idx]
    
    @property
    def p99_latency_ms(self) -> float:
        sorted_lat = sorted(self.latencies)
        idx = int(len(sorted_lat) * 0.99)
        return sorted_lat[min(idx, len(sorted_lat) - 1)]
    
    @property
    def tokens_per_second(self) -> float:
        if not self.latencies or not sum(self.token_counts):
            return 0.0
        total_tokens = sum(self.token_counts)
        total_seconds = sum(self.latencies) / 1000
        return total_tokens / total_seconds
    
    def to_dict(self) -> dict:
        return {
            "avg_latency_ms": round(self.avg_latency_ms, 2),
            "p50_latency_ms": round(self.p50_latency_ms, 2),
            "p99_latency_ms": round(self.p99_latency_ms, 2),
            "tokens_per_second": round(self.tokens_per_second, 2),
            "error_count": self.errors,
            "total_requests": len(self.latencies),
        }


@pytest.mark.asyncio
@pytest.mark.benchmark
async def test_ai_chat_completion_throughput():
    """测试 AI 对话完成接口的吞吐量和延迟"""
    from app.services.ai_service import AIService
    
    service = AIService()
    result = AIBenchmarkResult()
    
    prompts = [
        "解释什么是闭包?",
        "如何实现一个单例模式?",
        "React 和 Vue 的区别?",
        "什么是 Docker?",
        "解释 RESTful API 的设计原则。",
    ]
    
    # 并发测试配置
    concurrency = 10
    requests_per_round = 5
    rounds = 3
    
    for round_num in range(rounds):
        tasks = []
        for _ in range(concurrency):
            prompt = prompts[round_num % len(prompts)]
            tasks.append(_measure_single_request(service, prompt, result))
        
        await asyncio.gather(*tasks)
    
    # 输出结果
    print("\n" + "=" * 60)
    print("🚀 AI Inference Benchmark Results")
    print("=" * 60)
    print(f"Total requests: {result.total_requests}")
    print(f"Errors: {result.errors}")
    print(f"Avg latency: {result.avg_latency_ms:.2f} ms")
    print(f"P50 latency: {result.p50_latency_ms:.2f} ms")
    print(f"P99 latency: {result.p99_latency_ms:.2f} ms")
    print(f"Tokens/sec: {result.tokens_per_second:.2f}")
    print("=" * 60)
    
    # 断言性能基线
    assert result.p99_latency_ms < 5000, f"P99 latency {result.p99_latency_ms}ms exceeds 5000ms threshold"
    assert result.error_rate < 0.01, f"Error rate too high: {result.error_rate}"
    
    # 保存结果供 CI 对比
    _save_benchmark_result("ai_chat_completion", result.to_dict())


async def _measure_single_request(service: AIService, prompt: str, result: AIBenchmarkResult):
    """测量单次请求的性能"""
    start = time.perf_counter()
    try:
        response = await service.chat_completion(
            messages=[{"role": "user", "content": prompt}],
            max_tokens=500,
        )
        elapsed = (time.perf_counter() - start) * 1000  # ms
        result.latencies.append(elapsed)
        result.token_counts.append(response.token_count)
    except Exception as e:
        result.errors += 1
        print(f"Error: {e}")


def _save_benchmark_result(name: str, data: dict):
    """保存基准测试结果"""
    import json
    import os
    
    results_dir = os.path.join(os.path.dirname(__file__), "../benchmark-results")
    os.makedirs(results_dir, exist_ok=True)
    
    filename = f"{name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
    filepath = os.path.join(results_dir, filename)
    
    with open(filepath, 'w') as f:
        json.dump({
            "timestamp": datetime.now().isoformat(),
            "name": name,
            "data": data,
        }, f, indent=2)
    
    print(f"\n📊 Results saved to: {filepath}")

4.2 k6 负载测试脚本

// k6/tests/api-performance.js — MonkeyCode API 性能测试
import http from 'k6/http';
import { check, sleep } from 'k6';
import { Rate, Trend } from 'k6/metrics';
import { SharedArray } from 'k6/data';

// 自定义指标
const errorRate = new Rate('errors');
const apiLatency = new Trend('api_latency');

// 测试数据
const testData = new SharedArray('testPrompts', function () {
  return [
    'Write a Python function to sort a list',
    'Explain the concept of recursion',
    'How do I implement authentication?',
    'Debug this code snippet',
    'Refactor this class for better performance',
  ];
});

export const options = {
  stages: [
    { duration: '30s', target: 10 },   // 预热:逐步增加到 10 用户
    { duration: '1m', target: 50 },     // 加载:增加到 50 用户
    { duration: '2m', target: 100 },    // 高负载:100 用户
    { duration: '1m', target: 50 },     // 恢复:降到 50 用户
    { duration: '30s', target: 0 },     // 冷却:降到 0
  ],
  thresholds: {
    http_req_duration: ['p(95)<2000', 'p(99)<5000'],  // 延迟阈值
    errors: ['rate<0.05'],                              // 错误率 < 5%
    http_req_failed: ['rate<0.03'],                     // HTTP 失败率
  },
};

const BASE_URL = __ENV.BASE_URL || 'https://api.monkeyCode.dev';
const AUTH_TOKEN = __ENV.AUTH_TOKEN || '';

export default function () {
  // 场景 1:用户认证
  let authRes = http.post(`${BASE_URL}/auth/verify`, JSON.stringify({ token: AUTH_TOKEN }), {
    headers: { 'Content-Type': 'application/json' },
    tags: { scenario: 'auth' },
  });
  
  check(authRes, {
    'auth status 200': (r) => r.status === 200,
    'auth response time OK': (r) => r.timings.duration < 300,
  }) || errorRate.add(1);
  
  apiLatency.add(authRes.timings.duration, { endpoint: '/auth/verify' });
  
  sleep(Math.random() * 2);  // 模拟用户思考时间
  
  // 场景 2:代码分析
  const codeSample = `function quickSort(arr) {
    if (arr.length <= 1) return arr;
    const pivot = arr[0];
    const left = arr.slice(1).filter(x => x <= pivot);
    const right = arr.slice(1).filter(x => x > pivot);
    return [...quickSort(left), pivot, ...quickSort(right)];
  }`;
  
  let analyzeRes = http.post(`${BASE_URL}/v1/code/analyze`, JSON.stringify({
    language: 'javascript',
    code: codeSample,
    options: { complexity: true, suggestions: true },
  }), {
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${AUTH_TOKEN}`,
    },
    tags: { scenario: 'code-analysis' },
  });
  
  check(analyzeRes, {
    'analyze status 200': (r) => r.status === 200,
    'analyze has result': (r) => JSON.parse(r.body).analysis !== undefined,
    'analyze response time OK': (r) => r.timings.duration < 1000,
  }) || errorRate.add(1);
  
  apiLatency.add(analyzeRes.timings.duration, { endpoint: '/v1/code/analyze' });
  
  sleep(Math.random() * 3);
  
  // 场景 3:AI 对话
  const randomPrompt = testData[Math.floor(Math.random() * testData.length)];
  
  let chatRes = http.post(`${BASE_URL}/v1/ai/chat`, JSON.stringify({
    messages: [{ role: 'user', content: randomPrompt }],
    max_tokens: 200,
    temperature: 0.7,
  }), {
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${AUTH_TOKEN}`,
    },
    tags: { scenario: 'ai-chat' },
  });
  
  check(chatRes, {
    'chat status 200': (r) => r.status === 200,
    'chat has content': (r) => {
      try { return JSON.parse(r.body).content?.length > 0; }
      catch { return false; }
    },
  }) || errorRate.add(1);
  
  apiLatency.add(chatRes.timings.duration, { endpoint: '/v1/ai/chat' });
  
  sleep(Math.random() * 5);  // AI 响应后用户阅读时间
}

export function handleSummary(data) {
  // 自定义摘要输出
  console.log('\n========== MonkeyCode Performance Summary ==========');
  console.log(`Total requests: ${data.metrics.http_reqs?.values?.count || 0}`);
  console.log(`Error rate: ${(data.metrics.errors?.values?.rate || 0) * 100}%`);
  console.log('\n--- Latency by Percentile ---');
  if (data.metrics.http_req_duration) {
    console.log(`P50: ${data.metrics.http_req_duration.values['p(50)']}ms`);
    console.log(`P90: ${data.metrics.http_req_duration.values['p(90)']}ms`);
    console.log(`P95: ${data.metrics.http_req_duration.values['p(95)']}ms`);
    console.log(`P99: ${data.metrics.http_req_duration.values['p(99)']}ms`);
  }
  console.log('====================================================\n');
  
  // 如果失败率过高,退出码非零以便 CI 失败
  if ((data.metrics.errors?.values?.rate || 0) > 0.05) {
    console.error('❌ Error rate exceeds 5% threshold!');
  }
}

4.3 CI 集成:自动化性能回归检测

# .github/workflows/performance-regression.yml — MonkeyCode 性能回归检测
name: ⚡ Performance Regression Check

on:
  pull_request:
    branches: [main, develop]
    paths:
      - 'src/**'
      - 'package.json'
      - '**/Cargo.toml'
  push:
    branches: [main]
    paths:
      - 'src/**'

permissions:
  contents: read
  pull-requests: write

jobs:
  micro-benchmarks:
    name: 🔬 Micro Benchmarks
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0  # 需要 history 来对比
      
      - uses: pnpm/action-setup@v4
        with: { version: 9 }
      
      - uses: actions/setup-node@v4
        with: { node-version: 20, cache: 'pnpm' }
      
      - run: pnpm install --frozen-lockfile
      
      - name: Run Micro Benchmarks
        id: bench
        run: |
          pnpm build
          node benchmarks/run-all.js --format=json > benchmark-results.json
          
          echo "results<<EOF" >> $GITHUB_OUTPUT
          cat benchmark-results.json >> $GITHUB_OUTPUT
          echo "EOF" >> $GITHUB_OUTPUT
      
      - name: Compare with Baseline
        id: compare
        run: |
          node scripts/compare-benchmarks.js \
            --current benchmark-results.json \
            --baseline .benchmark-baseline.json \
            --threshold 0.10  # 允许 10% 波动
          
          echo "regression=$(cat regression-status.txt)" >> $GITHUB_OUTPUT
          echo "diff_details<<EOF" >> $GITHUB_OUTPUT
          cat benchmark-diff.md >> $GITHUB_OUTPUT
          echo "EOF" >> $GITHUB_OUTPUT
      
      - name: Comment on PR
        if: github.event_name == 'pull_request'
        uses: actions/github-script@v7
        with:
          script: |
            const diffDetails = `${{ steps.compare.outputs.diff_details }}`;
            const hasRegression = '${{ steps.compare.outputs.regression }}' === 'true';
            
            const body = `## ⚡ Performance Benchmark Results\n\n` +
              `${diffDetails}\n\n` +
              (hasRegression ? 
                '⚠️ **Performance regression detected!** Please review before merging.' :
                '✅ No significant performance regressions detected.');
            
            github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: body
            });
      
      - name: Fail on Regression
        if: steps.compare.outputs.regression == 'true'
        run: |
          echo "::error::Performance regression detected! See benchmark comparison above."
          exit 1

  api-load-test:
    name: 🚦 API Load Test (PR only)
    runs-on: ubuntu-latest
    if: github.event_name == 'pull_request'
    
    services:
      app:
        image: monkeycode:test-${{ github.sha }}
        ports:
          - 3000:3000
        options: >-
          --health-cmd="curl -f http://localhost:3000/api/health"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
      postgres:
        image: postgres:16-alpine
        env:
          POSTGRES_USER: test
          POSTGRES_PASSWORD: test
          POSTGRES_DB: monkeycode_test
        ports:
          - 5432:5432
      redis:
        image: redis:7-alpine
        ports:
          - 6379:6379
    
    steps:
      - uses: actions/checkout@v4
      
      - uses: actions/setup-go@v5
        with:
          go-version: '1.22'
      
      - name: Install k6
        run: go install go.k6.io/k6/v6/latest@latest
      
      - name: Wait for services
        run: |
          until curl -sf http://localhost:3000/api/health; do
            echo "Waiting for app..."
            sleep 2
          done
      
      - name: Run Load Test
        env:
          BASE_URL: http://localhost:3000
          AUTH_TOKEN: ${{ secrets.TEST_AUTH_TOKEN }}
        run: |
          ~/go/bin/k6 run k6/tests/api-performance.js \
            --summary-export=load-test-results.json \
            --out json=load-test-metrics/
      
      - name: Upload Results
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: load-test-results
          path: |
            load-test-results.json
            load-test-metrics/

五、性能数据分析与可视化

5.1 Grafana 仪表盘配置

{
  "dashboard": {
    "title": "MonkeyCode Performance Dashboard",
    "panels": [
      {
        "title": "API Latency P99 (24h)",
        "type": "timeseries",
        "targets": [
          {
            "expr": "histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket{job=\"monkeyCode-api\"}[5m])) by (le, endpoint))",
            "legendFormat": "{{endpoint}}"
          }
        ],
        "thresholds": [
          {"color": "green", "value": null},
          {"color": "yellow", "value": 1000},
          {"color": "red", "value": 3000}
        ]
      },
      {
        "title": "Requests Per Second",
        "type": "stat",
        "targets": [
          {
            "expr": "sum(rate(http_requests_total{job=\"monkeyCode-api\"}[1m]))",
            "legendFormat": "RPS"
          }
        ]
      },
      {
        "title": "Error Rate",
        "type": "gauge",
        "targets": [
          {
            "expr": "sum(rate(http_requests_total{job=\"monkeyCode-api\", status=~\"5..\"}[5m])) / sum(rate(http_requests_total{job=\"monkeyCode-api\"}[5m])) * 100",
            "legendFormat": "Error %"
          }
        ],
        "thresholds": [
          {"color": "green", "value": 0},
          {"color": "red", "value": 1}
        ]
      },
      {
        "title": "AI Inference Latency Distribution",
        "type": "heatmap",
        "targets": [
          {
            "expr": "sum(rate(ai_inference_duration_seconds_bucket{job=\"monkeyCode-ai\"}[5m])) by (le, model)",
            "legendFormat": "{{model}}"
          }
        ]
      }
    ]
  }
}

5.2 性能趋势追踪 SQL

-- MonkeyCode 性能趋势分析查询
WITH daily_metrics AS (
  SELECT 
    DATE_TRUNC('day', timestamp) AS day,
    endpoint,
    COUNT(*) AS request_count,
    ROUND(AVG(duration_ms), 2) AS avg_latency_ms,
    ROUND(PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY duration_ms), 2) AS p50_ms,
    ROUND(PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY duration_ms), 2) AS p95_ms,
    ROUND(PERCENTILE_CONT(0.99) WITHIN GROUP (ORDER BY duration_ms), 2) AS p99_ms,
    SUM(CASE WHEN status_code >= 500 THEN 1 ELSE 0 END) AS error_count,
    ROUND(100.0 * SUM(CASE WHEN status_code >= 500 THEN 1 ELSE 0 END) / NULLIF(COUNT(*), 0), 3) AS error_rate_pct
  FROM api_metrics
  WHERE timestamp >= NOW() - INTERVAL '30 days'
  GROUP BY DATE_TRUNC('day', timestamp), endpoint
)
SELECT 
  day,
  endpoint,
  request_count,
  avg_latency_ms,
  p50_ms,
  p95_ms,
  p99_ms,
  error_rate_pct,
  -- 计算与前一天的变化趋势
  LAG(avg_latency_ms) OVER (PARTITION BY endpoint ORDER BY day) AS prev_avg_latency,
  ROUND(
    100.0 * (avg_latency_ms - LAG(avg_latency_ms) OVER (PARTITION BY endpoint ORDER BY day)) 
    / NULLIF(LAG(avg_latency_ms) OVER (PARTITION BY endpoint ORDER BY day), 0), 
    2
  ) AS latency_change_pct
FROM daily_metrics
WHERE endpoint = '/api/v1/ai/chat'
ORDER BY day DESC
LIMIT 30;

六、常见问题与最佳实践

FAQ

## ❓ 性能基准测试常见问题

### Q1: 基准测试结果不稳定怎么办?
**A**:
1. 增加预热轮次(warmup)
2. 排除 GC/系统干扰(锁定 CPU 频率)
3. 增加样本数量(至少 100 次)
4. 使用统计方法报告(中位数优于均值)
5. 在隔离环境中运行

### Q2: 如何设定合理的性能基线?
**A**:
1. 从生产环境的 P95/P99 数据开始
2. 考虑业务需求(用户体验目标)
3. 参考行业同类产品标准
4. 设置合理的容差范围(通常 ±10-20%)
5. 定期回顾和调整基线

### Q3: 性能测试和功能测试如何平衡?
**A**:
1. 微基准:每个 PR 自动运行(快速)
2. 组件基准:合并到主分支时运行
3. 集成测试:发布前运行完整套件
4. 生产模拟:大版本和季度执行

### Q4: 如何处理性能退化的 PR?
**A**:
1. 自动标记性能回归
2. 要求开发者说明原因
3. 如果是预期内退化(如新功能),更新基线
4. 如果是意外退化,要求修复后再合入
5. 建立性能回归的例外审批流程

七、总结与行动号召

7.1 核心要点回顾

╔═══════════════════════════════════════════════════════════╗
║                                                           ║
║  🚀 MonkeyCode 性能基准测试六大原则                        ║
║                                                           ║
║  1️⃣ 可量化 — 一切以数据说话,拒绝"感觉变慢了"               ║
║  2️⃣ 可重复 — 相同条件下的结果必须一致                      ║
║  3️⃣ 可比较 — 历史数据对比,及时发现退化                     ║
║  4️⃣ 可自动化 — 集成到 CI/CD,无需手动触发                   ║
║  5️⃣ 分层测试 — 微基准→组件→集成→生产,逐层验证              ║
║  6️⃣ 持续改进 — 基线不是固定的,随业务发展而演进             ║
║                                                           ║
╚═══════════════════════════════════════════════════════════╝

7.2 如何参与?

  • 📊 贡献基准测试用例:帮我们完善各模块的性能测试覆盖
  • 🐛 报告性能问题:在 GitHub Issue 中标注 [perf] 前缀
  • 🔧 优化贡献:提交性能优化的 PR 并附带基准测试对比
  • 💬 参与 讨论:在 GitHub Discussions 中交流性能调优经验

现在就访问 MonkeyCode GitHub,查看我们的性能基准数据,提出你的优化建议吧!


本文最后更新于 2026 年 7 月 1 日。性能是一个持续优化的过程,请关注我们的性能报告获取最新数据。

相关文章推荐:


© 2026 MonkeyCode Open Source Project. Licensed under Apache License 2.0.

posted on 2026-07-01 12:52  MonkeyCode  阅读(36)  评论(0)    收藏  举报