perf(queue): 限制大媒体任务内存并消除准入惊群

将同步与异步非文本任务的准入唤醒改为按任务和全局队首推进,批量续租等待者,避免大量请求同时争抢 advisory lock 和数据库连接。

对 Base64 请求解析、素材解码、上游媒体执行和结果物化增加分层并发限制,复用请求素材并释放重复 Gemini wire 数据;生产 API 默认入口解析并发 16,媒体物化并发 8。

新增 1000 个同步 Gemini 图像编辑请求的模拟上游压力验收,10 MiB 输入和输出下全部成功,Heap 峰值增长约 2.58 GiB,并验证共享上传哈希、单次 attempt 与本地零落盘。

验证:go test ./... -count=1;go vet ./...;gofmt -l 无输出;kubectl kustomize deploy/kubernetes/production;10 MiB Gemini Base64 千任务压力测试通过。
This commit is contained in:
2026-07-30 13:13:32 +08:00
parent fd3b6bf042
commit ea58d21d03
26 changed files with 1980 additions and 74 deletions
+16 -5
View File
@@ -65,12 +65,14 @@ func decodeHTTPResponseForProtocol(resp *http.Response, protocol string) (map[st
Protocol: strings.TrimSpace(protocol),
StatusCode: resp.StatusCode,
Headers: compatibleResponseHeaders(resp.Header),
RawJSON: append([]byte(nil), raw...),
}
if len(raw) > 0 {
_ = json.Unmarshal(raw, &wire.Body)
// raw is already owned by this response. Reusing it avoids retaining a
// second copy of media responses that may be as large as 128 MiB.
RawJSON: raw,
}
if readErr != nil {
if len(raw) > 0 {
_ = json.Unmarshal(raw, &wire.Body)
}
return nil, wire, &ClientError{
Code: "response_read_error",
Message: readErr.Error(),
@@ -81,6 +83,9 @@ func decodeHTTPResponseForProtocol(resp *http.Response, protocol string) (map[st
}
}
if tooLarge {
if len(raw) > 0 {
_ = json.Unmarshal(raw, &wire.Body)
}
return nil, wire, &ClientError{
Code: "response_too_large",
Message: fmt.Sprintf("upstream JSON response exceeds %d bytes", maxBytes),
@@ -91,6 +96,9 @@ func decodeHTTPResponseForProtocol(resp *http.Response, protocol string) (map[st
}
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
if len(raw) > 0 {
_ = json.Unmarshal(raw, &wire.Body)
}
return nil, wire, &ClientError{
Code: statusCodeName(resp.StatusCode),
Message: errorMessage(raw, resp.Status),
@@ -108,7 +116,10 @@ func decodeHTTPResponseForProtocol(resp *http.Response, protocol string) (map[st
if err := json.Unmarshal(raw, &out); err != nil {
return nil, wire, &ClientError{Code: "invalid_response", Message: err.Error(), StatusCode: resp.StatusCode, Retryable: false, Wire: wire}
}
wire.Body = cloneBody(out)
// Result and wire metadata are read-only until the runner replaces the
// canonical result, so they can share the decoded object instead of keeping
// another full copy of a large Base64 media response.
wire.Body = out
return out, wire, nil
}