perf(backend): 使用 gjson/sjson 优化热路径 JSON 处理
将 API 网关热路径中的 json.Unmarshal+json.Marshal 替换为 gjson 零拷贝查询和 sjson 精准写入: - unwrapV1InternalResponse 性能提升 22x(4009ns→182ns),内存分配减少 28.5x - unwrapGeminiResponse、extractGeminiUsage、estimateGeminiCountTokens、ParseGeminiRateLimitResetTime 改为接收 []byte 使用 gjson 提取 - ParseGatewayRequest 的 model/stream/metadata/thinking/max_tokens 改用 gjson 类型安全提取 - Handler 层(sora/openai)改用 gjson 提取字段、sjson 注入/修改字段,移除 map[string]any 中间变量 - Sora Client 响应解析改用 gjson ForEach 遍历,减少内存分配 - 新增约 100 个单元测试用例,所有改动函数覆盖率 >85% Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -889,3 +890,144 @@ func TestAntigravityClientWriter(t *testing.T) {
|
||||
require.True(t, cw.Disconnected())
|
||||
})
|
||||
}
|
||||
|
||||
// TestUnwrapV1InternalResponse 测试 unwrapV1InternalResponse 的各种输入场景
|
||||
func TestUnwrapV1InternalResponse(t *testing.T) {
|
||||
svc := &AntigravityGatewayService{}
|
||||
|
||||
// 构造 >50KB 的大型 JSON
|
||||
largePadding := strings.Repeat("x", 50*1024)
|
||||
largeInput := []byte(fmt.Sprintf(`{"response":{"id":"big","pad":"%s"}}`, largePadding))
|
||||
largeExpected := fmt.Sprintf(`{"id":"big","pad":"%s"}`, largePadding)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input []byte
|
||||
expected string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "正常 response 包装",
|
||||
input: []byte(`{"response":{"id":"123","content":"hello"}}`),
|
||||
expected: `{"id":"123","content":"hello"}`,
|
||||
},
|
||||
{
|
||||
name: "无 response 透传",
|
||||
input: []byte(`{"id":"456"}`),
|
||||
expected: `{"id":"456"}`,
|
||||
},
|
||||
{
|
||||
name: "空 JSON",
|
||||
input: []byte(`{}`),
|
||||
expected: `{}`,
|
||||
},
|
||||
{
|
||||
name: "response 为 null",
|
||||
input: []byte(`{"response":null}`),
|
||||
expected: `null`,
|
||||
},
|
||||
{
|
||||
name: "response 为基础类型 string",
|
||||
input: []byte(`{"response":"hello"}`),
|
||||
expected: `"hello"`,
|
||||
},
|
||||
{
|
||||
name: "非法 JSON",
|
||||
input: []byte(`not json`),
|
||||
expected: `not json`,
|
||||
},
|
||||
{
|
||||
name: "嵌套 response 只解一层",
|
||||
input: []byte(`{"response":{"response":{"inner":true}}}`),
|
||||
expected: `{"response":{"inner":true}}`,
|
||||
},
|
||||
{
|
||||
name: "大型 JSON >50KB",
|
||||
input: largeInput,
|
||||
expected: largeExpected,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := svc.unwrapV1InternalResponse(tt.input)
|
||||
if tt.wantErr {
|
||||
require.Error(t, err)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tt.expected, strings.TrimSpace(string(got)))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// --- unwrapV1InternalResponse benchmark 对照组 ---
|
||||
|
||||
// unwrapV1InternalResponseOld 旧实现:Unmarshal+Marshal 双重开销(仅用于 benchmark 对照)
|
||||
func unwrapV1InternalResponseOld(body []byte) ([]byte, error) {
|
||||
var outer map[string]any
|
||||
if err := json.Unmarshal(body, &outer); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp, ok := outer["response"]; ok {
|
||||
return json.Marshal(resp)
|
||||
}
|
||||
return body, nil
|
||||
}
|
||||
|
||||
func BenchmarkUnwrapV1Internal_Old_Small(b *testing.B) {
|
||||
body := []byte(`{"response":{"candidates":[{"content":{"parts":[{"text":"hello world"}]}}],"usageMetadata":{"promptTokenCount":10,"candidatesTokenCount":5}}}`)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = unwrapV1InternalResponseOld(body)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkUnwrapV1Internal_New_Small(b *testing.B) {
|
||||
body := []byte(`{"response":{"candidates":[{"content":{"parts":[{"text":"hello world"}]}}],"usageMetadata":{"promptTokenCount":10,"candidatesTokenCount":5}}}`)
|
||||
svc := &AntigravityGatewayService{}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = svc.unwrapV1InternalResponse(body)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkUnwrapV1Internal_Old_Large(b *testing.B) {
|
||||
body := generateLargeUnwrapJSON(10 * 1024) // ~10KB
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = unwrapV1InternalResponseOld(body)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkUnwrapV1Internal_New_Large(b *testing.B) {
|
||||
body := generateLargeUnwrapJSON(10 * 1024) // ~10KB
|
||||
svc := &AntigravityGatewayService{}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = svc.unwrapV1InternalResponse(body)
|
||||
}
|
||||
}
|
||||
|
||||
// generateLargeUnwrapJSON 生成指定最小大小的包含 response 包装的 JSON
|
||||
func generateLargeUnwrapJSON(minSize int) []byte {
|
||||
parts := make([]map[string]string, 0)
|
||||
current := 0
|
||||
for current < minSize {
|
||||
text := fmt.Sprintf("这是第 %d 段内容,用于填充 JSON 到目标大小。", len(parts)+1)
|
||||
parts = append(parts, map[string]string{"text": text})
|
||||
current += len(text) + 20 // 估算 JSON 编码开销
|
||||
}
|
||||
inner := map[string]any{
|
||||
"candidates": []map[string]any{
|
||||
{"content": map[string]any{"parts": parts}},
|
||||
},
|
||||
"usageMetadata": map[string]any{
|
||||
"promptTokenCount": 100,
|
||||
"candidatesTokenCount": 50,
|
||||
},
|
||||
}
|
||||
outer := map[string]any{"response": inner}
|
||||
b, _ := json.Marshal(outer)
|
||||
return b
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user