10 - 性能与形态代价
本文不给出自测的横向性能数字。文中出现的所有性能数值都是各项目自己的声明,已逐条标注来源。第四节给出一套可复现的压测方法。
前置:02 - 四种形态。本篇是对那四种形态的代价结算。
本篇会用到的词:
| 词 | 意思 |
|---|---|
| RTT | Round-Trip Time,一个网络包往返的时间。同机房通常在 1 毫秒以内,跨区域可能几十毫秒 |
| 序列化 / 反序列化 | 把请求体在「字节流」和「内存对象」之间来回转换。网关要改写请求,就必须先解开再装回去,这是第二块开销的来源 |
| 热路径 | 用户正在等待的那条代码路径。放在热路径上的每一毫秒用户 都能感觉到,所以记账、上报这类事要挪到异步链路 |
| chunk | 流式响应里的一小段数据。网关要逐个处理它们,所以响应越长,这块开销累积得越多 |
| 压测 | 用工具模拟大量并发请求来测量性能。本篇第四节给的是一套可复现的方法,而不是一组结论数字 |
本篇回答:网关到底会让你的请求慢多少?该不该按性能选网关?(结论:绝大多数情况下不该)
一、开销的来源
先把"网关慢"这件事拆开。一次经过网关的 LLM 请求,网关本身贡献的开销只有四块:
关键在于这四块的权重和请求形态强相关:
| 非流式短请求 | 流式长响应 | Realtime WebSocket | |
|---|---|---|---|
| ① 网络跳数 | 占比高 | 摊薄 | 摊薄 |
| ② 协议转换 | 中 | 中(只在首尾) | 低 |
| ③ 策略执行 | 中 | 摊薄 | 摊薄 |
| ④ 流式转发 | 无 | 主导 | 主导 |
一次 30 秒的流式响应里,网关多花 2 毫秒做鉴权毫无意义。但如果它对每个 chunk 都做一次反序列化 + 正则扫描 + 重新序列化,那开销会被输出 token 数直接放大。 这就是为什么 AI 网关的性能问题几乎全部集中在第 ④ 块。
二、LiteLLM 的 Rust 重写
litellm-rust/ 目录已经进了主干。有意思的不是"Python 慢所以换 Rust"这个俗套结论,而是他们只重写了哪部分、以及明确说了不重写哪部分。
官方 README.md 写得很直白:
Python continues to own configuration, retries, routing policy, logging, callbacks, spend tracking, and customer plugins until each Rust path has parity coverage and production evidence.
配置、重试、路由策略、日志、回调、花费追踪、客户插件 —— 全部留在 Python。也就是说 第 03 篇 拆的那六种路由策略、第 04 篇 拆的那套限流,都不在重写范围内。
三个 crate 的分工:
| Crate | 职责 |
|---|---|
litellm-core | Rust 版 SDK:路由入口、类型、provider 转换 、鉴权、实际的 HTTP 调用 |
litellm-ai-gateway | axum 服务器 + WebSocket host,把 HTTP/WS 翻译成 core 的入口调用 |
litellm-python-bridge | PyO3 cdylib,把 Rust 暴露给 Python SDK |
依赖方向是无环的:core ← ai-gateway ← python-bridge。
而 ai-gateway/ARCHITECTURE.md 揭示了第一个被搬走的到底是什么:
The Rust ai-gateway does LLM inference (realtime WebSocket). Spend tracking is an API callback: it POSTs each finished session to the LiteLLM proxy, which records spend and runs the usual callbacks.
Realtime WebSocket。 不是普通的 completion 接口,是那个每秒要转发几十个音频/文本帧、连接一开就是几分钟的实时接口 —— 正好是上一节里第 ④ 块开销占绝对主导的场景。
而且花费统计的处理方式很说明问题:Rust 网关不自己算账,会话结束后 POST 给 Python proxy,让它去记录并跑原有的回调链。
这是一次教科书式的重写:把热路径(每帧都要过的数据搬运)搬到 Rust,把冷路径(每次会话只发生一次的记账)留在 Python 并改成异步回调。既拿到了性能,又没有把五年积累的策略逻辑推倒重来。
对照 crates/python-bridge/src/lib.rs 只有 15 KB —— 桥接层做得很薄,说明边界切得干净。
如果你在做类似的技术决策,这个案例的价值在于它给出了拆分的判据:一次请求里要执行 N 次的逻辑(N 随 token 数增长)搬走,执行 1 次的留下。
三、各项目的性能声明
以下数字全部来自项目方或第三方评测文章,本站未做验证:
| 来源 | 声明 | 类型 |
|---|---|---|
maximhq/bifrost 仓库描述 | "Fastest enterprise AI gateway (50x faster than LiteLLM)" | 项目自述 |
BerriAI/litellm 仓库描述 | "The fastest, litest AI Gateway. Rust core with Python SDK." | 项目自述 |
| 第三方评测文章 | Envoy AI Gateway 转发开销约 1–3 ms | 第三方评测 |
两家都自称最快,这本身就说明这类声明的信息量接近于零。 「50x faster than LiteLLM」没有说明测的是哪条路径 —— 如果测的是非流式短请求的空转吞吐,Go 对 Python 拉开一个数量级毫不意外;但如果测的是一次 30 秒流式响应的端到端延迟,网关开销早被模型推理时间淹没了。
唯一有意义的做法是自己按自己的流量形态测。
四、可复现的压测方法
要让四家可比,必须先把变量控制住。