lolly/docs/superpowers/plans/2026-06-10-performance-optimization-plan.md
xfy ebeb258c58 docs(benchmark): add v0.4.0 baseline summary and update gitignore
- 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
2026-06-11 13:43:28 +08:00

1236 lines
25 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 性能持续优化实施计划
> **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: 创建目录结构**
```bash
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`
```bash
touch benchmarks/.gitkeep
```
- [ ] **Step 3: Commit**
```bash
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 基准测试**
```go
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: 运行测试验证**
```bash
go test -bench=. -benchmem ./internal/benchmark/micro/resolver_bench_test.go
```
Expected: 4 个 benchmark 全部运行,无编译错误
- [ ] **Step 3: Commit**
```bash
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 基准测试**
```go
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: 运行测试验证**
```bash
go test -bench=. -benchmem ./internal/benchmark/micro/stream_bench_test.go
```
Expected: 2 个 benchmark 全部运行
- [ ] **Step 3: Commit**
```bash
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 基准测试**
```go
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: 运行测试验证**
```bash
go test -bench=. -benchmem ./internal/benchmark/micro/cache_bench_test.go
```
- [ ] **Step 3: Commit**
```bash
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 基准测试**
```go
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: 运行测试验证**
```bash
go test -bench=. -benchmem ./internal/benchmark/micro/lua_bench_test.go
```
- [ ] **Step 3: Commit**
```bash
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: 编写服务器集成基准**
```go
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: 运行测试验证**
```bash
go test -bench=. -benchmem ./internal/benchmark/integration/server_bench_test.go
```
- [ ] **Step 3: Commit**
```bash
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`:
```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`:
```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`:
```bash
#!/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: 添加执行权限**
```bash
chmod +x internal/benchmark/system/bench.sh
```
- [ ] **Step 5: Commit**
```bash
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`:
```bash
#!/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` 中添加:
```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: 添加执行权限**
```bash
chmod +x scripts/bench-suite.sh
```
- [ ] **Step 4: 运行测试**
```bash
make bench-suite
```
Expected: 脚本运行成功,结果保存到 `benchmarks/dev/` 目录
- [ ] **Step 5: Commit**
```bash
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: 运行微基准**
```bash
go test -bench=. -benchmem \
./internal/benchmark/micro/... \
> benchmarks/v0.4.0/micro.txt
```
- [ ] **Step 2: 运行已有包的基准**
```bash
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: 格式化基准结果**
```bash
# 如果安装了 benchstat
benchstat benchmarks/v0.4.0/micro.txt
benchstat benchmarks/v0.4.0/packages.txt
```
- [ ] **Step 4: Commit baseline**
```bash
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`:
```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:
```bash
./bin/lolly -c benchmark-pprof.yaml &
LOLLY_PID=$!
```
- [ ] **Step 2: 采集 CPU profile**
```bash
curl -s "http://localhost:8080/debug/pprof/profile?seconds=30" \
> benchmarks/v0.4.0/pprof/cpu.prof
```
- [ ] **Step 3: 采集 Heap profile**
```bash
curl -s "http://localhost:8080/debug/pprof/heap" \
> benchmarks/v0.4.0/pprof/heap.prof
```
- [ ] **Step 4: 采集 Allocs profile**
```bash
curl -s "http://localhost:8080/debug/pprof/allocs" \
> benchmarks/v0.4.0/pprof/allocs.prof
```
- [ ] **Step 5: 采集 Goroutine profile**
```bash
curl -s "http://localhost:8080/debug/pprof/goroutine" \
> benchmarks/v0.4.0/pprof/goroutine.prof
```
- [ ] **Step 6: 停止测试服务器**
```bash
kill $LOLLY_PID
rm benchmark-pprof.yaml
```
- [ ] **Step 7: Commit pprof 数据**
```bash
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**
```bash
go tool pprof -top benchmarks/v0.4.0/pprof/cpu.prof > benchmarks/v0.4.0/cpu-top.txt
```
查看 Top 20 CPU 消耗函数:
```bash
go tool pprof -top -n 20 benchmarks/v0.4.0/pprof/cpu.prof
```
- [ ] **Step 2: 分析 Heap profile**
```bash
go tool pprof -top benchmarks/v0.4.0/pprof/heap.prof > benchmarks/v0.4.0/heap-top.txt
```
- [ ] **Step 3: 分析 Allocs profile**
```bash
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`:
```markdown
# 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 报告**
```bash
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**
```bash
# 已有 baseline无需重复
```
- [ ] **Step 2: 实施优化**
[根据实际瓶颈实施具体优化]
- [ ] **Step 3: 验证优化效果**
```bash
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**
```bash
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`:
```bash
#!/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 目标**
```makefile
.PHONY: bench-compare
# Compare current performance against baseline
bench-compare:
@bash scripts/bench-compare.sh
```
- [ ] **Step 3: 添加执行权限**
```bash
chmod +x scripts/bench-compare.sh
```
- [ ] **Step 4: 测试回归检测**
```bash
make bench-compare
```
Expected: 显示当前性能与 baseline 的对比,无显著退化
- [ ] **Step 5: Commit**
```bash
git add scripts/bench-compare.sh Makefile
git commit -m "feat(benchmark): add performance regression detection"
```
---
## Task 14: 最终验证
- [ ] **Step 1: 全量测试通过**
```bash
make test
```
Expected: 全部 PASS
- [ ] **Step 2: Race 检测通过**
```bash
go test -race ./internal/...
```
Expected: 零 race
- [ ] **Step 3: Lint 通过**
```bash
make lint
```
Expected: 零 issues
- [ ] **Step 4: 构建验证**
```bash
make build
```
Expected: 构建成功
- [ ] **Step 5: 最终 Commit**
```bash
git log --oneline -20
```
确认所有 benchmark 相关 commit 都在。
---
## 附录:常用命令速查
```bash
# 运行所有微基准
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 |