- Collect baseline benchmark summary across all core modules - Save key results to benchmarks/v0.4.0/summary.txt - Update .gitignore to track benchmark summaries/reports - Include performance optimization design docs and plan
25 KiB
性能持续优化实施计划
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: 建立完整的性能基准测试体系,收集 baseline 数据,识别 Top 10 瓶颈,实施可量化的性能优化
Architecture: 数据驱动优化流程:建立基准 → 采集数据 → 分析瓶颈 → 实施优化 → 回归检测。先补齐缺失的 benchmark,再跑全量基准生成 baseline,然后用 pprof 定位瓶颈,最后逐个优化验证
Tech Stack: Go 1.26+, testing/benchmark, pprof, benchstat, wrk/oha/h2load
文件结构映射
internal/benchmark/
├── micro/ # 微基准测试
│ ├── resolver_bench_test.go # DNS 解析器基准
│ ├── stream_bench_test.go # Stream 代理基准
│ ├── cache_bench_test.go # 缓存系统基准
│ ├── lua_bench_test.go # Lua 引擎基准
│ └── variable_bench_test.go # 变量系统基准
├── integration/ # 集成基准测试
│ ├── server_bench_test.go # HTTP 服务器端到端
│ ├── proxy_bench_test.go # 反向代理端到端
│ └── static_bench_test.go # 静态文件端到端
└── system/ # 系统压测脚本
├── bench.sh # 主压测脚本
├── static.lua # wrk 静态文件压测脚本
└── proxy.lua # wrk 代理压测脚本
scripts/
└── bench-suite.sh # 一键运行全量基准
benchmarks/ # 基准结果存储
└── v0.4.0/ # 版本号目录
├── micro.txt
├── integration.txt
├── system.txt
└── pprof/
├── cpu.prof
├── heap.prof
├── allocs.prof
└── goroutine.prof
Task 1: 建立 Benchmark 目录结构
Files:
-
Create:
internal/benchmark/micro/ -
Create:
internal/benchmark/integration/ -
Create:
internal/benchmark/system/ -
Create:
benchmarks/ -
Modify:
.gitignore(忽略 benchmarks/ 但保留目录) -
Step 1: 创建目录结构
mkdir -p internal/benchmark/micro
mkdir -p internal/benchmark/integration
mkdir -p internal/benchmark/system
mkdir -p benchmarks/v0.4.0/pprof
- Step 2: 添加 .gitignore 规则
在 .gitignore 末尾添加:
# Benchmark results
benchmarks/*/
!benchmarks/.gitkeep
创建 benchmarks/.gitkeep:
touch benchmarks/.gitkeep
- Step 3: Commit
git add internal/benchmark/ benchmarks/ .gitignore
git commit -m "chore(benchmark): establish benchmark directory structure"
Task 2: 补充缺失的微基准 — Resolver
Files:
-
Create:
internal/benchmark/micro/resolver_bench_test.go -
Step 1: 编写 resolver 基准测试
package micro
import (
"testing"
"time"
"rua.plus/lolly/internal/resolver"
)
func BenchmarkResolverLookup(b *testing.B) {
// 使用 mock resolver 避免真实网络请求
r := resolver.NewMockResolver(map[string][]string{
"example.com": {"93.184.216.34"},
})
b.ReportAllocs()
b.ResetTimer()
for b.Loop() {
_, _ = r.Lookup("example.com")
}
}
func BenchmarkResolverLookupWithCache(b *testing.B) {
r := resolver.NewMockResolver(map[string][]string{
"example.com": {"93.184.216.34"},
})
// 预热缓存
_, _ = r.Lookup("example.com")
b.ReportAllocs()
b.ResetTimer()
for b.Loop() {
_, _ = r.Lookup("example.com")
}
}
func BenchmarkResolverCacheSet(b *testing.B) {
r := resolver.NewMockResolver(nil)
b.ReportAllocs()
b.ResetTimer()
for b.Loop() {
r.CacheSet("host"+string(rune(b.N)), []string{"1.2.3.4"}, time.Minute)
}
}
func BenchmarkResolverCacheGet(b *testing.B) {
r := resolver.NewMockResolver(nil)
r.CacheSet("example.com", []string{"1.2.3.4"}, time.Minute)
b.ReportAllocs()
b.ResetTimer()
for b.Loop() {
_, _ = r.CacheGet("example.com")
}
}
- Step 2: 运行测试验证
go test -bench=. -benchmem ./internal/benchmark/micro/resolver_bench_test.go
Expected: 4 个 benchmark 全部运行,无编译错误
- Step 3: Commit
git add internal/benchmark/micro/resolver_bench_test.go
git commit -m "feat(benchmark): add resolver micro benchmarks"
Task 3: 补充缺失的微基准 — Stream
Files:
-
Create:
internal/benchmark/micro/stream_bench_test.go -
Step 1: 编写 stream 基准测试
package micro
import (
"io"
"net"
"testing"
"github.com/stretchr/testify/require"
"rua.plus/lolly/internal/stream"
)
func BenchmarkStreamTCPForward(b *testing.B) {
// 创建后端 echo 服务器
backendLn, err := net.Listen("tcp", "127.0.0.1:0")
require.NoError(b, err)
defer backendLn.Close()
go func() {
for {
conn, err := backendLn.Accept()
if err != nil {
return
}
go func(c net.Conn) {
defer c.Close()
_, _ = io.Copy(c, c)
}(conn)
}
}()
// 创建 stream server
srv := stream.NewServer()
_ = srv.AddUpstream("test", []stream.TargetSpec{
{Addr: backendLn.Addr().String(), Weight: 1},
}, "round_robin", stream.HealthCheckSpec{})
// 设置 upstream 健康
srv.SetHealthy("test", 0, true)
_ = srv.ListenTCP("127.0.0.1:0")
_ = srv.Start()
defer srv.Stop()
proxyAddr := srv.GetListenerAddr("test")
b.ReportAllocs()
b.ResetTimer()
for b.Loop() {
conn, err := net.Dial("tcp", proxyAddr)
if err != nil {
b.Fatal(err)
}
_, _ = conn.Write([]byte("hello"))
buf := make([]byte, 5)
_, _ = io.ReadFull(conn, buf)
conn.Close()
}
}
func BenchmarkStreamSelectTarget(b *testing.B) {
srv := stream.NewServer()
_ = srv.AddUpstream("test", []stream.TargetSpec{
{Addr: "127.0.0.1:8001", Weight: 3},
{Addr: "127.0.0.1:8002", Weight: 2},
{Addr: "127.0.0.1:8003", Weight: 1},
}, "weighted_round_robin", stream.HealthCheckSpec{})
for i := 0; i < 3; i++ {
srv.SetHealthy("test", i, true)
}
b.ReportAllocs()
b.ResetTimer()
for b.Loop() {
_, _ = srv.SelectTarget("test", nil)
}
}
- Step 2: 运行测试验证
go test -bench=. -benchmem ./internal/benchmark/micro/stream_bench_test.go
Expected: 2 个 benchmark 全部运行
- Step 3: Commit
git add internal/benchmark/micro/stream_bench_test.go
git commit -m "feat(benchmark): add stream proxy micro benchmarks"
Task 4: 补充缺失的微基准 — Cache
Files:
-
Create:
internal/benchmark/micro/cache_bench_test.go -
Step 1: 编写 cache 基准测试
package micro
import (
"testing"
"time"
"rua.plus/lolly/internal/cache"
)
func BenchmarkCacheGet(b *testing.B) {
c := cache.New(cache.Config{MaxEntries: 10000})
_ = c.Set("key", []byte("value"), time.Hour)
b.ReportAllocs()
b.ResetTimer()
for b.Loop() {
_, _ = c.Get("key")
}
}
func BenchmarkCacheSet(b *testing.B) {
c := cache.New(cache.Config{MaxEntries: 10000})
value := []byte("value")
b.ReportAllocs()
b.ResetTimer()
for b.Loop() {
_ = c.Set("key"+string(rune(b.N)), value, time.Hour)
}
}
func BenchmarkCacheGetConcurrent(b *testing.B) {
c := cache.New(cache.Config{MaxEntries: 10000})
for i := 0; i < 1000; i++ {
_ = c.Set(string(rune(i)), []byte("value"), time.Hour)
}
b.ReportAllocs()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
i := 0
for pb.Next() {
_, _ = c.Get(string(rune(i % 1000)))
i++
}
})
}
func BenchmarkCacheSetConcurrent(b *testing.B) {
c := cache.New(cache.Config{MaxEntries: 10000})
value := []byte("value")
b.ReportAllocs()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
i := 0
for pb.Next() {
_ = c.Set(string(rune(i)), value, time.Hour)
i++
}
})
}
- Step 2: 运行测试验证
go test -bench=. -benchmem ./internal/benchmark/micro/cache_bench_test.go
- Step 3: Commit
git add internal/benchmark/micro/cache_bench_test.go
git commit -m "feat(benchmark): add cache micro benchmarks"
Task 5: 补充缺失的微基准 — Lua
Files:
-
Create:
internal/benchmark/micro/lua_bench_test.go -
Step 1: 编写 Lua 基准测试
package micro
import (
"testing"
"rua.plus/lolly/internal/lua"
)
func BenchmarkLuaSimpleScript(b *testing.B) {
engine := lua.NewEngine()
defer engine.Close()
script := `
local a = 1 + 2
return a
`
b.ReportAllocs()
b.ResetTimer()
for b.Loop() {
_ = engine.ExecuteString(script)
}
}
func BenchmarkLuaNginxAPI(b *testing.B) {
engine := lua.NewEngine()
defer engine.Close()
script := `
ngx.var.request_uri = "/test"
return ngx.var.request_uri
`
b.ReportAllocs()
b.ResetTimer()
for b.Loop() {
_ = engine.ExecuteString(script)
}
}
func BenchmarkLuaJSONEncode(b *testing.B) {
engine := lua.NewEngine()
defer engine.Close()
script := `
local json = require("cjson")
local t = {name = "test", value = 123}
return json.encode(t)
`
b.ReportAllocs()
b.ResetTimer()
for b.Loop() {
_ = engine.ExecuteString(script)
}
}
- Step 2: 运行测试验证
go test -bench=. -benchmem ./internal/benchmark/micro/lua_bench_test.go
- Step 3: Commit
git add internal/benchmark/micro/lua_bench_test.go
git commit -m "feat(benchmark): add lua engine micro benchmarks"
Task 6: 创建集成基准测试 — Server
Files:
-
Create:
internal/benchmark/integration/server_bench_test.go -
Step 1: 编写服务器集成基准
package integration
import (
"fmt"
"testing"
"github.com/valyala/fasthttp"
"rua.plus/lolly/internal/config"
"rua.plus/lolly/internal/server"
)
func BenchmarkServerStaticRequest(b *testing.B) {
cfg := &config.Config{
Servers: []config.ServerConfig{{
Listen: "127.0.0.1:0",
Static: []config.StaticConfig{{
Path: "/",
Root: "./testdata",
}},
}},
}
srv := server.New(cfg)
go srv.Start()
defer srv.Stop()
// 等待服务器启动
addr := srv.GetAddr()
client := &fasthttp.Client{}
req := fasthttp.AcquireRequest()
resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseRequest(req)
defer fasthttp.ReleaseResponse(resp)
req.SetRequestURI("http://" + addr + "/")
req.Header.SetMethod("GET")
b.ReportAllocs()
b.ResetTimer()
for b.Loop() {
_ = client.Do(req, resp)
}
}
func BenchmarkServerProxyRequest(b *testing.B) {
// 启动后端服务器
backend := &fasthttp.Server{
Handler: func(ctx *fasthttp.RequestCtx) {
ctx.SetBodyString("ok")
},
}
go backend.ListenAndServe("127.0.0.1:18081")
cfg := &config.Config{
Servers: []config.ServerConfig{{
Listen: "127.0.0.1:0",
Proxy: []config.ProxyConfig{{
Path: "/api",
Targets: []config.ProxyTarget{{
URL: "http://127.0.0.1:18081",
}},
}},
}},
}
srv := server.New(cfg)
go srv.Start()
defer srv.Stop()
addr := srv.GetAddr()
client := &fasthttp.Client{}
req := fasthttp.AcquireRequest()
resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseRequest(req)
defer fasthttp.ReleaseResponse(resp)
req.SetRequestURI("http://" + addr + "/api/test")
req.Header.SetMethod("GET")
b.ReportAllocs()
b.ResetTimer()
for b.Loop() {
_ = client.Do(req, resp)
}
}
- Step 2: 运行测试验证
go test -bench=. -benchmem ./internal/benchmark/integration/server_bench_test.go
- Step 3: Commit
git add internal/benchmark/integration/server_bench_test.go
git commit -m "feat(benchmark): add server integration benchmarks"
Task 7: 创建系统压测脚本
Files:
-
Create:
internal/benchmark/system/bench.sh -
Create:
internal/benchmark/system/static.lua -
Create:
internal/benchmark/system/proxy.lua -
Step 1: 编写 wrk 压测脚本 — 静态文件
internal/benchmark/system/static.lua:
-- wrk static file benchmark script
wrk.method = "GET"
wrk.headers["Accept"] = "text/html"
-- 随机访问不同路径增加真实感
math.randomseed(os.time())
request = function()
local paths = {"/", "/index.html", "/about.html", "/contact.html"}
local path = paths[math.random(#paths)]
return wrk.format(nil, path)
end
response = function(status, headers, body)
if status ~= 200 then
print("Error: " .. status)
end
end
- Step 2: 编写 wrk 压测脚本 — 代理
internal/benchmark/system/proxy.lua:
-- wrk proxy benchmark script
wrk.method = "GET"
wrk.headers["Accept"] = "application/json"
request = function()
local paths = {"/api/users", "/api/posts", "/api/comments"}
local path = paths[math.random(#paths)]
return wrk.format(nil, path)
end
- Step 3: 编写主压测脚本
internal/benchmark/system/bench.sh:
#!/bin/bash
set -e
# Lolly System Benchmark Suite
# Usage: ./bench.sh [lolly_addr] [duration]
ADDR=${1:-"http://127.0.0.1:8080"}
DURATION=${2:-"30s"}
CONNECTIONS=${3:-400}
THREADS=${4:-12}
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
RESULTS_DIR="${SCRIPT_DIR}/../../../benchmarks/$(date +%Y%m%d-%H%M%S)"
mkdir -p "$RESULTS_DIR"
echo "=== Lolly System Benchmark ==="
echo "Target: $ADDR"
echo "Duration: $DURATION"
echo "Connections: $CONNECTIONS"
echo "Threads: $THREADS"
echo "Results: $RESULTS_DIR"
echo ""
# Check tools
check_tool() {
if ! command -v "$1" &> /dev/null; then
echo "Warning: $1 not found, skipping related tests"
return 1
fi
return 0
}
# 1. Static file benchmark
echo "--- Static File Benchmark ---"
if check_tool wrk; then
wrk -t$THREADS -c$CONNECTIONS -d$DURATION \
-s "$SCRIPT_DIR/static.lua" \
"$ADDR" > "$RESULTS_DIR/static.txt"
echo "Static: $(grep 'Requests/sec' "$RESULTS_DIR/static.txt" || echo 'N/A')"
fi
# 2. Proxy benchmark
echo ""
echo "--- Proxy Benchmark ---"
if check_tool wrk; then
wrk -t$THREADS -c$CONNECTIONS -d$DURATION \
-s "$SCRIPT_DIR/proxy.lua" \
"$ADDR/api" > "$RESULTS_DIR/proxy.txt"
echo "Proxy: $(grep 'Requests/sec' "$RESULTS_DIR/proxy.txt" || echo 'N/A')"
fi
# 3. HTTP/2 benchmark
echo ""
echo "--- HTTP/2 Benchmark ---"
if check_tool h2load; then
h2load -n100000 -c100 -m10 "$ADDR" > "$RESULTS_DIR/http2.txt" 2>&1 || true
echo "HTTP/2: $(grep 'finished' "$RESULTS_DIR/http2.txt" || echo 'N/A')"
fi
# 4. Latency distribution with oha
echo ""
echo "--- Latency Distribution ---"
if check_tool oha; then
oha -z $DURATION -c $CONNECTIONS "$ADDR" > "$RESULTS_DIR/latency.txt"
echo "Latency: $(grep 'Success rate' "$RESULTS_DIR/latency.txt" || echo 'N/A')"
fi
echo ""
echo "=== Results saved to $RESULTS_DIR ==="
- Step 4: 添加执行权限
chmod +x internal/benchmark/system/bench.sh
- Step 5: Commit
git add internal/benchmark/system/
git commit -m "feat(benchmark): add system benchmark scripts"
Task 8: 创建一键全量基准脚本
Files:
-
Create:
scripts/bench-suite.sh -
Modify:
Makefile -
Step 1: 编写一键基准脚本
scripts/bench-suite.sh:
#!/bin/bash
set -e
# Run complete benchmark suite and save results
VERSION=$(git describe --tags --always --dirty 2>/dev/null || echo "dev")
RESULTS_DIR="benchmarks/$VERSION"
mkdir -p "$RESULTS_DIR/pprof"
echo "=== Lolly Benchmark Suite v$VERSION ==="
echo "Results: $RESULTS_DIR"
echo ""
# 1. Micro benchmarks
echo "--- Running Micro Benchmarks ---"
go test -bench=. -benchmem \
./internal/benchmark/micro/... \
> "$RESULTS_DIR/micro.txt" 2>&1 || true
echo "Micro benchmarks done"
# 2. Integration benchmarks
echo ""
echo "--- Running Integration Benchmarks ---"
go test -bench=. -benchmem \
./internal/benchmark/integration/... \
> "$RESULTS_DIR/integration.txt" 2>&1 || true
echo "Integration benchmarks done"
# 3. Existing package benchmarks
echo ""
echo "--- Running Package Benchmarks ---"
go test -bench=. -benchmem \
./internal/loadbalance/... \
./internal/matcher/... \
./internal/proxy/... \
./internal/middleware/... \
> "$RESULTS_DIR/packages.txt" 2>&1 || true
echo "Package benchmarks done"
# 4. Summary
echo ""
echo "=== Results Summary ==="
echo "Micro: $RESULTS_DIR/micro.txt"
echo "Integration: $RESULTS_DIR/integration.txt"
echo "Packages: $RESULTS_DIR/packages.txt"
if command -v benchstat &> /dev/null; then
echo ""
echo "--- Top Results ---"
grep -h "Benchmark" "$RESULTS_DIR"/*.txt | head -20
fi
echo ""
echo "All results saved to $RESULTS_DIR"
- Step 2: 添加 Makefile 目标
在 Makefile 中添加:
.PHONY: bench bench-stat bench-suite
# Run all benchmarks
bench:
go test -bench=. -benchmem ./internal/benchmark/micro/... ./internal/benchmark/integration/...
# Run benchmarks and show statistics
bench-stat: bench
@benchstat $(shell ls benchmarks/*/micro.txt 2>/dev/null | tail -1)
# Run complete benchmark suite
bench-suite:
@bash scripts/bench-suite.sh
# Run system benchmarks (requires running server)
bench-system:
@bash internal/benchmark/system/bench.sh
- Step 3: 添加执行权限
chmod +x scripts/bench-suite.sh
- Step 4: 运行测试
make bench-suite
Expected: 脚本运行成功,结果保存到 benchmarks/dev/ 目录
- Step 5: Commit
git add scripts/bench-suite.sh Makefile
git commit -m "feat(benchmark): add one-click benchmark suite"
Task 9: 运行第一轮全量基准 → 生成 Baseline
Files:
-
Create:
benchmarks/v0.4.0/*.txt -
Step 1: 运行微基准
go test -bench=. -benchmem \
./internal/benchmark/micro/... \
> benchmarks/v0.4.0/micro.txt
- Step 2: 运行已有包的基准
go test -bench=. -benchmem \
./internal/loadbalance/... \
./internal/matcher/... \
./internal/proxy/... \
./internal/middleware/... \
./internal/server/... \
./internal/cache/... \
./internal/stream/... \
./internal/resolver/... \
./internal/variable/... \
./internal/lua/... \
> benchmarks/v0.4.0/packages.txt
- Step 3: 格式化基准结果
# 如果安装了 benchstat
benchstat benchmarks/v0.4.0/micro.txt
benchstat benchmarks/v0.4.0/packages.txt
- Step 4: Commit baseline
git add benchmarks/v0.4.0/
git commit -m "chore(benchmark): add v0.4.0 baseline performance data"
Task 10: 采集 pprof 数据
Files:
- Create:
benchmarks/v0.4.0/pprof/*.prof
前置条件: 需要启动一个配置了 pprof 的 lolly 服务器
- Step 1: 启动带 pprof 的测试服务器
创建临时测试配置 benchmark-pprof.yaml:
servers:
- listen: ":8080"
static:
- path: "/"
root: "./testdata"
proxy:
- path: "/api"
targets:
- url: "http://127.0.0.1:18081"
monitoring:
pprof:
enabled: true
path: "/debug/pprof"
allow:
- "127.0.0.1"
启动后端 mock 服务器(可以用 Python/Node 快速启动一个 echo 服务)
启动 lolly:
./bin/lolly -c benchmark-pprof.yaml &
LOLLY_PID=$!
- Step 2: 采集 CPU profile
curl -s "http://localhost:8080/debug/pprof/profile?seconds=30" \
> benchmarks/v0.4.0/pprof/cpu.prof
- Step 3: 采集 Heap profile
curl -s "http://localhost:8080/debug/pprof/heap" \
> benchmarks/v0.4.0/pprof/heap.prof
- Step 4: 采集 Allocs profile
curl -s "http://localhost:8080/debug/pprof/allocs" \
> benchmarks/v0.4.0/pprof/allocs.prof
- Step 5: 采集 Goroutine profile
curl -s "http://localhost:8080/debug/pprof/goroutine" \
> benchmarks/v0.4.0/pprof/goroutine.prof
- Step 6: 停止测试服务器
kill $LOLLY_PID
rm benchmark-pprof.yaml
- Step 7: Commit pprof 数据
git add benchmarks/v0.4.0/pprof/
git commit -m "chore(benchmark): add v0.4.0 pprof profiles"
Task 11: 分析瓶颈 → 生成性能报告
Files:
-
Create:
benchmarks/v0.4.0/REPORT.md -
Step 1: 分析 CPU profile
go tool pprof -top benchmarks/v0.4.0/pprof/cpu.prof > benchmarks/v0.4.0/cpu-top.txt
查看 Top 20 CPU 消耗函数:
go tool pprof -top -n 20 benchmarks/v0.4.0/pprof/cpu.prof
- Step 2: 分析 Heap profile
go tool pprof -top benchmarks/v0.4.0/pprof/heap.prof > benchmarks/v0.4.0/heap-top.txt
- Step 3: 分析 Allocs profile
go tool pprof -top benchmarks/v0.4.0/pprof/allocs.prof > benchmarks/v0.4.0/allocs-top.txt
- Step 4: 汇总生成报告
benchmarks/v0.4.0/REPORT.md:
# Lolly v0.4.0 性能分析报告
> 生成日期: $(date)
## 1. 基准测试摘要
### 微基准
[粘贴 micro.txt 关键结果]
### 包基准
[粘贴 packages.txt 关键结果]
## 2. CPU 热点 Top 10
[粘贴 cpu-top.txt 结果]
## 3. 内存分配热点 Top 10
[粘贴 allocs-top.txt 结果]
## 4. 内存占用 Top 10
[粘贴 heap-top.txt 结果]
## 5. 优化建议
### P0 (高优先级)
- [ ] [根据分析结果填写]
### P1 (中优先级)
- [ ] [根据分析结果填写]
### P2 (低优先级)
- [ ] [根据分析结果填写]
- Step 5: Commit 报告
git add benchmarks/v0.4.0/REPORT.md benchmarks/v0.4.0/*-top.txt
git commit -m "docs(benchmark): add v0.4.0 performance analysis report"
Task 12: 实施优化(基于报告)
注意: 此 Task 的内容将在 Task 11 完成后根据实际瓶颈数据制定。以下为占位模板,实际实施时需替换为具体分析结果。
Task 12.1: 优化 [瓶颈1]
Files:
-
Modify:
internal/[package]/[file].go:[line-range] -
Step 1: 编写优化前 benchmark
# 已有 baseline,无需重复
- Step 2: 实施优化
[根据实际瓶颈实施具体优化]
- Step 3: 验证优化效果
go test -bench=[BenchmarkName] -benchmem ./internal/[package]/...
benchstat benchmarks/v0.4.0/old.txt benchmarks/v0.4.0/new.txt
Expected: 性能提升 > 5%
- Step 4: Commit
git add internal/[package]/
git commit -m "perf([package]): optimize [description]"
Task 12.2-12.N: 重复优化流程
对每个识别的瓶颈重复上述流程。
Task 13: 建立性能回归检测
Files:
-
Create:
.github/workflows/benchmark.yml(如果恢复 CI) -
Create:
scripts/bench-compare.sh -
Modify:
Makefile -
Step 1: 创建基准对比脚本
scripts/bench-compare.sh:
#!/bin/bash
set -e
# Compare current benchmark against baseline
# Usage: ./bench-compare.sh [baseline_version]
BASELINE=${1:-"v0.4.0"}
BASELINE_FILE="benchmarks/$BASELINE/packages.txt"
CURRENT_FILE="benchmarks/current.txt"
if [ ! -f "$BASELINE_FILE" ]; then
echo "Baseline not found: $BASELINE_FILE"
exit 1
fi
echo "Comparing against baseline: $BASELINE"
# Run current benchmarks
go test -bench=. -benchmem \
./internal/loadbalance/... \
./internal/matcher/... \
./internal/proxy/... \
./internal/middleware/... \
> "$CURRENT_FILE"
# Compare
if command -v benchstat &> /dev/null; then
benchstat "$BASELINE_FILE" "$CURRENT_FILE"
else
echo "benchstat not found, install with: go install golang.org/x/perf/cmd/benchstat@latest"
exit 1
fi
- Step 2: 添加 Makefile 目标
.PHONY: bench-compare
# Compare current performance against baseline
bench-compare:
@bash scripts/bench-compare.sh
- Step 3: 添加执行权限
chmod +x scripts/bench-compare.sh
- Step 4: 测试回归检测
make bench-compare
Expected: 显示当前性能与 baseline 的对比,无显著退化
- Step 5: Commit
git add scripts/bench-compare.sh Makefile
git commit -m "feat(benchmark): add performance regression detection"
Task 14: 最终验证
- Step 1: 全量测试通过
make test
Expected: 全部 PASS
- Step 2: Race 检测通过
go test -race ./internal/...
Expected: 零 race
- Step 3: Lint 通过
make lint
Expected: 零 issues
- Step 4: 构建验证
make build
Expected: 构建成功
- Step 5: 最终 Commit
git log --oneline -20
确认所有 benchmark 相关 commit 都在。
附录:常用命令速查
# 运行所有微基准
go test -bench=. -benchmem ./internal/benchmark/micro/...
# 运行单个基准
go test -bench=BenchmarkCacheGet -benchmem ./internal/benchmark/micro/...
# 对比两个基准结果
benchstat old.txt new.txt
# 查看 CPU profile
go tool pprof -http=:8081 benchmarks/v0.4.0/pprof/cpu.prof
# 查看内存分配
go tool pprof -http=:8081 benchmarks/v0.4.0/pprof/allocs.prof
# 生成火焰图
go tool pprof -png benchmarks/v0.4.0/pprof/cpu.prof > cpu-flamegraph.png
# 系统压测
make bench-system
# 性能回归检测
make bench-compare
Spec Coverage Check
| Spec Section | Task |
|---|---|
| 建立 benchmark 目录结构 | Task 1 |
| 补充 resolver 微基准 | Task 2 |
| 补充 stream 微基准 | Task 3 |
| 补充 cache 微基准 | Task 4 |
| 补充 lua 微基准 | Task 5 |
| 集成基准测试 | Task 6 |
| 系统压测脚本 | Task 7 |
| 一键基准脚本 | Task 8 |
| 生成 baseline | Task 9 |
| 采集 pprof | Task 10 |
| 分析报告 | Task 11 |
| 实施优化 | Task 12 |
| 回归检测 | Task 13 |
| 最终验证 | Task 14 |