refactor: remove unused code and fix formatting
- Remove unused benchmark/tools package - Make ValidAlgorithms private (validAlgorithms) in loadbalance - Remove dead code (_ = result) in lua/api_socket_tcp.go - Fix code formatting with goimports Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
ce80352e79
commit
25d93c25fa
2
go.mod
2
go.mod
@ -5,6 +5,7 @@ go 1.26.1
|
|||||||
require (
|
require (
|
||||||
github.com/andybalholm/brotli v1.2.1
|
github.com/andybalholm/brotli v1.2.1
|
||||||
github.com/fasthttp/router v1.5.4
|
github.com/fasthttp/router v1.5.4
|
||||||
|
github.com/goccy/go-json v0.10.4
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/gorilla/websocket v1.5.3
|
github.com/gorilla/websocket v1.5.3
|
||||||
github.com/hashicorp/golang-lru/v2 v2.0.7
|
github.com/hashicorp/golang-lru/v2 v2.0.7
|
||||||
@ -41,7 +42,6 @@ require (
|
|||||||
github.com/go-logr/logr v1.4.3 // indirect
|
github.com/go-logr/logr v1.4.3 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||||
github.com/goccy/go-json v0.10.4 // indirect
|
|
||||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||||
github.com/magiconair/properties v1.8.10 // indirect
|
github.com/magiconair/properties v1.8.10 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||||
|
|||||||
@ -1,42 +0,0 @@
|
|||||||
<!-- Parent: ../AGENTS.md -->
|
|
||||||
<!-- Generated: 2026-04-07 | Updated: 2026-04-07 -->
|
|
||||||
|
|
||||||
# tools
|
|
||||||
|
|
||||||
## Purpose
|
|
||||||
基准测试工具集,提供 Mock 后端服务器、负载生成器和测试数据生成功能,支持各种测试场景(延迟、错误、随机响应)。
|
|
||||||
|
|
||||||
## Key Files
|
|
||||||
|
|
||||||
| File | Description |
|
|
||||||
|------|-------------|
|
|
||||||
| `mock_backend.go` | Mock 后端实现,支持多种响应模式(固定、延迟、错误、随机) |
|
|
||||||
| `loadgen.go` | 负载生成器,收集 QPS、延迟分布(P50/P90/P99)统计 |
|
|
||||||
| `testdata.go` | 测试数据生成,支持多种预定义大小(1KB~10MB) |
|
|
||||||
|
|
||||||
## For AI Agents
|
|
||||||
|
|
||||||
### Working In This Directory
|
|
||||||
- Mock 后端使用 `fasthttputil.InmemoryListener` 进行零网络开销测试
|
|
||||||
- `BackendMode` 支持四种模式:ModeFixed、ModeDelay、ModeError、ModeRandomResponse
|
|
||||||
- 负载生成器支持并发执行和百分位延迟统计
|
|
||||||
- 测试数据使用随机字节填充,适合压缩测试
|
|
||||||
|
|
||||||
### Testing Requirements
|
|
||||||
- 工具本身无独立测试,作为其他模块基准测试的基础设施
|
|
||||||
- 使用示例见 `internal/proxy/proxy_bench_test.go`
|
|
||||||
|
|
||||||
### Common Patterns
|
|
||||||
- 创建简单后端:`SimpleMockBackend(statusCode, body)`
|
|
||||||
- 创建延迟后端:`DelayedMockBackend(delay, body)`
|
|
||||||
- 创建错误后端:`ErrorMockBackend(errorRate, body)`
|
|
||||||
- 创建加权目标:`CreateWeightedTestTargets(n)`
|
|
||||||
- 运行负载测试:`loadGen.Run(n, concurrency)`
|
|
||||||
|
|
||||||
## Dependencies
|
|
||||||
|
|
||||||
### External
|
|
||||||
- `github.com/valyala/fasthttp` - HTTP 框架
|
|
||||||
- `github.com/valyala/fasthttp/fasthttputil` - 内存监听器
|
|
||||||
|
|
||||||
<!-- MANUAL: -->
|
|
||||||
@ -1,359 +0,0 @@
|
|||||||
// Package tools 提供基准测试工具函数。
|
|
||||||
//
|
|
||||||
// 该文件提供标准化的基准测试上下文构造器,用于:
|
|
||||||
// - 快速创建模拟的 fasthttp.RequestCtx
|
|
||||||
// - 标准化测试数据大小
|
|
||||||
// - 简化组件级基准测试编写
|
|
||||||
//
|
|
||||||
// 作者:xfy
|
|
||||||
package tools
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"math/rand"
|
|
||||||
"net"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/valyala/fasthttp"
|
|
||||||
)
|
|
||||||
|
|
||||||
// BenchmarkContext 提供标准化的基准测试上下文。
|
|
||||||
//
|
|
||||||
// 包含构造模拟请求所需的所有配置。
|
|
||||||
type BenchmarkContext struct {
|
|
||||||
// randSrc 随机数生成器
|
|
||||||
randSrc *rand.Rand
|
|
||||||
|
|
||||||
// RequestSize 请求数据大小
|
|
||||||
RequestSize TestDataSize
|
|
||||||
|
|
||||||
// ResponseSize 响应数据大小
|
|
||||||
ResponseSize TestDataSize
|
|
||||||
|
|
||||||
// Concurrency 并发级别(用于并行测试)
|
|
||||||
Concurrency int
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBenchmarkContext 创建基准测试上下文。
|
|
||||||
//
|
|
||||||
// 参数:
|
|
||||||
// - reqSize: 请求数据大小
|
|
||||||
// - respSize: 响应数据大小
|
|
||||||
// - concurrency: 并发级别
|
|
||||||
//
|
|
||||||
// 返回值:
|
|
||||||
// - *BenchmarkContext: 配置好的基准测试上下文
|
|
||||||
func NewBenchmarkContext(reqSize, respSize TestDataSize, concurrency int) *BenchmarkContext {
|
|
||||||
return &BenchmarkContext{
|
|
||||||
RequestSize: reqSize,
|
|
||||||
ResponseSize: respSize,
|
|
||||||
Concurrency: concurrency,
|
|
||||||
randSrc: rand.New(rand.NewSource(time.Now().UnixNano())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockRequestCtx 构造模拟的 fasthttp.RequestCtx。
|
|
||||||
//
|
|
||||||
// 创建一个可用于基准测试的请求上下文,包含:
|
|
||||||
// - 请求方法和路径
|
|
||||||
// - 请求头
|
|
||||||
// - 请求体
|
|
||||||
// - 远程地址
|
|
||||||
//
|
|
||||||
// 参数:
|
|
||||||
// - method: HTTP 方法 (GET, POST, etc.)
|
|
||||||
// - path: 请求路径
|
|
||||||
//
|
|
||||||
// 返回值:
|
|
||||||
// - *fasthttp.RequestCtx: 模拟的请求上下文
|
|
||||||
func (bc *BenchmarkContext) MockRequestCtx(method, path string) *fasthttp.RequestCtx {
|
|
||||||
ctx := &fasthttp.RequestCtx{}
|
|
||||||
|
|
||||||
// 设置请求行
|
|
||||||
ctx.Request.Header.SetMethod(method)
|
|
||||||
ctx.Request.SetRequestURI(path)
|
|
||||||
|
|
||||||
// 设置远程地址
|
|
||||||
ctx.Init(&fasthttp.Request{}, &net.TCPAddr{
|
|
||||||
IP: net.ParseIP("192.168.1.100"),
|
|
||||||
Port: 12345,
|
|
||||||
}, nil)
|
|
||||||
|
|
||||||
// 设置请求体
|
|
||||||
if bc.RequestSize > 0 {
|
|
||||||
body := GenerateTestData(bc.RequestSize)
|
|
||||||
ctx.Request.SetBody(body)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockRequestCtxWithHeaders 构造带自定义请求头的模拟上下文。
|
|
||||||
//
|
|
||||||
// 参数:
|
|
||||||
// - method: HTTP 方法
|
|
||||||
// - path: 请求路径
|
|
||||||
// - headers: 请求头键值对
|
|
||||||
//
|
|
||||||
// 返回值:
|
|
||||||
// - *fasthttp.RequestCtx: 模拟的请求上下文
|
|
||||||
func (bc *BenchmarkContext) MockRequestCtxWithHeaders(method, path string, headers map[string]string) *fasthttp.RequestCtx {
|
|
||||||
ctx := bc.MockRequestCtx(method, path)
|
|
||||||
|
|
||||||
// 设置请求头
|
|
||||||
for key, value := range headers {
|
|
||||||
ctx.Request.Header.Set(key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockRequestCtxWithBody 构造带自定义请求体的模拟上下文。
|
|
||||||
//
|
|
||||||
// 参数:
|
|
||||||
// - method: HTTP 方法
|
|
||||||
// - path: 请求路径
|
|
||||||
// - body: 请求体内容
|
|
||||||
//
|
|
||||||
// 返回值:
|
|
||||||
// - *fasthttp.RequestCtx: 模拟的请求上下文
|
|
||||||
func (bc *BenchmarkContext) MockRequestCtxWithBody(method, path string, body []byte) *fasthttp.RequestCtx {
|
|
||||||
ctx := bc.MockRequestCtx(method, path)
|
|
||||||
ctx.Request.SetBody(body)
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockRequestCtxWithIP 构造带指定 IP 的模拟上下文。
|
|
||||||
//
|
|
||||||
// 参数:
|
|
||||||
// - method: HTTP 方法
|
|
||||||
// - path: 请求路径
|
|
||||||
// - ip: 客户端 IP 地址
|
|
||||||
//
|
|
||||||
// 返回值:
|
|
||||||
// - *fasthttp.RequestCtx: 模拟的请求上下文
|
|
||||||
func (bc *BenchmarkContext) MockRequestCtxWithIP(method, path, ip string) *fasthttp.RequestCtx {
|
|
||||||
ctx := &fasthttp.RequestCtx{}
|
|
||||||
|
|
||||||
ctx.Request.Header.SetMethod(method)
|
|
||||||
ctx.Request.SetRequestURI(path)
|
|
||||||
|
|
||||||
ctx.Init(&fasthttp.Request{}, &net.TCPAddr{
|
|
||||||
IP: net.ParseIP(ip),
|
|
||||||
Port: 12345,
|
|
||||||
}, nil)
|
|
||||||
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockResponse 构造模拟响应数据。
|
|
||||||
//
|
|
||||||
// 根据 ResponseSize 生成响应体。
|
|
||||||
//
|
|
||||||
// 返回值:
|
|
||||||
// - []byte: 模拟的响应数据
|
|
||||||
func (bc *BenchmarkContext) MockResponse() []byte {
|
|
||||||
return GenerateTestData(bc.ResponseSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockResponseWithContentType 构造带 Content-Type 的模拟响应。
|
|
||||||
//
|
|
||||||
// 参数:
|
|
||||||
// - statusCode: HTTP 状态码
|
|
||||||
// - contentType: 内容类型
|
|
||||||
//
|
|
||||||
// 返回值:
|
|
||||||
// - []byte: 模拟的响应数据
|
|
||||||
func (bc *BenchmarkContext) MockResponseWithContentType(_, _ string) []byte {
|
|
||||||
// 返回响应体,调用者负责设置状态码和 Content-Type
|
|
||||||
return GenerateTestData(bc.ResponseSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RandomIP 生成随机 IP 地址。
|
|
||||||
//
|
|
||||||
// 用于测试多客户端场景。
|
|
||||||
//
|
|
||||||
// 返回值:
|
|
||||||
// - string: 随机 IP 地址
|
|
||||||
func (bc *BenchmarkContext) RandomIP() string {
|
|
||||||
return "192.168." + strconv.Itoa(bc.randSrc.Intn(256)) + "." + strconv.Itoa(bc.randSrc.Intn(256))
|
|
||||||
}
|
|
||||||
|
|
||||||
// RandomPath 生成随机请求路径。
|
|
||||||
//
|
|
||||||
// 参数:
|
|
||||||
// - prefix: 路径前缀
|
|
||||||
//
|
|
||||||
// 返回值:
|
|
||||||
// - string: 随机路径
|
|
||||||
func (bc *BenchmarkContext) RandomPath(prefix string) string {
|
|
||||||
return prefix + "/" + strconv.Itoa(bc.randSrc.Intn(10000))
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockJSONRequest 构造 JSON 格式的模拟请求。
|
|
||||||
//
|
|
||||||
// 参数:
|
|
||||||
// - path: 请求路径
|
|
||||||
// - data: JSON 数据
|
|
||||||
//
|
|
||||||
// 返回值:
|
|
||||||
// - *fasthttp.RequestCtx: 模拟的请求上下文
|
|
||||||
func (bc *BenchmarkContext) MockJSONRequest(path string, data []byte) *fasthttp.RequestCtx {
|
|
||||||
ctx := bc.MockRequestCtx("POST", path)
|
|
||||||
ctx.Request.Header.SetContentType("application/json")
|
|
||||||
ctx.Request.SetBody(data)
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockFormRequest 构造表单格式的模拟请求。
|
|
||||||
//
|
|
||||||
// 参数:
|
|
||||||
// - path: 请求路径
|
|
||||||
// - form: 表单数据键值对
|
|
||||||
//
|
|
||||||
// 返回值:
|
|
||||||
// - *fasthttp.RequestCtx: 模拟的请求上下文
|
|
||||||
func (bc *BenchmarkContext) MockFormRequest(path string, form map[string]string) *fasthttp.RequestCtx {
|
|
||||||
ctx := bc.MockRequestCtx("POST", path)
|
|
||||||
ctx.Request.Header.SetContentType("application/x-www-form-urlencoded")
|
|
||||||
|
|
||||||
// 构造表单数据
|
|
||||||
var buf bytes.Buffer
|
|
||||||
first := true
|
|
||||||
for key, value := range form {
|
|
||||||
if !first {
|
|
||||||
buf.WriteByte('&')
|
|
||||||
}
|
|
||||||
buf.WriteString(key)
|
|
||||||
buf.WriteByte('=')
|
|
||||||
buf.WriteString(value)
|
|
||||||
first = false
|
|
||||||
}
|
|
||||||
ctx.Request.SetBody(buf.Bytes())
|
|
||||||
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetResponse 设置模拟上下文的响应。
|
|
||||||
//
|
|
||||||
// 用于测试响应处理逻辑。
|
|
||||||
//
|
|
||||||
// 参数:
|
|
||||||
// - ctx: 请求上下文
|
|
||||||
// - statusCode: HTTP 状态码
|
|
||||||
// - body: 响应体
|
|
||||||
func (bc *BenchmarkContext) SetResponse(ctx *fasthttp.RequestCtx, statusCode int, body []byte) {
|
|
||||||
ctx.Response.SetStatusCode(statusCode)
|
|
||||||
ctx.Response.SetBody(body)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetJSONResponse 设置 JSON 格式的模拟响应。
|
|
||||||
//
|
|
||||||
// 参数:
|
|
||||||
// - ctx: 请求上下文
|
|
||||||
// - statusCode: HTTP 状态码
|
|
||||||
// - json: JSON 数据
|
|
||||||
func (bc *BenchmarkContext) SetJSONResponse(ctx *fasthttp.RequestCtx, statusCode int, json []byte) {
|
|
||||||
ctx.Response.SetStatusCode(statusCode)
|
|
||||||
ctx.Response.Header.SetContentType("application/json")
|
|
||||||
ctx.Response.SetBody(json)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultBenchmarkContext 返回默认的基准测试上下文。
|
|
||||||
//
|
|
||||||
// 配置:
|
|
||||||
// - RequestSize: 1KB
|
|
||||||
// - ResponseSize: 1KB
|
|
||||||
// - Concurrency: 1
|
|
||||||
//
|
|
||||||
// 返回值:
|
|
||||||
// - *BenchmarkContext: 默认配置的上下文
|
|
||||||
func DefaultBenchmarkContext() *BenchmarkContext {
|
|
||||||
return NewBenchmarkContext(Size1KB, Size1KB, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SmallRequestContext 返回小请求的基准测试上下文。
|
|
||||||
//
|
|
||||||
// 配置:
|
|
||||||
// - RequestSize: 100B
|
|
||||||
// - ResponseSize: 100B
|
|
||||||
//
|
|
||||||
// 返回值:
|
|
||||||
// - *BenchmarkContext: 小请求配置的上下文
|
|
||||||
func SmallRequestContext() *BenchmarkContext {
|
|
||||||
return NewBenchmarkContext(100, 100, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LargeRequestContext 返回大请求的基准测试上下文。
|
|
||||||
//
|
|
||||||
// 配置:
|
|
||||||
// - RequestSize: 100KB
|
|
||||||
// - ResponseSize: 100KB
|
|
||||||
//
|
|
||||||
// 返回值:
|
|
||||||
// - *BenchmarkContext: 大请求配置的上下文
|
|
||||||
func LargeRequestContext() *BenchmarkContext {
|
|
||||||
return NewBenchmarkContext(Size100KB, Size100KB, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HighConcurrencyContext 返回高并发基准测试上下文。
|
|
||||||
//
|
|
||||||
// 配置:
|
|
||||||
// - Concurrency: 100
|
|
||||||
//
|
|
||||||
// 返回值:
|
|
||||||
// - *BenchmarkContext: 高并发配置的上下文
|
|
||||||
func HighConcurrencyContext() *BenchmarkContext {
|
|
||||||
return NewBenchmarkContext(Size1KB, Size1KB, 100)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BenchmarkContextPool 提供基准测试上下文的池。
|
|
||||||
//
|
|
||||||
// 用于减少内存分配开销。
|
|
||||||
type BenchmarkContextPool struct {
|
|
||||||
pool chan *BenchmarkContext
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBenchmarkContextPool 创建基准测试上下文池。
|
|
||||||
//
|
|
||||||
// 参数:
|
|
||||||
// - size: 池大小
|
|
||||||
//
|
|
||||||
// 返回值:
|
|
||||||
// - *BenchmarkContextPool: 上下文池
|
|
||||||
func NewBenchmarkContextPool(size int) *BenchmarkContextPool {
|
|
||||||
p := &BenchmarkContextPool{
|
|
||||||
pool: make(chan *BenchmarkContext, size),
|
|
||||||
}
|
|
||||||
// 预填充池
|
|
||||||
for range size {
|
|
||||||
p.pool <- DefaultBenchmarkContext()
|
|
||||||
}
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get 从池中获取基准测试上下文。
|
|
||||||
//
|
|
||||||
// 返回值:
|
|
||||||
// - *BenchmarkContext: 基准测试上下文
|
|
||||||
func (p *BenchmarkContextPool) Get() *BenchmarkContext {
|
|
||||||
select {
|
|
||||||
case ctx := <-p.pool:
|
|
||||||
return ctx
|
|
||||||
default:
|
|
||||||
return DefaultBenchmarkContext()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Put 将基准测试上下文放回池中。
|
|
||||||
//
|
|
||||||
// 参数:
|
|
||||||
// - ctx: 基准测试上下文
|
|
||||||
func (p *BenchmarkContextPool) Put(ctx *BenchmarkContext) {
|
|
||||||
select {
|
|
||||||
case p.pool <- ctx:
|
|
||||||
default:
|
|
||||||
// 池已满,丢弃
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,160 +0,0 @@
|
|||||||
// Package tools provides testing utilities and mock infrastructure for benchmark tests.
|
|
||||||
package tools
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
"slices"
|
|
||||||
"sync"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/valyala/fasthttp"
|
|
||||||
)
|
|
||||||
|
|
||||||
// FasthttpLoadGenerator is a load generator using fasthttp client.
|
|
||||||
type FasthttpLoadGenerator struct {
|
|
||||||
client *fasthttp.HostClient
|
|
||||||
addr string
|
|
||||||
stats LoadGenStats
|
|
||||||
mu sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadGenStats contains load generator statistics.
|
|
||||||
type LoadGenStats struct {
|
|
||||||
Latencies []time.Duration // For percentile calculation
|
|
||||||
TotalRequests int
|
|
||||||
SuccessCount int
|
|
||||||
ErrorCount int
|
|
||||||
TotalDuration time.Duration
|
|
||||||
MinLatency time.Duration
|
|
||||||
MaxLatency time.Duration
|
|
||||||
MeanLatency time.Duration
|
|
||||||
P50Latency time.Duration
|
|
||||||
P90Latency time.Duration
|
|
||||||
P99Latency time.Duration
|
|
||||||
QPS float64
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFasthttpLoadGenerator creates a new load generator for the given address.
|
|
||||||
func NewFasthttpLoadGenerator(addr string) *FasthttpLoadGenerator {
|
|
||||||
return &FasthttpLoadGenerator{
|
|
||||||
client: &fasthttp.HostClient{
|
|
||||||
Addr: addr,
|
|
||||||
MaxConns: 1000,
|
|
||||||
},
|
|
||||||
addr: addr,
|
|
||||||
stats: LoadGenStats{
|
|
||||||
MinLatency: time.Duration(math.MaxInt64),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run executes a load test with n requests using the specified concurrency.
|
|
||||||
// Returns collected statistics.
|
|
||||||
func (lg *FasthttpLoadGenerator) Run(n int, concurrency int) *LoadGenStats {
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
requestsPerWorker := n / concurrency
|
|
||||||
|
|
||||||
// Channels for collecting metrics
|
|
||||||
latencyChan := make(chan time.Duration, n)
|
|
||||||
errorChan := make(chan error, n)
|
|
||||||
|
|
||||||
start := time.Now()
|
|
||||||
|
|
||||||
for range concurrency {
|
|
||||||
wg.Go(func() {
|
|
||||||
req := fasthttp.AcquireRequest()
|
|
||||||
resp := fasthttp.AcquireResponse()
|
|
||||||
defer fasthttp.ReleaseRequest(req)
|
|
||||||
defer fasthttp.ReleaseResponse(resp)
|
|
||||||
|
|
||||||
for range requestsPerWorker {
|
|
||||||
req.SetRequestURI("http://" + lg.addr + "/")
|
|
||||||
req.Header.SetMethod("GET")
|
|
||||||
|
|
||||||
reqStart := time.Now()
|
|
||||||
err := lg.client.Do(req, resp)
|
|
||||||
latency := time.Since(reqStart)
|
|
||||||
|
|
||||||
latencyChan <- latency
|
|
||||||
if err != nil {
|
|
||||||
errorChan <- err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
wg.Wait()
|
|
||||||
close(latencyChan)
|
|
||||||
close(errorChan)
|
|
||||||
|
|
||||||
totalDuration := time.Since(start)
|
|
||||||
|
|
||||||
// Collect latencies
|
|
||||||
latencies := make([]time.Duration, 0, n)
|
|
||||||
for lat := range latencyChan {
|
|
||||||
latencies = append(latencies, lat)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count errors
|
|
||||||
errorCount := 0
|
|
||||||
for err := range errorChan {
|
|
||||||
_ = err // Error recorded, used for counting
|
|
||||||
errorCount++
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate statistics
|
|
||||||
lg.mu.Lock()
|
|
||||||
defer lg.mu.Unlock()
|
|
||||||
|
|
||||||
lg.stats.TotalRequests = n
|
|
||||||
lg.stats.ErrorCount = errorCount
|
|
||||||
lg.stats.SuccessCount = n - errorCount
|
|
||||||
lg.stats.TotalDuration = totalDuration
|
|
||||||
lg.stats.QPS = float64(n) / totalDuration.Seconds()
|
|
||||||
lg.stats.Latencies = latencies
|
|
||||||
|
|
||||||
// Calculate latency distribution
|
|
||||||
if len(latencies) > 0 {
|
|
||||||
slices.Sort(latencies)
|
|
||||||
|
|
||||||
lg.stats.MinLatency = latencies[0]
|
|
||||||
lg.stats.MaxLatency = latencies[len(latencies)-1]
|
|
||||||
|
|
||||||
// Calculate mean
|
|
||||||
var sum time.Duration
|
|
||||||
for _, l := range latencies {
|
|
||||||
sum += l
|
|
||||||
}
|
|
||||||
lg.stats.MeanLatency = sum / time.Duration(len(latencies))
|
|
||||||
|
|
||||||
// Calculate percentiles
|
|
||||||
lg.stats.P50Latency = latencies[len(latencies)*50/100]
|
|
||||||
lg.stats.P90Latency = latencies[len(latencies)*90/100]
|
|
||||||
lg.stats.P99Latency = latencies[len(latencies)*99/100]
|
|
||||||
}
|
|
||||||
|
|
||||||
return &lg.stats
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetStats returns current statistics without running a test.
|
|
||||||
func (lg *FasthttpLoadGenerator) GetStats() *LoadGenStats {
|
|
||||||
lg.mu.Lock()
|
|
||||||
defer lg.mu.Unlock()
|
|
||||||
return &lg.stats
|
|
||||||
}
|
|
||||||
|
|
||||||
// RunParallel runs requests in parallel using testing.PB.
|
|
||||||
// This is designed for use with Go benchmark functions.
|
|
||||||
func (lg *FasthttpLoadGenerator) RunParallel(pb *testing.PB) {
|
|
||||||
req := fasthttp.AcquireRequest()
|
|
||||||
resp := fasthttp.AcquireResponse()
|
|
||||||
defer fasthttp.ReleaseRequest(req)
|
|
||||||
defer fasthttp.ReleaseResponse(resp)
|
|
||||||
|
|
||||||
for pb.Next() {
|
|
||||||
req.SetRequestURI("http://" + lg.addr + "/")
|
|
||||||
req.Header.SetMethod("GET")
|
|
||||||
_ = lg.client.Do(req, resp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,151 +0,0 @@
|
|||||||
// Package tools provides testing utilities and mock infrastructure for benchmark tests.
|
|
||||||
package tools
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/rand"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/valyala/fasthttp"
|
|
||||||
"github.com/valyala/fasthttp/fasthttputil"
|
|
||||||
)
|
|
||||||
|
|
||||||
// BackendMode defines the response behavior of the mock backend.
|
|
||||||
type BackendMode int
|
|
||||||
|
|
||||||
const (
|
|
||||||
// ModeFixed returns a fixed response with configurable status and body.
|
|
||||||
ModeFixed BackendMode = iota
|
|
||||||
// ModeDelay adds artificial delay before responding.
|
|
||||||
ModeDelay
|
|
||||||
// ModeError returns errors for a percentage of requests.
|
|
||||||
ModeError
|
|
||||||
// ModeRandomResponse returns random status codes.
|
|
||||||
ModeRandomResponse
|
|
||||||
)
|
|
||||||
|
|
||||||
// MockBackendConfig configures the mock backend behavior.
|
|
||||||
type MockBackendConfig struct {
|
|
||||||
Body []byte
|
|
||||||
Mode BackendMode
|
|
||||||
StatusCode int
|
|
||||||
Delay time.Duration
|
|
||||||
ErrorRate float64 // 0.0 to 1.0, for ModeError
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockBackend represents a mock fasthttp server for testing.
|
|
||||||
type MockBackend struct {
|
|
||||||
server *fasthttp.Server
|
|
||||||
config MockBackendConfig
|
|
||||||
mu sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// StartMockFasthttpBackend starts a mock fasthttp backend server.
|
|
||||||
// Returns the server address and a cleanup function.
|
|
||||||
func StartMockFasthttpBackend(config MockBackendConfig) (string, func()) {
|
|
||||||
mb := &MockBackend{
|
|
||||||
config: config,
|
|
||||||
}
|
|
||||||
|
|
||||||
mb.server = &fasthttp.Server{
|
|
||||||
Handler: mb.handler,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use in-memory listener for testing
|
|
||||||
ln := fasthttputil.NewInmemoryListener()
|
|
||||||
|
|
||||||
// Start server in background
|
|
||||||
go func() {
|
|
||||||
_ = mb.server.Serve(ln)
|
|
||||||
}()
|
|
||||||
|
|
||||||
addr := "127.0.0.1:0" // In-memory listener address
|
|
||||||
|
|
||||||
cleanup := func() {
|
|
||||||
_ = mb.server.Shutdown()
|
|
||||||
_ = ln.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
return addr, cleanup
|
|
||||||
}
|
|
||||||
|
|
||||||
// handler processes incoming requests based on the configured mode.
|
|
||||||
func (mb *MockBackend) handler(ctx *fasthttp.RequestCtx) {
|
|
||||||
mb.mu.RLock()
|
|
||||||
config := mb.config
|
|
||||||
mb.mu.RUnlock()
|
|
||||||
|
|
||||||
switch config.Mode {
|
|
||||||
case ModeFixed:
|
|
||||||
ctx.SetStatusCode(config.StatusCode)
|
|
||||||
_, _ = ctx.Write(config.Body)
|
|
||||||
|
|
||||||
case ModeDelay:
|
|
||||||
time.Sleep(config.Delay)
|
|
||||||
ctx.SetStatusCode(config.StatusCode)
|
|
||||||
_, _ = ctx.Write(config.Body)
|
|
||||||
|
|
||||||
case ModeError:
|
|
||||||
if rand.Float64() < config.ErrorRate {
|
|
||||||
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
|
|
||||||
_, _ = ctx.WriteString("internal server error")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.SetStatusCode(config.StatusCode)
|
|
||||||
_, _ = ctx.Write(config.Body)
|
|
||||||
|
|
||||||
case ModeRandomResponse:
|
|
||||||
codes := []int{
|
|
||||||
fasthttp.StatusOK,
|
|
||||||
fasthttp.StatusCreated,
|
|
||||||
fasthttp.StatusNoContent,
|
|
||||||
fasthttp.StatusBadRequest,
|
|
||||||
fasthttp.StatusNotFound,
|
|
||||||
}
|
|
||||||
ctx.SetStatusCode(codes[rand.Intn(len(codes))])
|
|
||||||
_, _ = ctx.Write(config.Body)
|
|
||||||
|
|
||||||
default: // ModeFixed
|
|
||||||
ctx.SetStatusCode(config.StatusCode)
|
|
||||||
_, _ = ctx.Write(config.Body)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetConfig updates the backend configuration at runtime.
|
|
||||||
func (mb *MockBackend) SetConfig(config MockBackendConfig) {
|
|
||||||
mb.mu.Lock()
|
|
||||||
defer mb.mu.Unlock()
|
|
||||||
mb.config = config
|
|
||||||
}
|
|
||||||
|
|
||||||
// SimpleMockBackend creates a simple backend with fixed response.
|
|
||||||
// Returns address and cleanup function.
|
|
||||||
func SimpleMockBackend(statusCode int, body []byte) (string, func()) {
|
|
||||||
return StartMockFasthttpBackend(MockBackendConfig{
|
|
||||||
Mode: ModeFixed,
|
|
||||||
StatusCode: statusCode,
|
|
||||||
Body: body,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// DelayedMockBackend creates a backend with delayed responses.
|
|
||||||
// Returns address and cleanup function.
|
|
||||||
func DelayedMockBackend(delay time.Duration, body []byte) (string, func()) {
|
|
||||||
return StartMockFasthttpBackend(MockBackendConfig{
|
|
||||||
Mode: ModeDelay,
|
|
||||||
StatusCode: fasthttp.StatusOK,
|
|
||||||
Body: body,
|
|
||||||
Delay: delay,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrorMockBackend creates a backend that returns errors at the specified rate.
|
|
||||||
// Returns address and cleanup function.
|
|
||||||
func ErrorMockBackend(errorRate float64, body []byte) (string, func()) {
|
|
||||||
return StartMockFasthttpBackend(MockBackendConfig{
|
|
||||||
Mode: ModeError,
|
|
||||||
StatusCode: fasthttp.StatusOK,
|
|
||||||
Body: body,
|
|
||||||
ErrorRate: errorRate,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@ -1,182 +0,0 @@
|
|||||||
// Package tools provides testing utilities and mock infrastructure for benchmark tests.
|
|
||||||
package tools
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"math/rand"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TestDataSize represents predefined test data sizes.
|
|
||||||
type TestDataSize int
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Size1KB represents 1KB test data.
|
|
||||||
Size1KB TestDataSize = 1024
|
|
||||||
// Size10KB represents 10KB test data.
|
|
||||||
Size10KB TestDataSize = 10 * 1024
|
|
||||||
// Size100KB represents 100KB test data.
|
|
||||||
Size100KB TestDataSize = 100 * 1024
|
|
||||||
// Size1MB represents 1MB test data.
|
|
||||||
Size1MB TestDataSize = 1024 * 1024
|
|
||||||
// Size10MB represents 10MB test data.
|
|
||||||
Size10MB TestDataSize = 10 * 1024 * 1024
|
|
||||||
)
|
|
||||||
|
|
||||||
// GenerateTestData generates test data of the specified size.
|
|
||||||
func GenerateTestData(size TestDataSize) []byte {
|
|
||||||
data := make([]byte, size)
|
|
||||||
// Fill with random data for compression testing
|
|
||||||
for i := range data {
|
|
||||||
data[i] = byte(rand.Intn(256))
|
|
||||||
}
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateTestDataString generates test data as string.
|
|
||||||
func GenerateTestDataString(size TestDataSize) string {
|
|
||||||
return string(GenerateTestData(size))
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestTarget represents a backend target for testing.
|
|
||||||
type TestTarget struct {
|
|
||||||
Address string
|
|
||||||
Weight int
|
|
||||||
}
|
|
||||||
|
|
||||||
// createTestTargets creates n test backend targets with mock servers.
|
|
||||||
// Returns the target configurations and a cleanup function.
|
|
||||||
func createTestTargets(n int) ([]TestTarget, func()) {
|
|
||||||
targets := make([]TestTarget, n)
|
|
||||||
cleanups := make([]func(), n)
|
|
||||||
|
|
||||||
for i := range n {
|
|
||||||
body := GenerateTestData(Size1KB)
|
|
||||||
addr, cleanup := SimpleMockBackend(200, body)
|
|
||||||
targets[i] = TestTarget{
|
|
||||||
Address: addr,
|
|
||||||
Weight: 1,
|
|
||||||
}
|
|
||||||
cleanups[i] = cleanup
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanupAll := func() {
|
|
||||||
for _, cleanup := range cleanups {
|
|
||||||
if cleanup != nil {
|
|
||||||
cleanup()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return targets, cleanupAll
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateTestTargets creates n test backend targets.
|
|
||||||
// Returns the target configurations and a cleanup function.
|
|
||||||
func CreateTestTargets(n int) ([]TestTarget, func()) {
|
|
||||||
return createTestTargets(n)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateWeightedTestTargets creates n test backend targets with varying weights.
|
|
||||||
// Returns the target configurations and a cleanup function.
|
|
||||||
func CreateWeightedTestTargets(n int) ([]TestTarget, func()) {
|
|
||||||
targets := make([]TestTarget, n)
|
|
||||||
cleanups := make([]func(), n)
|
|
||||||
|
|
||||||
for i := range n {
|
|
||||||
body := GenerateTestData(Size1KB)
|
|
||||||
addr, cleanup := SimpleMockBackend(200, body)
|
|
||||||
// Vary weights: 1, 2, 3, etc.
|
|
||||||
targets[i] = TestTarget{
|
|
||||||
Address: addr,
|
|
||||||
Weight: i + 1,
|
|
||||||
}
|
|
||||||
cleanups[i] = cleanup
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanupAll := func() {
|
|
||||||
for _, cleanup := range cleanups {
|
|
||||||
if cleanup != nil {
|
|
||||||
cleanup()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return targets, cleanupAll
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateDelayedTestTargets creates n test backend targets with varying delays.
|
|
||||||
// Useful for testing timeout and latency-related behavior.
|
|
||||||
func CreateDelayedTestTargets(n int, baseDelay time.Duration) ([]TestTarget, func()) {
|
|
||||||
targets := make([]TestTarget, n)
|
|
||||||
cleanups := make([]func(), n)
|
|
||||||
|
|
||||||
for i := range n {
|
|
||||||
body := GenerateTestData(Size1KB)
|
|
||||||
// Each target has increasing delay
|
|
||||||
delay := baseDelay * time.Duration(i+1)
|
|
||||||
addr, cleanup := DelayedMockBackend(delay, body)
|
|
||||||
targets[i] = TestTarget{
|
|
||||||
Address: addr,
|
|
||||||
Weight: 1,
|
|
||||||
}
|
|
||||||
cleanups[i] = cleanup
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanupAll := func() {
|
|
||||||
for _, cleanup := range cleanups {
|
|
||||||
if cleanup != nil {
|
|
||||||
cleanup()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return targets, cleanupAll
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateErrorTestTargets creates n test backend targets with varying error rates.
|
|
||||||
// Useful for testing error handling and circuit breaker behavior.
|
|
||||||
func CreateErrorTestTargets(n int, baseErrorRate float64) ([]TestTarget, func()) {
|
|
||||||
targets := make([]TestTarget, n)
|
|
||||||
cleanups := make([]func(), n)
|
|
||||||
|
|
||||||
for i := range n {
|
|
||||||
body := GenerateTestData(Size1KB)
|
|
||||||
// Vary error rates slightly per target
|
|
||||||
errorRate := baseErrorRate + float64(i)*0.05
|
|
||||||
if errorRate > 1.0 {
|
|
||||||
errorRate = 1.0
|
|
||||||
}
|
|
||||||
addr, cleanup := ErrorMockBackend(errorRate, body)
|
|
||||||
targets[i] = TestTarget{
|
|
||||||
Address: addr,
|
|
||||||
Weight: 1,
|
|
||||||
}
|
|
||||||
cleanups[i] = cleanup
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanupAll := func() {
|
|
||||||
for _, cleanup := range cleanups {
|
|
||||||
if cleanup != nil {
|
|
||||||
cleanup()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return targets, cleanupAll
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateCacheKey generates a unique cache key for testing.
|
|
||||||
func GenerateCacheKey(prefix string, index int) string {
|
|
||||||
return fmt.Sprintf("%s-key-%d", prefix, index)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateCacheValue generates a cache value of specified size.
|
|
||||||
func GenerateCacheValue(size TestDataSize) []byte {
|
|
||||||
return GenerateTestData(size)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateRandomCacheKey generates a random cache key.
|
|
||||||
func GenerateRandomCacheKey() string {
|
|
||||||
return fmt.Sprintf("random-key-%d-%d", time.Now().UnixNano(), rand.Int())
|
|
||||||
}
|
|
||||||
@ -69,8 +69,8 @@ func DefaultConfig() *Config {
|
|||||||
CodeCacheSize: 1000,
|
CodeCacheSize: 1000,
|
||||||
EnableFileWatch: true,
|
EnableFileWatch: true,
|
||||||
MaxExecutionTime: 30 * time.Second,
|
MaxExecutionTime: 30 * time.Second,
|
||||||
LStatePoolInitialSize: 100,
|
LStatePoolInitialSize: 100,
|
||||||
LStatePoolMaxSize: 1000,
|
LStatePoolMaxSize: 1000,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Static: []StaticConfig{{
|
Static: []StaticConfig{{
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
// Package loadbalance 提供负载均衡算法实现。
|
// Package loadbalance 提供负载均衡算法实现。
|
||||||
//
|
//
|
||||||
// 该文件包含负载均衡算法相关的辅助逻辑,包括:
|
// 该文件包含负载均衡算法相关的辅助逻辑,包括:
|
||||||
// - ValidAlgorithms 有效算法列表定义
|
|
||||||
// - IsValidAlgorithm 算法有效性校验函数
|
// - IsValidAlgorithm 算法有效性校验函数
|
||||||
//
|
//
|
||||||
// 主要用途:
|
// 主要用途:
|
||||||
@ -9,7 +8,7 @@
|
|||||||
// 用于校验和枚举系统支持的负载均衡算法类型,供配置解析和路由选择使用。
|
// 用于校验和枚举系统支持的负载均衡算法类型,供配置解析和路由选择使用。
|
||||||
//
|
//
|
||||||
// 注意事项:
|
// 注意事项:
|
||||||
// - 新增算法时必须同步更新 ValidAlgorithms 列表
|
// - 新增算法时必须同步更新 validAlgorithms 列表
|
||||||
// - 空字符串被视为有效值,表示使用默认算法
|
// - 空字符串被视为有效值,表示使用默认算法
|
||||||
//
|
//
|
||||||
// 作者:xfy
|
// 作者:xfy
|
||||||
@ -17,15 +16,8 @@ package loadbalance
|
|||||||
|
|
||||||
import "slices"
|
import "slices"
|
||||||
|
|
||||||
// ValidAlgorithms 定义系统支持的负载均衡算法名称列表。
|
// validAlgorithms 定义系统支持的负载均衡算法名称列表。
|
||||||
//
|
var validAlgorithms = []string{
|
||||||
// 该列表用于配置校验,包含以下算法:
|
|
||||||
// - round_robin: 简单轮询,按顺序均匀分配请求
|
|
||||||
// - weighted_round_robin: 加权轮询,按权重比例分配请求
|
|
||||||
// - least_conn: 最少连接,选择活跃连接数最少的目标
|
|
||||||
// - ip_hash: IP 哈希,基于客户端 IP 实现会话保持
|
|
||||||
// - consistent_hash: 一致性哈希,使用虚拟节点实现均匀分布
|
|
||||||
var ValidAlgorithms = []string{
|
|
||||||
"round_robin",
|
"round_robin",
|
||||||
"weighted_round_robin",
|
"weighted_round_robin",
|
||||||
"least_conn",
|
"least_conn",
|
||||||
@ -43,11 +35,11 @@ var ValidAlgorithms = []string{
|
|||||||
// - alg: 算法名称字符串,如 "round_robin"、"least_conn" 等
|
// - alg: 算法名称字符串,如 "round_robin"、"least_conn" 等
|
||||||
//
|
//
|
||||||
// 返回值:
|
// 返回值:
|
||||||
// - true: 算法有效(在 ValidAlgorithms 列表中或为空字符串)
|
// - true: 算法有效(在 validAlgorithms 列表中或为空字符串)
|
||||||
// - false: 算法无效(不在 ValidAlgorithms 列表中且非空)
|
// - false: 算法无效(不在 validAlgorithms 列表中且非空)
|
||||||
func IsValidAlgorithm(alg string) bool {
|
func IsValidAlgorithm(alg string) bool {
|
||||||
if alg == "" {
|
if alg == "" {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return slices.Contains(ValidAlgorithms, alg)
|
return slices.Contains(validAlgorithms, alg)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -869,7 +869,6 @@ func (c *LuaCoroutine) handleCosocketConnect(values []glua.LValue) ([]glua.LValu
|
|||||||
return []glua.LValue{glua.LNil, glua.LNil}, nil
|
return []glua.LValue{glua.LNil, glua.LNil}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = result // 连接成功,返回 1
|
|
||||||
return []glua.LValue{glua.LNumber(1)}, nil
|
return []glua.LValue{glua.LNumber(1)}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -87,8 +87,8 @@ func DefaultConfig() *Config {
|
|||||||
EnableLoadLib: false,
|
EnableLoadLib: false,
|
||||||
CoroutineStackSize: 64, // 优化:较小的栈减少内存分配
|
CoroutineStackSize: 64, // 优化:较小的栈减少内存分配
|
||||||
MinimizeStackMemory: true,
|
MinimizeStackMemory: true,
|
||||||
CoroutinePoolWarmup: 4, // 预热4个协程结构
|
CoroutinePoolWarmup: 4, // 预热4个协程结构
|
||||||
LStatePoolInitialSize: 100, // LState 池预热 100 个
|
LStatePoolInitialSize: 100, // LState 池预热 100 个
|
||||||
LStatePoolMaxSize: 1000, // LState 池最大 1000 个(与 MaxConcurrentCoroutines 匹配)
|
LStatePoolMaxSize: 1000, // LState 池最大 1000 个(与 MaxConcurrentCoroutines 匹配)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -151,11 +151,11 @@ func NewEngine(config *Config) (*LuaEngine, error) {
|
|||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
engine := &LuaEngine{
|
engine := &LuaEngine{
|
||||||
config: config,
|
config: config,
|
||||||
codeCache: NewCodeCache(config.CodeCacheSize, config.CodeCacheTTL, config.EnableFileWatch),
|
codeCache: NewCodeCache(config.CodeCacheSize, config.CodeCacheTTL, config.EnableFileWatch),
|
||||||
maxCoroutines: config.MaxConcurrentCoroutines,
|
maxCoroutines: config.MaxConcurrentCoroutines,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
sharedDictManager: NewSharedDictManager(),
|
sharedDictManager: NewSharedDictManager(),
|
||||||
coroutinePool: sync.Pool{
|
coroutinePool: sync.Pool{
|
||||||
New: func() any {
|
New: func() any {
|
||||||
|
|||||||
@ -149,4 +149,4 @@ func (p *LStatePool) Available() int {
|
|||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
defer p.mu.Unlock()
|
defer p.mu.Unlock()
|
||||||
return len(p.pool)
|
return len(p.pool)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -93,4 +93,4 @@ func (h *LuaRouteHandler) ServeHTTP(ctx *fasthttp.RequestCtx) {
|
|||||||
|
|
||||||
luaCtx.FlushOutput()
|
luaCtx.FlushOutput()
|
||||||
luaCtx.Release()
|
luaCtx.Release()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,9 +5,10 @@
|
|||||||
// 作者:xfy
|
// 作者:xfy
|
||||||
package matcher
|
package matcher
|
||||||
|
|
||||||
import "maps"
|
import (
|
||||||
|
"fmt"
|
||||||
import "fmt"
|
"maps"
|
||||||
|
)
|
||||||
|
|
||||||
// ConflictDetector 路径冲突检测器。
|
// ConflictDetector 路径冲突检测器。
|
||||||
//
|
//
|
||||||
|
|||||||
@ -15,9 +15,11 @@
|
|||||||
// 作者:xfy
|
// 作者:xfy
|
||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import "slices"
|
import (
|
||||||
|
"slices"
|
||||||
|
|
||||||
import "github.com/valyala/fasthttp"
|
"github.com/valyala/fasthttp"
|
||||||
|
)
|
||||||
|
|
||||||
// Middleware 中间件接口,定义中间件的标准方法。
|
// Middleware 中间件接口,定义中间件的标准方法。
|
||||||
//
|
//
|
||||||
|
|||||||
@ -111,8 +111,8 @@ func initLuaEngine(luaCfg *config.LuaMiddlewareConfig) (*lua.LuaEngine, error) {
|
|||||||
EnableOSLib: false, // 安全默认值
|
EnableOSLib: false, // 安全默认值
|
||||||
EnableIOLib: false,
|
EnableIOLib: false,
|
||||||
EnableLoadLib: false,
|
EnableLoadLib: false,
|
||||||
LStatePoolInitialSize: luaCfg.GlobalSettings.LStatePoolInitialSize,
|
LStatePoolInitialSize: luaCfg.GlobalSettings.LStatePoolInitialSize,
|
||||||
LStatePoolMaxSize: luaCfg.GlobalSettings.LStatePoolMaxSize,
|
LStatePoolMaxSize: luaCfg.GlobalSettings.LStatePoolMaxSize,
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置协程栈优化选项
|
// 设置协程栈优化选项
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user