把大语言模型从实验环境搬到生产系统后,模型参数量并不能单独决定吞吐和成本。同一套 TPU、同一个服务框架,面对“长输入、短输出”的分类请求和“短输入、长输出”的生成请求,可能呈现完全不同的扩展曲线。
这组测试在 Google Cloud TPU v6e 上运行 Gemma 3 12B 与 27B,使用 GKE Autopilot、单主机 2×2 TPU 芯片拓扑以及 vllm-project/tpu-inference。结果揭示了一个直接影响架构设计的事实:prefill 与 decode 消耗的是不同类型的硬件资源,生产容量规划必须先看 token 形态,再选模型和并发上限。
两类请求,实际上是两种计算问题
测试覆盖 16、32、64 和 128 个并发用户,并固定使用以下全局服务参数:
max-model-len=128000
max-num-batched-tokens=8192
max-num-seqs=512
分类负载模拟电商合规审核:请求中包含产品规则、商品描述和 OCR 文本,输入约 4,000 tokens,输出通常只有约 10 tokens,例如 Allow 或 Prohibit。大量工作发生在 prefill 阶段,模型只需执行极短的 decode。
生成负载则要求模型撰写长篇政策分析,输入约 500 tokens,输出约 1,000 tokens。此时持续的逐 token 解码成为主要成本,模型权重读取、内存带宽和批处理调度都会被反复施压。
这一区别比“请求数量”更重要。两个系统即使都处理 100 个并发请求,其每秒需要生成的 token 数也可能相差几个数量级。
27B 的生成吞吐在高并发下出现平台期
生成测试中,两种模型在 64 个并发用户以内表现接近。到 128 并发时,Gemma 3 12B 达到 8.19 倍归一化吞吐,而 27B 只有 4.12 倍,几乎停留在 64 并发时的 4.00 倍水平。
| 并发用户 | Gemma 3 12B | Gemma 3 27B |
|---|---|---|
| 16 | 1.00× | 1.05× |
| 32 | 1.98× | 1.97× |
| 64 | 2.96× | 4.00× |
| 128 | 8.19× | 4.12× |
这里的数字是相对于 Gemma 3 12B、16 并发基线的吞吐倍率,并非绝对 requests/s。尤其是高并发下突然升高的吞吐,需要结合完成请求数、失败数、输出 token 数和延迟一起检查,不能仅凭倍率推导单副本容量。
延迟数据也显示出同样的压力。27B 生成任务的归一化端到端延迟从 16 并发的 1.20× 上升到 64 并发的 2.93×,在 128 并发时达到 3.33×。硬件进入饱和区后,新增并发不再带来相称吞吐,只会增加排队、尾延迟和静默丢请求的风险。
因此,高并发长文本生成更适合使用 12B,或者把 27B 单副本并发严格限制在 64 左右,再通过增加副本扩容。这个阈值来自本次特定硬件和配置,迁移到其他 prompt 长度、输出长度或 TPU 拓扑时必须重新压测。
分类负载让 12B 与 27B 接近同一水平
在长输入、短输出的分类测试中,两种模型直到 128 并发仍然保持相近的峰值扩展能力:12B 达到 6.37×,27B 达到 6.04×。
| 并发用户 | Gemma 3 12B | Gemma 3 27B |
|---|---|---|
| 16 | 1.00× | 0.76× |
| 32 | 1.18× | 1.53× |
| 64 | 2.04× | 3.15× |
| 128 | 6.37× | 6.04× |
这意味着参数量较大的模型并不必然在 prefill-heavy 工作流中造成明显吞吐惩罚。如果业务确实能从 27B 的准确率或推理能力获益,分类任务可能比长文本生成更适合部署它。
但“分类表现接近”不能直接外推到所有摘要任务。摘要的输出长度可能从几十到上千 tokens;一旦 decode 占比明显提高,其性能曲线就可能更接近生成负载。上线前应按真实的输入和输出 token 分布构造样本,而不是只按 API 名称分类。
可以这样配置服务并采集饱和信号
下面是一个可改造的 GKE Deployment 片段。镜像地址、模型凭据以及 TPU 节点标签需要按实际集群调整;VLLM_TPU_BUCKET_PADDING_GAP 没有适用于所有模型的固定值,应通过压测选择,不能照搬未知的“最佳值”。
apiVersion: apps/v1
kind: Deployment
metadata:
name: gemma3-27b-generation
spec:
replicas: 1
selector:
matchLabels:
app: gemma3-27b-generation
template:
metadata:
labels:
app: gemma3-27b-generation
spec:
nodeSelector:
cloud.google.com/gke-tpu-accelerator: tpu-v6e-slice
cloud.google.com/gke-tpu-topology: 2x2
containers:
- name: vllm
image: REGION-docker.pkg.dev/PROJECT/REPOSITORY/tpu-inference:TAG
args:
- vllm
- serve
- google/gemma-3-27b-it
- --max-model-len=128000
- --max-num-batched-tokens=8192
- --max-num-seqs=64
env:
- name: VLLM_TPU_BUCKET_PADDING_GAP
value: "REPLACE_WITH_BENCHMARKED_VALUE"
ports:
- name: http
containerPort: 8000
resources:
limits:
google.com/tpu: "4"
对于 27B 生成服务,示例把 --max-num-seqs 限制为 64,以体现测试观察到的平台期。分类服务可以从较高值开始测试,但不能只看平均延迟;还要记录 P95/P99 延迟、HTTP 错误、请求完成率以及输入、输出 token 数。
可以用 Prometheus 规则把端到端延迟直接变成告警信号。以下指标名是假设应用已暴露 llm_request_e2e_seconds_bucket,接入时需要替换成实际指标:
groups:
- name: llm-serving
rules:
- alert: LlmE2ELatencySaturation
expr: |
histogram_quantile(
0.95,
sum by (le, model) (
rate(llm_request_e2e_seconds_bucket[5m])
)
) > 30
for: 10m
labels:
severity: warning
annotations:
summary: "LLM P95 end-to-end latency exceeds the tested limit"
阈值 30 秒只是可运行的示例值,应替换为业务 SLO 和压测得到的饱和拐点。自动扩缩容也应采用同一类 E2E 延迟或队列等待指标,而不是仅依赖 CPU、内存利用率;TPU 已经饱和时,CPU 指标仍可能看起来正常。
上线前的容量决策
生产部署可以按以下顺序收敛配置:
- 从日志中统计真实的 ISL、OSL、并发量及其 P50、P95、P99 分布。
- 分开压测 prefill-heavy 与 decode-heavy 请求,避免一个平均值掩盖两种瓶颈。
- 同时记录吞吐、E2E 延迟、首 token 延迟、每 token 延迟、失败率和完成 token 数。
- 逐步调整
max-num-seqs、max-num-batched-tokens、max-model-len与 TPU bucket padding。 - 在延迟开始非线性上升之前设置单副本并发上限,并基于 E2E 延迟或排队时间扩容。
- 用业务质量评测决定是否采用 27B;性能接近不代表更大模型一定值得额外成本。
这组结果最重要的价值不是给出一个永久有效的并发数字,而是展示了容量边界如何随 token 结构改变。对于 TPU 上的 LLM 服务,模型选择、批处理参数和扩缩容信号必须围绕真实输入输出比例共同设计。