lolly/internal/server/middleware_bench_test.go
xfy fd4e164ae6 refactor(security): 滑动窗口限流器使用分段锁优化并发性能
将单一 counters map + 全局 mutex 改为 16 buckets 分段锁结构:

- 新增 limiterBucket 结构体,每个桶独立持有 RW 锁和计数器 map
- 使用 FNV-1a 哈希算法将键均匀分布到 16 个桶中
- 各方法修改为按 bucket 分发操作:
  - Allow() / allowApproximate() / allowPrecise()
  - Reset() / ResetAll() / Cleanup()
  - GetStats() / GetCount()

收益:
- 并发场景下锁竞争降低约 94% (16 个桶并行)
- 基准测试显示并行 Allow 操作约 89ns/op

测试验证:
- go test -race 通过并发安全测试
- 基准测试显示吞吐提升

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-14 14:26:01 +08:00

176 lines
4.4 KiB
Go
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.

// Package server 提供中间件性能基准测试
//
// 该文件测试中间件链模块的性能,包括:
// - 创建中间件链的开销
// - Process 包装的开销
// - 完整链执行的开销
//
// 用于评估中间件链在不同场景下的性能表现
package server
import (
"testing"
"github.com/valyala/fasthttp"
"rua.plus/lolly/internal/middleware"
)
// noopMiddleware 是一个空的中间件实现,用于基准测试
// 只记录进入和退出,不做任何实际操作
type noopMiddleware struct {
name string
}
// Name 返回中间件名称
func (m *noopMiddleware) Name() string {
return m.name
}
// Process 包装下一个请求处理器
// 直接调用下一个处理器,不做任何处理
func (m *noopMiddleware) Process(next fasthttp.RequestHandler) fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) {
next(ctx)
}
}
// BenchmarkMiddlewareNewChainApply 测试创建中间件链和应用的开销
//
// 该基准测试测量:
// - 使用 NewChain() 创建链的开销
// - 使用 Apply() 应用中间件链到最终处理器的开销
//
// 测试场景:包含 3 个中间件的链
func BenchmarkMiddlewareNewChainApply(b *testing.B) {
// 创建 3 个空中间件
mw1 := &noopMiddleware{name: "mw1"}
mw2 := &noopMiddleware{name: "mw2"}
mw3 := &noopMiddleware{name: "mw3"}
// 最终处理器
finalHandler := func(ctx *fasthttp.RequestCtx) {
ctx.WriteString("ok")
}
b.ResetTimer()
for b.Loop() {
// 创建链并应用
chain := middleware.NewChain(mw1, mw2, mw3)
_ = chain.Apply(finalHandler)
}
}
// BenchmarkMiddlewareProcessChain 测试 Process 包装的开销
//
// 该基准测试测量单个中间件 Process 方法包装处理器的开销
// 关注单个中间件的包装性能,不涉及链的创建
func BenchmarkMiddlewareProcessChain(b *testing.B) {
mw := &noopMiddleware{name: "benchmark"}
// 最终处理器
finalHandler := func(ctx *fasthttp.RequestCtx) {
ctx.WriteString("ok")
}
b.ResetTimer()
for b.Loop() {
// 只测量 Process 包装的开销
_ = mw.Process(finalHandler)
}
}
// BenchmarkMiddlewareChainExecution 测试完整中间件链的执行开销
//
// 该基准测试测量:
// - 预创建的中间件链的执行性能
// - 多中间件嵌套调用的开销
// - 空 handler 情况下的链遍历成本
//
// 测试场景3 个中间件的完整链执行
func BenchmarkMiddlewareChainExecution(b *testing.B) {
// 创建 3 个空中间件
mw1 := &noopMiddleware{name: "mw1"}
mw2 := &noopMiddleware{name: "mw2"}
mw3 := &noopMiddleware{name: "mw3"}
// 创建链并应用
chain := middleware.NewChain(mw1, mw2, mw3)
// 最终处理器(空操作)
finalHandler := func(ctx *fasthttp.RequestCtx) {
// 空 handler不做任何操作
}
handler := chain.Apply(finalHandler)
ctx := &fasthttp.RequestCtx{}
b.ResetTimer()
for b.Loop() {
// 执行完整的中间件链
handler(ctx)
}
}
// BenchmarkMiddlewareChainExecutionWithResponse 测试带响应的完整链执行
//
// 与 BenchmarkMiddlewareChainExecution 类似,但包含实际的响应写入操作
// 更接近实际使用场景
func BenchmarkMiddlewareChainExecutionWithResponse(b *testing.B) {
mw1 := &noopMiddleware{name: "mw1"}
mw2 := &noopMiddleware{name: "mw2"}
mw3 := &noopMiddleware{name: "mw3"}
chain := middleware.NewChain(mw1, mw2, mw3)
finalHandler := func(ctx *fasthttp.RequestCtx) {
ctx.WriteString("response")
}
handler := chain.Apply(finalHandler)
b.ResetTimer()
for b.Loop() {
ctx := &fasthttp.RequestCtx{}
handler(ctx)
}
}
// BenchmarkMiddlewareEmptyChain 测试空中间件链的性能
//
// 作为对照组,测量没有任何中间件时的基础开销
func BenchmarkMiddlewareEmptyChain(b *testing.B) {
chain := middleware.NewChain()
finalHandler := func(ctx *fasthttp.RequestCtx) {
ctx.WriteString("ok")
}
handler := chain.Apply(finalHandler)
ctx := &fasthttp.RequestCtx{}
b.ResetTimer()
for b.Loop() {
handler(ctx)
}
}
// BenchmarkMiddlewareSingleMiddleware 测试单个中间件的开销
//
// 测量只有一个中间件时的性能,用于对比多中间件场景
func BenchmarkMiddlewareSingleMiddleware(b *testing.B) {
mw := &noopMiddleware{name: "single"}
chain := middleware.NewChain(mw)
finalHandler := func(ctx *fasthttp.RequestCtx) {
ctx.WriteString("ok")
}
handler := chain.Apply(finalHandler)
ctx := &fasthttp.RequestCtx{}
b.ResetTimer()
for b.Loop() {
handler(ctx)
}
}