perf(proxy): 缓存键哈希计算零分配优化
- 新增 buildCacheKeyHashValue 直接计算哈希值 - 消除缓存键字符串构建的内存分配 - 内部调用改用新函数降低 GC 压力 - 添加基准测试对比两种方法性能差异 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
9cbc380de5
commit
eccdcde901
@ -531,7 +531,7 @@ func (p *Proxy) ServeHTTP(ctx *fasthttp.RequestCtx) {
|
||||
|
||||
// 释放缓存锁
|
||||
if p.cache != nil && attempt == 0 {
|
||||
hashKey, _ := p.buildCacheKeyHash(ctx)
|
||||
hashKey := p.buildCacheKeyHashValue(ctx)
|
||||
p.cache.ReleaseLock(hashKey, err)
|
||||
}
|
||||
|
||||
@ -562,7 +562,7 @@ func (p *Proxy) ServeHTTP(ctx *fasthttp.RequestCtx) {
|
||||
if shouldRetry {
|
||||
// 释放缓存锁
|
||||
if p.cache != nil && attempt == 0 {
|
||||
hashKey, _ := p.buildCacheKeyHash(ctx)
|
||||
hashKey := p.buildCacheKeyHashValue(ctx)
|
||||
p.cache.ReleaseLock(hashKey, fmt.Errorf("HTTP %d", statusCode))
|
||||
}
|
||||
|
||||
@ -903,13 +903,16 @@ func (p *Proxy) GetConfig() *config.ProxyConfig {
|
||||
}
|
||||
|
||||
// buildCacheKey 构建缓存键。
|
||||
// 保留此函数用于日志记录和调试。
|
||||
func (p *Proxy) buildCacheKey(ctx *fasthttp.RequestCtx) string {
|
||||
// 使用请求方法和路径作为缓存键
|
||||
return string(ctx.Request.Header.Method()) + ":" + string(ctx.Request.URI().RequestURI())
|
||||
}
|
||||
|
||||
// buildCacheKeyHash 使用 FNV-64a 计算缓存键的 uint64 哈希值。
|
||||
// 这个函数分配 0 内存,比字符串键更高效。
|
||||
// 返回哈希值和原始字符串键。
|
||||
// 注意:此函数会先构建字符串键再哈希,存在双重分配。
|
||||
// 对于只需要哈希值的场景,使用 buildCacheKeyHashValue 代替。
|
||||
func (p *Proxy) buildCacheKeyHash(ctx *fasthttp.RequestCtx) (uint64, string) {
|
||||
// 构建原始 key
|
||||
origKey := p.buildCacheKey(ctx)
|
||||
@ -920,6 +923,16 @@ func (p *Proxy) buildCacheKeyHash(ctx *fasthttp.RequestCtx) (uint64, string) {
|
||||
return h.Sum64(), origKey
|
||||
}
|
||||
|
||||
// buildCacheKeyHashValue 直接计算缓存键的哈希值,零字符串分配。
|
||||
// 用于只需要哈希值而不需要原始键的场景。
|
||||
func (p *Proxy) buildCacheKeyHashValue(ctx *fasthttp.RequestCtx) uint64 {
|
||||
h := fnv.New64a()
|
||||
h.Write(ctx.Request.Header.Method())
|
||||
h.Write([]byte(":"))
|
||||
h.Write(ctx.Request.URI().RequestURI())
|
||||
return h.Sum64()
|
||||
}
|
||||
|
||||
// writeCachedResponse 写入缓存的响应。
|
||||
func (p *Proxy) writeCachedResponse(ctx *fasthttp.RequestCtx, entry *cache.ProxyCacheEntry) {
|
||||
ctx.Response.SetBody(entry.Data)
|
||||
|
||||
@ -427,3 +427,39 @@ func BenchmarkProxyHeaderProcessing(b *testing.B) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// BenchmarkBuildCacheKeyHash 基准测试缓存键哈希计算性能。
|
||||
func BenchmarkBuildCacheKeyHash(b *testing.B) {
|
||||
ctx := &fasthttp.RequestCtx{}
|
||||
ctx.Request.Header.SetMethod(fasthttp.MethodGet)
|
||||
ctx.Request.SetRequestURI("/api/test?query=1")
|
||||
|
||||
p, err := NewProxy(&config.ProxyConfig{
|
||||
Path: "/api",
|
||||
LoadBalance: "round_robin",
|
||||
Timeout: config.ProxyTimeout{
|
||||
Connect: 5 * time.Second,
|
||||
Read: 30 * time.Second,
|
||||
Write: 30 * time.Second,
|
||||
},
|
||||
}, []*loadbalance.Target{{URL: "http://localhost:8080"}}, nil, nil)
|
||||
if err != nil {
|
||||
b.Fatalf("NewProxy() error: %v", err)
|
||||
}
|
||||
|
||||
b.Run("buildCacheKeyHash_with_string", func(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
hashKey, _ := p.buildCacheKeyHash(ctx)
|
||||
_ = hashKey
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("buildCacheKeyHashValue_direct", func(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
hashKey := p.buildCacheKeyHashValue(ctx)
|
||||
_ = hashKey
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user