Lazy loaded image
005-压测一个网关,先要测对层次:LLM Access Gateway 的分层基准测试与结果解读
字数 1863阅读时长 5 分钟
2026-4-9
type
Post
status
Published
date
Apr 9, 2026
slug
gateway005
summary
tags
gateway
推荐
category
icon
password

说明

这次压测的目的是,把正常情况下这个网关不同路径的性能基线测清楚。后面阶段在 fallback、unhealthy backend、readyz 波动等故障场景下,性能代价才有可对照的基线

一、问题定义

压测网关最容易犯的错误是:没分清楚不同层次的开销
压测一个网关时,必须先分清楚自己测到的是网关内部路径,还是网关加 adapter 的整条本地路径。只有先把层次分开,后面的性能数字才有解释力。
在这个项目里,至少有两条不同的测量路径:
  • in-process mock path:主要测网关内部路径
  • local HTTP adapter path:测网关内部路径 + 真实 HTTP adapter 开销
在当前仓库里:
  • mock path 主要覆盖:
auth、governance、routing、JSON shaping
  • HTTP adapter path 额外覆盖:
socket I/O、HTTP request construction、response parsing、JSON encode / decode(请求构造、socket I/O、响应解析与 JSON 编解码)

二、测量对象分层图

先把测量对象说清楚。
notion image
这张图要表达的是:
  • mock path 更接近测 gateway internal path
  • adapter path 更接近测 gateway + adapter 的本地真实代码路径
两条路径要区分清楚。

三、压测工具边界

我做了一个面向本网关项目验证的轻量压测工具cmd/loadtest,目的是为了稳定复现 non-stream / stream 两条路径,并把网关内部路径和 adapter 路径分层测清楚
它具备的能力包括:
  • POST /v1/chat/completions
  • 支持 non-stream 和 stream
  • 输出 success / failure
  • 输出 latency P50 / P95 / max
  • stream 模式额外输出 TTFT 和 chunk 总数
这是当前阶段足够实用的 benchmark driver。

四、non-stream benchmark

运行参数:
  • requests = 100
  • concurrency = 10
结果如下:
路径
Success
Failure
Approx QPS
P50
P95
Max
In-process mock
100
0
740.7 req/s
11 ms
22 ms
24 ms
Local HTTP adapter
100
0
609.8 req/s
14 ms
34 ms
37 ms
这组结果说明:
HTTP adapter path 引入了真实请求构造和响应解析成本,即使上游仍然是本地的。
这组数字展示了:
  • 网关内部路径本身的开销
  • 进入真实 adapter 代码路径后,多付出了多少本地成本

non-stream 结果图

这张图想说明的是:
  • mock path 的结果更接近 gateway internal path
  • adapter path 的额外代价主要来自 HTTP adapter 路径,而不是网关内部逻辑突然变差

五、stream benchmark

运行参数:
  • requests = 50
  • concurrency = 5
结果如下:
路径
Success
Failure
Throughput
Latency P95
TTFT P95
Chunks
In-process mock
50
0
549.5 req/s
19 ms
12 ms
200
Local HTTP adapter
50
0
61.4 req/s
98 ms
28 ms
150
这里最关键的不是整体变慢,而是:
TTFT 仍然相对低,总流式时延的大头发生在首 chunk 之后。
原因很清楚:当前 synthetic upstream 会通过多次写出,把整条流式过程刻意拉长。
因此,对流式系统来说,至少要区分两个问题:
  • TTFT:用户第一次看到内容要多久
  • time to full completion:整条流什么时候结束
这两个指标不能混在一起理解。

stream 结果图:TTFT vs 总时延

这张图要表达的是:
adapter path 的主要增量不在“首 token 出来之前”,而在“首 token 之后整条流被拉长”。
也就是说,对流式系统来说,“首包快”和“整条流结束快”不是同一个命题。

六、为什么压测前必须调整 tenant 限额

本地 seed tenant 默认是:
  • 60 req/min
这个值适合 smoke test,不适合 benchmark。
方法说明
这次 benchmark 前临时调高 tenant 限额,不是为了“跑得更好看”,而是为了隔离治理层对结果的干扰。
如果限流器先把压测挡下来,那么测出来的就是 quota 策略,而不是 gateway path 本身。
原因很简单:
如果你明明在测网关路径,却让 rate limiter 先把压测挡下来,那么你测到的就是治理策略,而不是网关性能。
所以 benchmark 前会临时调高 tenant 限额,结束后再恢复。
这是在保证:
当前 benchmark 测的是 gateway layer,而不是 rate limiter

七、资源快照:本地依赖成本主要落在 MySQL

100 请求那组 benchmark 结束得太快,一次性的进程采样意义不大。
因此我又补了一次更长的观测:
观测期间的资源快照显示:
Component
Approx Memory
Gateway
28 MiB
MySQL
587.8 MiB
Redis
9.953 MiB
这组快照说明了一件事:
当前本地 benchmark 环境里的资源 footprint 主导项是 MySQL,而不是 Redis。
也就是说,在当前本地验证环境里,状态存储层的资源体量明显高于缓存层。

八、边界说明

本文里的 adapter path 对比,不是 hosted provider benchmark。
当前使用的是本地 synthetic OpenAI-compatible upstream,因此测到的是:
网关路径、adapter 路径、本地 upstream 交互开销
它没有覆盖:
  • WAN 抖动、真实 provider 侧波动、公网环境下的复杂时延分布
所以这组 benchmark 的正确定位是:
它表示网关自身开销,但它不能替代真实 hosted-provider latency study。

九、如何复现实验

复现实验说明
这组 benchmark 的价值也在于它可以被稳定复现。
当前复现实验分两条路径:
  • in-process mock path:更接近测 gateway internal path
  • local HTTP adapter path:更接近测 gateway + adapter 的本地真实代码路径

十、结论

LLM Access Gateway正常基线已经建立。
non-stream 的 in-process mock path 为 740.7 req/s P95 22 ms local HTTP adapter path 为 609.8 req/s P95 34 ms 在 stream 场景下,adapter path 的 TTFT P9528 ms,但总 Latency P95 上升到 98 ms
 
回到首页