CPU 花在了哪里?
大请求体的重复 JSON 处理是首要热点
两台生产 Pod 的 CPU profile 给出一致证据:输入预处理与诊断摘要值得优先优化。当前内存容量有余量,GC 不是本次采样中最大的 CPU 消耗项。
2 × 30s CPU · 1 × 30s 分配增量 · 5 天趋势01 / 结论与证据边界
生产 profile 已证明这些函数消耗大量 CPU;具体节省比例必须通过修改后的基准与生产对照验证,不能把热点占比直接当成可节省比例。
已验证
- 当前更接近 CPU 的 HPA 目标,内存容量没有成为主要约束。
- 两台 Pod 的 JSON 扫描热点一致,输入准备路径约占 46–50% 的累计 CPU。
- 诊断摘要会扫描完整请求体;正常 LLM 字段会触发元数据解析的 fallback。
- 30 秒采样分配约 7.52 GiB,主要来自解码缓冲、RawMessage 复制及协议序列化。
尚未证明
- 哪次发布造成了过去 5 天单位成本上涨。
- 上述热点中有多少可以安全消除;本次未实施代码优化。
- GC 的完整总占比:5.4% 指后台标记路径,不包含所有 GC assist / sweep 成本。
- 所有模型和流量时段都具有相同热点占比。
02 / CPU 与内存容量
资源快照:北京时间 2026-10-21 20:06,15 个 Pod;CPU 为最近 5 分钟平均。
| 每 Pod 指标 | 平均使用 | 最高使用 | HPA 目标 | 硬上限 |
|---|---|---|---|---|
| CPU | 1.11 核 | 1.24 核 | 1.20 核 | 4 核 |
| 内存 working set | 0.78 GiB | 1.07 GiB | 2 GiB | 4 GiB |
CPU 平均使用量约为 HPA 目标的 93%;内存约为目标的 39%。CPU 目标来自 request 1.5 核 × 80%;内存目标来自 request 2 GiB × 100%。HPA 按整体利用率决策,并非某一个 Pod 到达阈值就立即扩容。
当前 throttled period 比例每 Pod 为 0–0.17%。过去 5 天全体 CPU 的 5 分钟均值最高约 22.8 核,throttled period 比例最高约 10.2%(不是损失 CPU 时间占比)。单容器内存观测峰值 2.71 GiB;OOM 原因指标无返回记录,不等同于证明历史从未 OOM。
03 / 最近 5 天:工作量不能完全解释成本增长
首个窗口 = 100;悬停圆点查看指数。
请求量 +149%,CPU +205%
单位 LLM 请求 CPU:201 → 246 ms(+22%)。单位总 Token CPU:1.17 → 1.48 秒/百万(+26%)。
单独按输出归一化:189 → 264 秒/百万输出 Token(+40%)。输入 Token 占总量超过 99%,总 TPM 更接近输入侧工作量,但缓存 Token 数仍不等同于实际 JSON 字节数。
| 窗口结束 | LLM 请求/s | 总 TPM / 百万 | CPU 核 | CPU ms/请求 | CPU s/百万 Token | 内存 GiB | 分配 MB/请求 |
|---|---|---|---|---|---|---|---|
| 10/17 | 21.46 | 220.9 | 4.31 | 201 | 1.17 | 4.39 | 41.6 |
| 10/18 | 35.15 | 369.9 | 7.57 | 215 | 1.23 | 6.38 | 47.8 |
| 10/19 | 36.47 | 395.0 | 8.63 | 237 | 1.31 | 7.69 | 53.5 |
| 10/20 | 31.61 | 333.4 | 7.57 | 240 | 1.36 | 7.02 | 50.0 |
| 10/21 | 53.45 | 532.7 | 13.13 | 246 | 1.48 | 10.41 | 50.6 |
每行是截至当天 20:06 的前 24 小时。小时级 rate[1h] 取 24 个非重叠窗口,先汇总分子分母再相除;内存为小时快照均值。所有曲线覆盖 121 个点,无缺失。LLM 请求是开始的逻辑模型调用;Token 在结束时记账,窗口边界可能有错位。全体 Link CPU 包含后台工作和非 LLM 开销,因此这是摊销成本,不是独占 LLM 的函数计时。
接口限定 /v1/chat/completions、/v1/responses、/v1/messages。总 Token = input_total + output,input_total 已含缓存读写,未重复叠加子分类。完成请求计数的长窗口查询返回 502,因此采用已验证的 started counter;HTTP LLM 接口计数另行查询作交叉核对。
下载归一化数据04 / 生产 CPU profile:两台 Pod 交叉验证
版本 f5f2e15a3f0d63229c5e50b9841d333f6ff2d06e;Go build ID a0e9f56ca6f682f9942261fa425ac2ac2557cc95。使用已有 loopback pprof,通过临时端口转发采集;未修改生产配置、未重启 Pod,转发已关闭。
| 样本 | Pod 尾缀 | 开始时间(北京时间) | 时长 | 采样 CPU 时间 |
|---|---|---|---|---|
| A | 8cb4j | 20:17:01 | 30 秒 | 28.82 秒(约 0.96 核) |
| B | j4qk2 | 20:18:38 | 30 秒 | 35.66 秒(约 1.19 核) |
20:19 附近的 5 分钟指标显示,两台 Pod 约 5.1 / 5.0 LLM 请求/s,输入约 88.2 万 / 81.2 万 Token/s,输出约 4516 / 4508 Token/s。它们是采样附近的流量背景,并非精确 30 秒窗口的计数。
JSON Unmarshal 累计占比为 52.7% / 55.3%;Decoder.Decode 为 19.3% / 20.6%。这些入口也不应直接相加。相比之下,streamBifrost 约 3.9–4.9%,所以本次证据不支持首先调整流式 Flush。
05 / 三个具体优化方向
消除元数据提取的重复整包解析 优先验证
prepareRequest 的目标结构只有 model、provider_id、stream,却调用 DisallowUnknownFields()。正常请求包含 messages、tools 或 input,于是走 map[string]any fallback,再解析一次全部内容。
源码行级 profile:A 的第一次解码 2.17s,fallback 1.80s;合计 13.8%。B 分别为 2.60s、2.07s;合计 13.1%。这是整条双解析路径的成本,不能假设全部都可消除。
方向:一次提取所需元数据,避免为无关 messages/tools 构造通用对象树。必须保留字段类型、重复键、null、非法 JSON、尾随内容与错误响应的兼容语义;不能仅删一行后直接上线。
诊断摘要复用字段,减少大字段扫描与复制 ≈19% CPU
thinkingdiag.Summarize 为读取少量 thinking/reasoning 控制字段,将整个 body 解码成 map[string]json.RawMessage。RawMessage 避免构建全部对象树,但仍需扫描并复制大字段。Inbound、Normalized、Outbound 会重复执行这一工作。
CPU 为 19.0% / 18.7%;分配增量约 605 MiB(7.86%)。方向:复用已有解析结果,或者只提取白名单字段;避免为了诊断复制 messages/tools。若采用采样,需明确丢失哪些诊断覆盖,不能静默削弱错误分析能力。
合并请求规范化与适配步骤 后续结构优化
prepareTargetBody 累计 CPU 18–21%,newChatRequest 14–17%。分配 profile 中,两条路径各占约 17.7%(与其它累计路径存在重叠)。
方向:共享解析后的请求表示,合并 reasoning/default/compatibility 处理,在必要边界才序列化。优先修改 Link internal;若确需改 vendored Bifrost,按仓库要求记录补丁原因、验证和维护方案。
不要首先用增大 GOMEMLIMIT、放宽 HPA 或全局替换 JSON 库代替消除重复工作。
06 / 分配证据与验证计划
Pod A 的 allocs?seconds=30 增量 profile:实际时长 30.17 秒,采样估算分配约 7.52 GiB,约 255 MiB/s。这是累计分配量,不是活跃 heap,也不代表泄漏。分配数据有采样误差与 GC 记账滞后。
| 直接分配位置(flat) | 分配占比 |
|---|---|
| encoding/json.Decoder.refill | 19.53% |
| json.RawMessage.UnmarshalJSON | 15.90% |
| sonic.frozenConfig.Unmarshal | 12.41% |
| sonic EncodeJsonMarshaler | 7.37% |
| bytes.growSlice | 6.81% |
| io.ReadAll | 6.09% |
- 构造不同体积的合成请求:小请求、长上下文、工具 schema、Responses/Messages,建立处理吞吐与 allocs/op 基线。
- 先修复元数据双解析和诊断摘要重复扫描;分别测试,确认 CPU/op、bytes/op 改善。
- 验证错误语义、reasoning 转换、工具调用、流式中断、计费结果和诊断白名单保持正确。
- 用同版本、同模型构成、相近请求大小的对照流量验证 CPU/请求、CPU/输入字节、TTFT、错误率及分配率,再评估容量收益。
附录 / 可复核证据
源码分析已使用生产镜像对应提交,而非工作区未提交版本。以下是符号化摘要,不包含请求内容、凭据或原始 heap 转储。CPU 占比均相对于对应样本总 CPU 时间。
CPU 样本 A · flat 排名
File: gateway
Build ID: a0e9f56ca6f682f9942261fa425ac2ac2557cc95
Type: cpu
Time: 2026-10-21 20:17:01 CST
Duration: 30s, Total samples = 28.82s (96.06%)
Showing nodes accounting for 24.46s, 84.87% of 28.82s total
Dropped 746 nodes (cum <= 0.14s)
flat flat% sum% cum cum%
5.48s 19.01% 19.01% 5.52s 19.15% encoding/json.stateInString
5.04s 17.49% 36.50% 6.93s 24.05% encoding/json.checkValid
4.58s 15.89% 52.39% 7.48s 25.95% encoding/json.(*decodeState).skip
1.78s 6.18% 58.57% 3.34s 11.59% encoding/json.(*Decoder).readValue
1.58s 5.48% 64.05% 1.58s 5.48% internal/runtime/syscall/linux.Syscall6
1.32s 4.58% 68.63% 1.32s 4.58% runtime.memmove
0.61s 2.12% 70.75% 1.01s 3.50% encoding/json.unquoteBytes
0.49s 1.70% 72.45% 0.49s 1.70% runtime.memclrNoHeapPointers
0.38s 1.32% 73.77% 0.38s 1.32% runtime.futex
0.37s 1.28% 75.05% 0.40s 1.39% encoding/json.(*decodeState).rescanLiteral
0.34s 1.18% 76.23% 0.60s 2.08% encoding/json.appendCompact
0.25s 0.87% 77.10% 0.25s 0.87% runtime.madvise
0.24s 0.83% 77.93% 0.27s 0.94% unicode/utf8.DecodeRune (inline)
0.16s 0.56% 78.49% 0.28s 0.97% runtime.tryDeferToSpanScan
0.15s 0.52% 79.01% 0.21s 0.73% encoding/json.stateInStringEsc
0.15s 0.52% 79.53% 0.26s 0.9% runtime.scanObjectsSmall
0.13s 0.45% 79.98% 0.26s 0.9% encoding/json.stateEndValue
0.13s 0.45% 80.43% 0.20s 0.69% runtime.(*unwinder).resolveInternal
0.11s 0.38% 80.81% 0.70s 2.43% encoding/json.structEncoder.encode
0.10s 0.35% 81.16% 0.19s 0.66% runtime.pcvalue
0.06s 0.21% 81.37% 1.03s 3.57% decode_
0.06s 0.21% 81.58% 0.19s 0.66% runtime.mapassign_faststr
0.06s 0.21% 81.78% 0.77s 2.67% runtime.markroot
0.06s 0.21% 81.99% 0.15s 0.52% runtime.wbBufFlush1
0.05s 0.17% 82.17% 0.49s 1.70% runtime.mallocgcSmallScanNoHeader
0.05s 0.17% 82.34% 0.23s 0.8% runtime.scanObject
0.05s 0.17% 82.51% 0.16s 0.56% runtime.scanblock
0.04s 0.14% 82.65% 0.29s 1.01% runtime.mallocgcSmallNoscan
0.03s 0.1% 82.76% 1.19s 4.13% runtime.mallocgc
0.03s 0.1% 82.86% 0.40s 1.39% runtime.scanSpan
0.03s 0.1% 82.96% 0.29s 1.01% runtime.selectgo
0.02s 0.069% 83.03% 0.59s 2.05% encode_struct { *openai.Alias; Messages [...]schemas.ChatTool "json:\"tools,omitempty\""; Reasoning *schemas.ChatReasoning "json:\"reasoning,omitempty\""; ReasoningEffort *string "json:\"reasoning_effort,omitempty\"" }
0.02s 0.069% 83.10% 0.16s 0.56% gcWriteBarrier
0.02s 0.069% 83.17% 1.41s 4.89% github.com/nexu-io/vela/services/link/internal/handlers.(*OpenAIHandler).streamBifrost
0.02s 0.069% 83.24% 0.25s 0.87% runtime.(*mcache).refill
0.02s 0.069% 83.31% 0.18s 0.62% runtime.(*mcentral).cacheSpan
0.02s 0.069% 83.38% 0.58s 2.01% runtime.findRunnable
0.02s 0.069% 83.45% 0.36s 1.25% runtime.makeslice
0.02s 0.069% 83.52% 0.31s 1.08% runtime.netpoll
0.02s 0.069% 83.59% 0.25s 0.87% runtime.newobject
0.02s 0.069% 83.66% 0.64s 2.22% runtime.scanstack
0.02s 0.069% 83.73% 0.64s 2.22% runtime.schedule
0.02s 0.069% 83.80% 0.51s 1.77% runtime.slicebytetostring
0.01s 0.035% 83.83% 0.63s 2.19% bytes.(*Buffer).ReadFrom
0.01s 0.035% 83.87% 0.16s 0.56% bytes.(*Buffer).grow
0.01s 0.035% 83.90% 0.71s 2.46% crypto/tls.(*Conn).Read
0.01s 0.035% 83.93% 0.68s 2.36% crypto/tls.(*Conn).readRecordOrCCS
0.01s 0.035% 83.97% 0.42s 1.46% encode_schemas.Alias
0.01s 0.035% 84.00% 0.52s 1.80% encode_schemas.ChatToolFunction
0.01s 0.035% 84.04% 0.25s 0.87% encoding/json.(*Decoder).Token
0.01s 0.035% 84.07% 1.69s 5.86% encoding/json.(*decodeState).arrayInterface
0.01s 0.035% 84.11% 0.97s 3.37% github.com/bytedance/sonic.frozenConfig.Marshal
0.01s 0.035% 84.14% 1.06s 3.68% github.com/bytedance/sonic/internal/decoder/api.(*Decoder).Decode
0.01s 0.035% 84.18% 1.06s 3.68% github.com/bytedance/sonic/internal/decoder/jitdec.Decode
0.01s 0.035% 84.21% 0.82s 2.85% github.com/bytedance/sonic/internal/decoder/jitdec.decodeJsonUnmarshaler
0.01s 0.035% 84.25% 1.04s 3.61% github.com/bytedance/sonic/internal/decoder/jitdec.decodeTypedPointer
0.01s 0.035% 84.28% 0.77s 2.67% github.com/go-chi/chi/v5/middleware.(*httpFancyWriter).Flush
0.01s 0.035% 84.32% 1.62s 5.62% github.com/maximhq/bifrost/core/providers/openai.HandleOpenAIChatCompletionStreaming.func2
0.01s 0.035% 84.35% 0.31s 1.08% github.com/maximhq/bifrost/core/providers/utils.ProcessAndSendResponse
0.01s 0.035% 84.39% 0.80s 2.78% internal/poll.(*FD).Write
0.01s 0.035% 84.42% 0.81s 2.81% net.(*conn).Write
0.01s 0.035% 84.46% 0.69s 2.39% net/http/internal.(*chunkedReader).Read
0.01s 0.035% 84.49% 0.28s 0.97% runtime.(*mcache).nextFree
0.01s 0.035% 84.52% 0.17s 0.59% runtime.(*unwinder).next
0.01s 0.035% 84.56% 0.29s 1.01% runtime.futexwakeup
0.01s 0.035% 84.59% 0.37s 1.28% runtime.growslice
0.01s 0.035% 84.63% 0.70s 2.43% runtime.markroot.func1
0.01s 0.035% 84.66% 0.30s 1.04% runtime.notewakeup
0.01s 0.035% 84.70% 0.63s 2.19% runtime.park_m
0.01s 0.035% 84.73% 0.19s 0.66% runtime.ready
0.01s 0.035% 84.77% 0.26s 0.9% runtime.scanframeworker
0.01s 0.035% 84.80% 0.22s 0.76% runtime.startm
0.01s 0.035% 84.84% 0.17s 0.59% runtime.stealWork
0.01s 0.035% 84.87% 1.30s 4.51% syscall.RawSyscall6
0 0% 84.87% 0.68s 2.36% bufio.(*Reader).ReadSlice
0 0% 84.87% 0.68s 2.36% bufio.(*Reader).fill
0 0% 84.87% 0.72s 2.50% bufio.(*Scanner).Scan
0 0% 84.87% 0.79s 2.74% bufio.(*Writer).Flush
0 0% 84.87% 0.63s 2.19% crypto/tls.(*Conn).readFromUntil
0 0% 84.87% 0.68s 2.36% crypto/tls.(*Conn).readRecord (inline)
0 0% 84.87% 0.62s 2.15% crypto/tls.(*atLeastReader).Read
0 0% 84.87% 0.52s 1.80% encode_*schemas.Alias
0 0% 84.87% 0.34s 1.18% encode_*schemas.OrderedMap
0 0% 84.87% 5.57s 19.33% encoding/json.(*Decoder).Decode
0 0% 84.87% 0.44s 1.53% encoding/json.(*Decoder).refill
0 0% 84.87% 0.39s 1.35% encoding/json.(*RawMessage).UnmarshalJSON
0 0% 84.87% 7.97s 27.65% encoding/json.(*decodeState).array
0 0% 84.87% 1.46s 5.07% encoding/json.(*decodeState).literalInterface
0 0% 84.87% 9.78s 33.93% encoding/json.(*decodeState).object
0 0% 84.87% 1.66s 5.76% encoding/json.(*decodeState).objectInterface
0 0% 84.87% 10.45s 36.26% encoding/json.(*decodeState).unmarshal
0 0% 84.87% 10.45s 36.26% encoding/json.(*decodeState).value
0 0% 84.87% 1.66s 5.76% encoding/json.(*decodeState).valueInterface
0 0% 84.87% 0.98s 3.40% encoding/json.(*encodeState).marshal
0 0% 84.87% 0.97s 3.37% encoding/json.(*encodeState).reflectValue
0 0% 84.87% 0.28s 0.97% encoding/json.Compact
0 0% 84.87% 1.05s 3.64% encoding/json.Marshal
0 0% 84.87% 15.19s 52.71% encoding/json.Unmarshal
0 0% 84.87% 0.43s 1.49% encoding/json.addrMarshalerEncoder
0 0% 84.87% 0.63s 2.19% encoding/json.arrayEncoder.encode
0 0% 84.87% 0.61s 2.12% encoding/json.condAddrEncoder.encode
0 0% 84.87% 0.26s 0.9% encoding/json.mapEncoder.encode
0 0% 84.87% 0.25s 0.87% encoding/json.marshalerEncoder
0 0% 84.87% 0.24s 0.83% encoding/json.ptrEncoder.encode
0 0% 84.87% 0.63s 2.19% encoding/json.sliceEncoder.encode
0 0% 84.87% 1.09s 3.78% encoding/json.unquote (inline)
0 0% 84.87% 1s 3.47% github.com/bytedance/sonic.Unmarshal (inline)
0 0% 84.87% 0.39s 1.35% github.com/bytedance/sonic.UnmarshalString (inline)
0 0% 84.87% 1s 3.47% github.com/bytedance/sonic.frozenConfig.Unmarshal
0 0% 84.87% 1.07s 3.71% github.com/bytedance/sonic.frozenConfig.UnmarshalFromString
0 0% 84.87% 0.97s 3.37% github.com/bytedance/sonic/internal/encoder.Encode
0 0% 84.87% 0.96s 3.33% github.com/bytedance/sonic/internal/encoder.encodeInto
0 0% 84.87% 0.96s 3.33% github.com/bytedance/sonic/internal/encoder.encodeIntoCheckRace (inline)
0 0% 84.87% 0.28s 0.97% github.com/bytedance/sonic/internal/encoder/prim.Compact
0 0% 84.87% 0.81s 2.81% github.com/bytedance/sonic/internal/encoder/prim.EncodeJsonMarshaler
0 0% 84.87% 0.96s 3.33% github.com/bytedance/sonic/internal/encoder/x86.EncodeTypedPointer
0 0% 84.87% 15.15s 52.57% github.com/go-chi/chi/v5.(*ChainHandler).ServeHTTP
0 0% 84.87% 15.15s 52.57% github.com/go-chi/chi/v5.(*Mux).Mount.func1
0 0% 84.87% 15.18s 52.67% github.com/go-chi/chi/v5.(*Mux).ServeHTTP
0 0% 84.87% 15.16s 52.60% github.com/go-chi/chi/v5.(*Mux).routeHTTP
0 0% 84.87% 15.13s 52.50% github.com/go-chi/chi/v5/middleware.RealIP.func1
0 0% 84.87% 15.15s 52.57% github.com/go-chi/chi/v5/middleware.Recoverer.func1
0 0% 84.87% 15.13s 52.50% github.com/go-chi/chi/v5/middleware.RequestID.func1
0 0% 84.87% 4.06s 14.09% github.com/maximhq/bifrost/core.(*Bifrost).handleProviderStreamRequest
0 0% 84.87% 4.15s 14.40% github.com/maximhq/bifrost/core.(*Bifrost).requestWorker
0 0% 84.87% 4.05s 14.05% github.com/maximhq/bifrost/core.(*Bifrost).requestWorker.func3
0 0% 84.87% 4.06s 14.09% github.com/maximhq/bifrost/core.executeRequestWithRetries[go.shape.chan *github.com/maximhq/bifrost/core/schemas.BifrostStreamChunk]
0 0% 84.87% 0.57s 1.98% github.com/maximhq/bifrost/core/providers/openai.(*OpenAIChatRequest).MarshalJSON
0 0% 84.87% 0.64s 2.22% github.com/maximhq/bifrost/core/providers/openai.(*OpenAIChatRequest).UnmarshalJSON
0 0% 84.87% 3.99s 13.84% github.com/maximhq/bifrost/core/providers/openai.(*OpenAIProvider).ChatCompletionStream
0 0% 84.87% 4.08s 14.16% github.com/maximhq/bifrost/core/providers/openai.HandleOpenAIChatCompletionStreaming
0 0% 84.87% 1.86s 6.45% github.com/maximhq/bifrost/core/providers/openai.doOpenAICompatibleStreamingRequest
0 0% 84.87% 0.69s 2.39% github.com/maximhq/bifrost/core/providers/utils.(*chunkedBody).Read
0 0% 84.87% 0.76s 2.64% github.com/maximhq/bifrost/core/providers/utils.(*defaultSSEDataReader).ReadDataLine
0 0% 84.87% 0.71s 2.46% github.com/maximhq/bifrost/core/providers/utils.(*idleTimeoutReader).Read
0 0% 84.87% 0.69s 2.39% github.com/maximhq/bifrost/core/providers/utils.(*streamBody).Read
0 0% 84.87% 2.25s 7.81% github.com/maximhq/bifrost/core/providers/utils.CheckContextAndGetRequestBody
0 0% 84.87% 1.86s 6.45% github.com/maximhq/bifrost/core/providers/utils.DoStreamingRequest
0 0% 84.87% 0.56s 1.94% github.com/maximhq/bifrost/core/providers/utils.MarshalProviderRequest
0 0% 84.87% 0.58s 2.01% github.com/maximhq/bifrost/core/providers/utils.MarshalSorted (inline)
0 0% 84.87% 1.65s 5.73% github.com/maximhq/bifrost/core/providers/utils.MergeExtraParamsIntoJSON
0 0% 84.87% 0.16s 0.56% github.com/maximhq/bifrost/core/schemas.(*BifrostContext).Value
0 0% 84.87% 0.37s 1.28% github.com/maximhq/bifrost/core/schemas.(*ChatParameters).UnmarshalJSON
0 0% 84.87% 0.20s 0.69% github.com/maximhq/bifrost/core/schemas.(*ChatStreamResponseChoiceDelta).UnmarshalJSON
0 0% 84.87% 0.29s 1.01% github.com/maximhq/bifrost/core/schemas.(*ChatTool).UnmarshalJSON
0 0% 84.87% 0.15s 0.52% github.com/maximhq/bifrost/core/schemas.(*OrderedMap).UnmarshalJSON
0 0% 84.87% 0.28s 0.97% github.com/maximhq/bifrost/core/schemas.(*ToolFunctionParameters).UnmarshalJSON
0 0% 84.87% 0.54s 1.87% github.com/maximhq/bifrost/core/schemas.ChatTool.MarshalJSON
0 0% 84.87% 0.71s 2.46% github.com/maximhq/bifrost/core/schemas.MarshalSorted (inline)
0 0% 84.87% 1.83s 6.35% github.com/maximhq/bifrost/core/schemas.ObserveProviderRequestBody
0 0% 84.87% 0.37s 1.28% github.com/maximhq/bifrost/core/schemas.OrderedMap.MarshalJSON
0 0% 84.87% 0.48s 1.67% github.com/maximhq/bifrost/core/schemas.ToolFunctionParameters.MarshalJSON
0 0% 84.87% 0.77s 2.67% github.com/maximhq/bifrost/core/schemas.Unmarshal (inline)
0 0% 84.87% 0.15s 0.52% github.com/maximhq/bifrost/core/schemas.normalizeSingleReasoningDetails
0 0% 84.87% 4.06s 14.09% github.com/nexu-io/vela/services/link/internal/bifrostengine.(*BifrostEngine).ChatCompletionStream
0 0% 84.87% 0.19s 0.66% github.com/nexu-io/vela/services/link/internal/bifrostengine.(*BifrostEngine).MessagesStream
0 0% 84.87% 0.17s 0.59% github.com/nexu-io/vela/services/link/internal/bifrostengine.(*BifrostEngine).Responses
0 0% 84.87% 0.48s 1.67% github.com/nexu-io/vela/services/link/internal/bifrostengine.(*BifrostEngine).ResponsesStream
0 0% 84.87% 0.53s 1.84% github.com/nexu-io/vela/services/link/internal/bifrostengine.enablePromptCachingChat
0 0% 84.87% 0.15s 0.52% github.com/nexu-io/vela/services/link/internal/bifrostengine.enablePromptCachingResponses
0 0% 84.87% 4.07s 14.12% github.com/nexu-io/vela/services/link/internal/bifrostengine.newChatRequest
0 0% 84.87% 0.64s 2.22% github.com/nexu-io/vela/services/link/internal/bifrostengine.newResponsesRequest
0 0% 84.87% 0.16s 0.56% github.com/nexu-io/vela/services/link/internal/bifrostengine.normalizeChatReasoningAlias
0 0% 84.87% 0.37s 1.28% github.com/nexu-io/vela/services/link/internal/bifrostengine.normalizeChatStop
0 0% 84.87% 0.68s 2.36% github.com/nexu-io/vela/services/link/internal/bifrostengine.promptCacheKey
0 0% 84.87% 1.06s 3.68% github.com/nexu-io/vela/services/link/internal/bifrostengine.validateDeepSeekChatCustomTools
0 0% 84.87% 0.16s 0.56% github.com/nexu-io/vela/services/link/internal/handlers.(*OpenAIHandler).admitProviderRequest
0 0% 84.87% 11.74s 40.74% github.com/nexu-io/vela/services/link/internal/handlers.(*OpenAIHandler).handleChatCompletions
0 0% 84.87% 4.06s 14.09% github.com/nexu-io/vela/services/link/internal/handlers.(*OpenAIHandler).handleChatCompletions.func1
0 0% 84.87% 0.49s 1.70% github.com/nexu-io/vela/services/link/internal/handlers.(*OpenAIHandler).handleMessages
0 0% 84.87% 2.83s 9.82% github.com/nexu-io/vela/services/link/internal/handlers.(*OpenAIHandler).handleResponses
0 0% 84.87% 0.48s 1.67% github.com/nexu-io/vela/services/link/internal/handlers.(*OpenAIHandler).handleResponses.func1
0 0% 84.87% 13.24s 45.94% github.com/nexu-io/vela/services/link/internal/handlers.(*OpenAIHandler).prepareRequest
0 0% 84.87% 0.19s 0.66% github.com/nexu-io/vela/services/link/internal/handlers.(*OpenAIHandler).streamAnthropicMessages.func1
0 0% 84.87% 0.16s 0.56% github.com/nexu-io/vela/services/link/internal/handlers.(*admissionPipeline).Admit
0 0% 84.87% 1.89s 6.56% github.com/nexu-io/vela/services/link/internal/handlers.applyPublicModelReasoningEffort
0 0% 84.87% 4.73s 16.41% github.com/nexu-io/vela/services/link/internal/handlers.awaitStreamEstablishment[go.shape.*uint8].func1
0 0% 84.87% 1.58s 5.48% github.com/nexu-io/vela/services/link/internal/handlers.normalizeRequestBody
0 0% 84.87% 5.23s 18.15% github.com/nexu-io/vela/services/link/internal/handlers.prepareTargetBody
0 0% 84.87% 0.25s 0.87% github.com/nexu-io/vela/services/link/internal/handlers.requestLogSummary
0 0% 84.87% 1.76s 6.11% github.com/nexu-io/vela/services/link/internal/providercompat.Adapter.PrepareDefaultReasoning
0 0% 84.87% 4.06s 14.09% github.com/nexu-io/vela/services/link/internal/runtimeconfig.(*leasedEngine).ChatCompletionStream
0 0% 84.87% 0.19s 0.66% github.com/nexu-io/vela/services/link/internal/runtimeconfig.(*leasedEngine).MessagesStream
0 0% 84.87% 0.17s 0.59% github.com/nexu-io/vela/services/link/internal/runtimeconfig.(*leasedEngine).Responses
0 0% 84.87% 0.48s 1.67% github.com/nexu-io/vela/services/link/internal/runtimeconfig.(*leasedEngine).ResponsesStream
0 0% 84.87% 15.13s 52.50% github.com/nexu-io/vela/services/link/internal/server.newRouter.ServerRequestMiddleware.func5.1
0 0% 84.87% 15.16s 52.60% github.com/nexu-io/vela/services/link/internal/server.newRouter.Timeout.func6.1
0 0% 84.87% 15.16s 52.60% github.com/nexu-io/vela/services/link/internal/server.newRouter.accessLog.func7.1
0 0% 84.87% 15.15s 52.57% github.com/nexu-io/vela/services/link/internal/server.newRouter.func3.Auth.1.1
0 0% 84.87% 15.08s 52.32% github.com/nexu-io/vela/services/link/internal/server.newRouter.func3.metrics.2.1
0 0% 84.87% 15.16s 52.60% github.com/nexu-io/vela/services/link/internal/server.newRouter.rejectNewRequestsWhileDraining.func8.1
0 0% 84.87% 15.10s 52.39% github.com/nexu-io/vela/services/link/internal/server.normalizeClientRequestID.func1
0 0% 84.87% 1.76s 6.11% github.com/nexu-io/vela/services/link/internal/thinkingdiag.(*Collector).Normalized
0 0% 84.87% 1.83s 6.35% github.com/nexu-io/vela/services/link/internal/thinkingdiag.(*Collector).ObserveProviderRequestBody
0 0% 84.87% 1.87s 6.49% github.com/nexu-io/vela/services/link/internal/thinkingdiag.New
0 0% 84.87% 5.47s 18.98% github.com/nexu-io/vela/services/link/internal/thinkingdiag.Summarize
0 0% 84.87% 0.66s 2.29% internal/poll.(*FD).Read
0 0% 84.87% 1.43s 4.96% internal/poll.ignoringEINTRIO (inline)
0 0% 84.87% 0.29s 1.01% internal/runtime/syscall/linux.EpollWait
0 0% 84.87% 0.66s 2.29% net.(*conn).Read
0 0% 84.87% 0.66s 2.29% net.(*netFD).Read
0 0% 84.87% 0.80s 2.78% net.(*netFD).Write
0 0% 84.87% 0.76s 2.64% net/http.(*chunkWriter).flush
0 0% 84.87% 15.03s 52.15% net/http.(*conn).serve
0 0% 84.87% 0.76s 2.64% net/http.(*response).Flush
0 0% 84.87% 0.76s 2.64% net/http.(*response).FlushError
0 0% 84.87% 15.18s 52.67% net/http.HandlerFunc.ServeHTTP
0 0% 84.87% 0.76s 2.64% net/http.checkConnErrorWriter.Write
0 0% 84.87% 15.03s 52.15% net/http.serverHandler.ServeHTTP
0 0% 84.87% 0.68s 2.36% net/http/internal.(*chunkedReader).beginChunk
0 0% 84.87% 0.68s 2.36% net/http/internal.readChunkLine
0 0% 84.87% 0.27s 0.94% runtime.(*pageAlloc).scavenge
0 0% 84.87% 0.27s 0.94% runtime.(*pageAlloc).scavenge.func1
0 0% 84.87% 0.27s 0.94% runtime.(*pageAlloc).scavengeOne
0 0% 84.87% 0.27s 0.94% runtime.(*scavengerState).init.func2
0 0% 84.87% 0.27s 0.94% runtime.(*scavengerState).run
0 0% 84.87% 0.27s 0.94% runtime.bgscavenge
0 0% 84.87% 1.56s 5.41% runtime.gcBgMarkWorker
0 0% 84.87% 1.51s 5.24% runtime.gcBgMarkWorker.func2
0 0% 84.87% 1.51s 5.24% runtime.gcDrain
0 0% 84.87% 0.73s 2.53% runtime.gcDrainMarkWorkerDedicated (inline)
0 0% 84.87% 0.78s 2.71% runtime.gcDrainMarkWorkerIdle (inline)
0 0% 84.87% 0.19s 0.66% runtime.goready (inline)
0 0% 84.87% 0.28s 0.97% runtime.mallocgcLarge
0 0% 84.87% 0.67s 2.32% runtime.mcall
0 0% 84.87% 0.17s 0.59% runtime.memclrNoHeapPointersChunked
0 0% 84.87% 0.15s 0.52% runtime.send
0 0% 84.87% 0.25s 0.87% runtime.sysUnused (inline)
0 0% 84.87% 0.25s 0.87% runtime.sysUnusedOS
0 0% 84.87% 2.52s 8.74% runtime.systemstack
0 0% 84.87% 0.23s 0.8% runtime.wakep
0 0% 84.87% 0.15s 0.52% runtime.wbBufFlush
0 0% 84.87% 0.15s 0.52% runtime.wbBufFlush.func1
0 0% 84.87% 0.64s 2.22% syscall.Read (inline)
0 0% 84.87% 1.43s 4.96% syscall.Syscall
0 0% 84.87% 0.79s 2.74% syscall.Write (inline)
0 0% 84.87% 0.64s 2.22% syscall.read
0 0% 84.87% 0.79s 2.74% syscall.write
CPU 样本 B · flat 排名
File: gateway
Build ID: a0e9f56ca6f682f9942261fa425ac2ac2557cc95
Type: cpu
Time: 2026-10-21 20:18:38 CST
Duration: 30s, Total samples = 35.66s (118.86%)
Showing nodes accounting for 30.19s, 84.66% of 35.66s total
Dropped 737 nodes (cum <= 0.18s)
Showing top 20 nodes out of 218
flat flat% sum% cum cum%
7.51s 21.06% 21.06% 7.58s 21.26% encoding/json.stateInString
6.31s 17.69% 38.75% 9.11s 25.55% encoding/json.checkValid
5.85s 16.40% 55.16% 9.98s 27.99% encoding/json.(*decodeState).skip
2.52s 7.07% 62.23% 4.24s 11.89% encoding/json.(*Decoder).readValue
1.68s 4.71% 66.94% 1.68s 4.71% internal/runtime/syscall/linux.Syscall6
1.32s 3.70% 70.64% 1.32s 3.70% runtime.memmove
0.98s 2.75% 73.39% 1.54s 4.32% encoding/json.unquoteBytes
0.80s 2.24% 75.63% 1.01s 2.83% encoding/json.appendCompact
0.64s 1.79% 77.43% 0.64s 1.79% runtime.memclrNoHeapPointers
0.51s 1.43% 78.86% 0.53s 1.49% encoding/json.(*decodeState).rescanLiteral
0.44s 1.23% 80.09% 0.47s 1.32% unicode/utf8.DecodeRune (inline)
0.32s 0.9% 80.99% 0.53s 1.49% runtime.tryDeferToSpanScan
0.27s 0.76% 81.74% 0.29s 0.81% encoding/json.stateInStringEsc
0.24s 0.67% 82.42% 0.24s 0.67% runtime.futex
0.22s 0.62% 83.03% 0.22s 0.62% runtime.madvise
0.18s 0.5% 83.54% 0.30s 0.84% runtime.(*unwinder).resolveInternal
0.12s 0.34% 83.88% 0.40s 1.12% runtime.scanObjectsSmall
0.10s 0.28% 84.16% 0.30s 0.84% encoding/json.stateEndValue
0.09s 0.25% 84.41% 1.02s 2.86% decode_
0.09s 0.25% 84.66% 0.29s 0.81% runtime.selectgo
30 秒分配增量 · alloc_space
File: gateway
Build ID: a0e9f56ca6f682f9942261fa425ac2ac2557cc95
Type: alloc_space
Time: 2026-10-21 20:18:22 CST
Duration: 30.17s, Total samples = 7702.92MB
Showing nodes accounting for 7309.14MB, 94.89% of 7702.92MB total
Dropped 493 nodes (cum <= 38.51MB)
Showing top 25 nodes out of 151
flat flat% sum% cum cum%
1504.54MB 19.53% 19.53% 1507.08MB 19.57% encoding/json.(*Decoder).refill
1225.07MB 15.90% 35.44% 1225.07MB 15.90% encoding/json.(*RawMessage).UnmarshalJSON
955.88MB 12.41% 47.85% 1343.75MB 17.44% github.com/bytedance/sonic.frozenConfig.Unmarshal
567.55MB 7.37% 55.21% 1007.31MB 13.08% github.com/bytedance/sonic/internal/encoder/prim.EncodeJsonMarshaler
524.55MB 6.81% 62.02% 524.55MB 6.81% bytes.growSlice
469.18MB 6.09% 68.11% 469.18MB 6.09% io.ReadAll
414.51MB 5.38% 73.50% 648MB 8.41% encoding/json.unquote (inline)
300.71MB 3.90% 77.40% 300.71MB 3.90% github.com/bytedance/sonic/internal/rt.GrowSlice
233.49MB 3.03% 80.43% 233.49MB 3.03% encoding/json.unquoteBytes
212.89MB 2.76% 83.19% 212.89MB 2.76% github.com/bytedance/gopkg/lang/dirtmake.Bytes
164.91MB 2.14% 85.34% 976.11MB 12.67% decode_
155.54MB 2.02% 87.35% 830.04MB 10.78% encoding/json.(*decodeState).objectInterface
136.39MB 1.77% 89.12% 136.39MB 1.77% github.com/valyala/bytebufferpool.(*ByteBuffer).Set
125.74MB 1.63% 90.76% 305.47MB 3.97% encoding/json.Marshal
91.04MB 1.18% 91.94% 316.65MB 4.11% github.com/maximhq/bifrost/core/providers/openai.HandleOpenAIChatCompletionStreaming.func2
57MB 0.74% 92.68% 71.50MB 0.93% encoding/json.(*scanner).error (inline)
46.03MB 0.6% 93.28% 46.03MB 0.6% decode_value
41.02MB 0.53% 93.81% 41.02MB 0.53% github.com/maximhq/bifrost/core/providers/utils.GetBifrostResponseForStreamResponse (inline)
18MB 0.23% 94.04% 118.52MB 1.54% encoding/json.(*Decoder).Token
15.50MB 0.2% 94.24% 119.57MB 1.55% github.com/maximhq/bifrost/core/schemas.(*ChatStreamResponseChoiceDelta).UnmarshalJSON
14.08MB 0.18% 94.43% 835.12MB 10.84% encoding/json.(*decodeState).arrayInterface
14MB 0.18% 94.61% 652.50MB 8.47% encoding/json.(*decodeState).literalInterface
9.50MB 0.12% 94.73% 534.05MB 6.93% bytes.(*Buffer).grow
7MB 0.091% 94.82% 65.99MB 0.86% encoding/json.mapEncoder.encode
5MB 0.065% 94.89% 1134.29MB 14.73% github.com/bytedance/sonic/internal/encoder.encodeInto
源码行级归因 · prepareRequest
Total: 28.82s
ROUTINE ======================== github.com/nexu-io/vela/services/link/internal/handlers.(*OpenAIHandler).prepareRequest in internal/handlers/openai.go
0 13.24s (flat, cum) 45.94% of Total
. . 1464:func (h *OpenAIHandler) prepareRequest(runtime *catalog.Runtime, endpoint string, r *http.Request) ([]byte, requestMeta, domain.Principal, domain.ResolvedModel, *requestError) {
. . 1465: correlationRequestID, _ := requestcorrelation.ClientRequestID(r.Header.Get(requestIDHeader))
. . 1466: requestID := correlationRequestID
. . 1467: if requestID == "" {
. . 1468: requestID = uuid.NewString()
. . 1469: }
. . 1470: meta := requestMeta{RequestID: requestID, ExecutionID: uuid.NewString(), CorrelationRequestID: correlationRequestID, Endpoint: endpoint}
. . 1471:
. . 1472: principal, ok := requestctx.PrincipalFromContext(r.Context())
. . 1473: if !ok {
. . 1474: return nil, meta, domain.Principal{}, domain.ResolvedModel{}, &requestError{status: http.StatusInternalServerError, code: "internal_error", message: "missing authenticated principal"}
. . 1475: }
. . 1476:
. 140ms 1477: body, err := io.ReadAll(io.LimitReader(r.Body, h.maxRequestBodyBytes+1))
. . 1478: if err != nil {
. . 1479: return nil, meta, domain.Principal{}, domain.ResolvedModel{}, &requestError{status: http.StatusBadRequest, code: "invalid_request", message: "failed to read request body", detail: err.Error()}
. . 1480: }
. . 1481: if int64(len(body)) > h.maxRequestBodyBytes {
. . 1482: return nil, meta, domain.Principal{}, domain.ResolvedModel{}, &requestError{status: http.StatusRequestEntityTooLarge, code: "request_too_large", message: "request body exceeds configured limit", rawBody: body}
. . 1483: }
. . 1484:
. . 1485: if endpoint == "/v1/chat/completions" || endpoint == "/v1/responses" || endpoint == anthropicMessagesEndpoint {
. 1.87s 1486: meta.thinking = thinkingdiag.New(body)
. . 1487: }
. . 1488:
. . 1489: var payload struct {
. . 1490: Model string `json:"model"`
. . 1491: ProviderID string `json:"provider_id"`
. . 1492: Stream bool `json:"stream"`
. . 1493: }
. . 1494: decoder := json.NewDecoder(bytes.NewReader(body))
. . 1495: decoder.DisallowUnknownFields()
. 2.17s 1496: if err := decoder.Decode(&payload); err != nil {
. . 1497: var generic map[string]any
. 1.80s 1498: if err2 := json.Unmarshal(body, &generic); err2 != nil {
. . 1499: return nil, meta, domain.Principal{}, domain.ResolvedModel{}, &requestError{status: http.StatusBadRequest, code: "invalid_json", message: "request body must be valid JSON", detail: err.Error(), rawBody: body}
. . 1500: }
. . 1501: model, _ := generic["model"].(string)
. . 1502: providerID, _ := generic["provider_id"].(string)
. . 1503: stream, _ := generic["stream"].(bool)
. . 1504: payload.Model = model
. . 1505: payload.ProviderID = providerID
. . 1506: payload.Stream = stream
. . 1507: }
. . 1508: meta.RequestedModel = payload.Model
. . 1509: meta.RequestedProviderID = payload.ProviderID
. . 1510: meta.Stream = payload.Stream
. . 1511: if payload.Model == "" {
. . 1512: return nil, meta, domain.Principal{}, domain.ResolvedModel{}, &requestError{status: http.StatusBadRequest, code: "invalid_model", message: "model is required", rawBody: body}
. . 1513: }
. . 1514: selectedProvider := payload.ProviderID
. 40ms 1515: if endpoint == anthropicMessagesEndpoint && deepseeksearch.PublicModel(payload.Model) && deepseeksearch.Requested(body) {
. . 1516: if payload.Stream {
. . 1517: return nil, meta, domain.Principal{}, domain.ResolvedModel{}, &requestError{status: http.StatusBadRequest, code: deepseeksearch.StreamingUnsupportedCode, message: deepseeksearch.StreamingUnsupportedMessage, rawBody: body}
. . 1518: }
. . 1519: if selectedProvider != "" && selectedProvider != deepseeksearch.ProviderID {
. . 1520: return nil, meta, domain.Principal{}, domain.ResolvedModel{}, &requestError{status: http.StatusBadRequest, code: "unsupported_tool", message: "DeepSeek native web search requires the official DeepSeek provider", rawBody: body}
. . 1521: }
. . 1522: selectedProvider = deepseeksearch.ProviderID
. . 1523: }
. . 1524: resolved, err := h.resolveRequestModel(runtime, payload.Model, selectedProvider, requestKindForEndpoint(endpoint), routeSelectionKey(principal, meta.RequestID), &meta)
. . 1525: if err != nil {
. . 1526: return nil, meta, domain.Principal{}, domain.ResolvedModel{}, &requestError{status: http.StatusNotFound, code: "model_not_found", message: err.Error(), rawBody: body}
. . 1527: }
. . 1528: setExplicitZeroCostUsageModel(r.Context(), resolved, &meta)
. . 1529: if err := enforcePublicModelMembershipEntitlement(runtime, principal.Membership, entitlementPublicModelID(runtime, resolved, &meta, requestKindForEndpoint(endpoint)), requestKindForEndpoint(endpoint)); err != nil {
. . 1530: return nil, meta, domain.Principal{}, domain.ResolvedModel{}, err
. . 1531: }
. . 1532: if h.admissionPipeline == nil {
. . 1533: if economicsErr := h.applyRequestEconomics(r.Context(), &principal, &meta, requestKindForEndpoint(endpoint)); economicsErr != nil {
. . 1534: return nil, meta, domain.Principal{}, domain.ResolvedModel{}, economicsErr
. . 1535: }
. . 1536: }
. . 1537: if err := applyRequestRole(r, principal, &meta, requestKindForEndpoint(endpoint)); err != nil {
. . 1538: return nil, meta, domain.Principal{}, domain.ResolvedModel{}, err
. . 1539: }
. . 1540: if err := applyProviderQueueMetadata(&meta, resolved); err != nil {
. . 1541: return nil, meta, domain.Principal{}, domain.ResolvedModel{}, err
. . 1542: }
. . 1543: meta.shadow = h.shadow.Capture(shadowOrigin(meta, principal), runtime, valueOrEmpty(meta.PublicModelID), endpoint, meta.Stream, body)
. 5.23s 1544: normalizedBody, notes, err := prepareTargetBody(endpoint, resolved, meta.PublicModel, body)
. . 1545: if err != nil {
. . 1546: return nil, meta, domain.Principal{}, domain.ResolvedModel{}, &requestError{status: http.StatusBadRequest, code: "invalid_request", message: "failed to prepare provider request", detail: err.Error(), rawBody: body}
. . 1547: }
. . 1548: if len(notes) > 0 && h.logger != nil {
. . 1549: h.logger.Info("request normalized",
. . 1550: "request_id", meta.RequestID,
. . 1551: "endpoint", endpoint,
. . 1552: "requested_model", meta.RequestedModel,
. . 1553: "public_model_id", valueOrEmpty(meta.PublicModelID),
. . 1554: "route_id", valueOrEmpty(meta.RouteID),
. . 1555: "provider_id", resolved.Provider.ID,
. . 1556: "provider_name", resolved.Provider.Name,
. . 1557: "provider_kind", resolved.Provider.Kind,
. . 1558: "model_id", resolved.BackendModel.ID,
. . 1559: "model", resolved.BackendModel.ExternalName,
. . 1560: "bifrost_model", resolved.BackendModel.BifrostModel,
. . 1561: "server_side_queue_enabled", meta.QueueEnabled,
. . 1562: "server_side_queue_wait_timeout_seconds", meta.QueueWaitTimeoutSec,
. . 1563: "notes", notes,
. 230ms 1564: "request", requestLogSummary(body),
. . 1565: )
. . 1566: }
. 1.76s 1567: meta.thinking.Normalized(normalizedBody, notes)
. . 1568: body = normalizedBody
. . 1569: meta.NormalizationNotes = notes
. . 1570: meta.RequestBodyBytes = len(body)
. . 1571:
. . 1572: return body, meta, principal, resolved, nil