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.
浙公网安备 33010602011771号