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

25 KiB
Raw Permalink Blame History

性能持续优化实施计划

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