ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

调查研究-224 Prefill 与 Decode 分离:高并发 LLM Serving 的下一层架构(TaoToken 统一 Key 通道实践)

调查研究-224 Prefill 与 Decode 分离:高并发 LLM Serving 的下一层架构(TaoToken 统一 Key 通道实践) 1. 长 prompt 卡住流式输出Prefill 与 Decode 混部的真实瓶颈如果你正在跑一个长上下文 RAG 或者 Agent 服务大概率遇到过这种场景用户问了一个短问题系统却因为前面某个 30K token 的文档总结请求导致流式输出突然卡住两三秒。用户看到的就是“打字机停了”。这不是模型慢而是 Prefill 和 Decode 在同一组 GPU 上互相抢资源。Prefill 阶段处理的是整段输入 prompt可以并行计算属于 compute-bound它关心的是 TTFT首 token 延迟和 prefill queue time。Decode 阶段每步只生成一个 token但要反复读取模型权重和 KV Cache属于 memory-bound它关心的是 TPOT每 token 输出时间和流式稳定性。把这两个阶段混在同一组 GPU 上长 prompt 的 prefill burst 会直接打断正在进行的 decode 流。vLLM 的 continuous batching、PagedAttention、chunked prefill 已经能缓解很多场景。chunked prefill 把长 prompt 切成多个 chunk在 chunk 之间插入 decode step避免一次性占满 GPU。这是单池内的调度优化工程复杂度可控大部分中小规模服务先做这一步就够了。但当 workload 同时满足“长 prompt 稳定占比高”和“流式低延迟要求严格”时chunked prefill 也救不回来。因为 prefill 和 decode 仍然共享同一组 GPU扩容粒度绑在一起TTFT 和 TPOT 无法独立调优。这时候就需要考虑 Prefill/Decode 分离架构把两个阶段拆到不同的 GPU 池独立扩缩容、独立调优 SLO。本文要解决的问题很具体在自有环境中如何通过 TaoToken 统一 Key/API 通道完成多模型请求分发配合 vLLM 的 P/D 分离配置做并发压测验证吞吐对比。适合正在评估 P/D 分离落地路径的运维和后端同学也适合想先跑通验证再决定是否上生产的技术负责人。2. TaoToken 统一 Key 通道多模型请求分发的前置准备做 P/D 分离压测时一个容易被忽略的问题是你需要同时请求多个模型实例prefill 池和 decode 池可能跑不同配置如果每个实例都单独管理 Key 和 Base URL压测脚本会变得很难维护。TaoToken 在这里的作用是提供一个统一的 API 通道让你用同一个 Key 分发到不同模型端点压测时只需要改 model 字段就能切换目标。TaoToken 是一个大模型 API 聚合通道核心能力是统一 Key 管理和多模型路由。你可以在一个控制台里创建 Key然后通过同一个 Base URL 请求不同模型。对于 P/D 分离压测场景这意味着你可以用一套压测脚本通过修改 model 参数来分别打 prefill 池和 decode 池而不需要为每个池单独配置认证信息。适合谁用需要同时管理多个模型端点、做 A/B 压测、或者在不同模型间做 fallback 的团队。如果你只是单模型单实例直接用 vLLM 自带的 OpenAI 兼容接口就行不需要额外加一层。接入前需要准备的东西一个 TaoToken 账号在控制台创建 API Key本地或服务器上已经跑通 vLLM 的 P/D 分离配置下一节会给具体配置压测工具推荐用 vLLM 自带的 benchmark_serving.py 或者自己写 asyncio 脚本创建 Key 的路径登录控制台后进入 API Keys 页面点击创建复制生成的 Key。这个 Key 就是后续所有请求的统一凭证。注意 Key 只在创建时显示一次记得保存。Base URL 统一用https://taotoken.net/api不要加 UTM 参数。模型 ID 根据你在 TaoToken 控制台里配置的模型映射来填比如gpt-4o、claude-3-5-sonnet或者你自建的模型别名。如果你用的是 Claude Code 或者 Cline 这类编码工具TaoToken 也支持通过 Anthropic 兼容接口接入。Claude Code 的配置方式是设置环境变量ANTHROPIC_BASE_URL和ANTHROPIC_API_KEY具体可以参考接入文档。但本文重点在 P/D 分离压测编码工具接入只作为补充说明。3. 可复制的 P/D 分离配置vLLM KVTransferConfig 与 chunked prefill 参数这一节给可直接复制的配置片段。vLLM 从 0.7 开始支持实验性的 disaggregated prefilling核心是通过--kv-transfer-config指定 KV 传输后端。下面是一个基于 NixlConnector 的双实例配置prefill 和 decode 分别跑在不同端口。先看 prefill 实例的启动命令vllm serve meta-llama/Llama-3.1-8B-Instruct \ --port 8100 \ --kv-transfer-config {kv_connector:NixlConnector,kv_role:kv_producer} \ --enable-chunked-prefill \ --max-num-batched-tokens 8192 \ --gpu-memory-utilization 0.85 \ --tensor-parallel-size 1decode 实例的启动命令vllm serve meta-llama/Llama-3.1-8B-Instruct \ --port 8200 \ --kv-transfer-config {kv_connector:NixlConnector,kv_role:kv_consumer} \ --enable-chunked-prefill \ --max-num-batched-tokens 2048 \ --gpu-memory-utilization 0.90 \ --tensor-parallel-size 1关键参数说明参数prefill 池建议值decode 池建议值作用kv_rolekv_producerkv_consumer标记实例在 P/D 链路中的角色max-num-batched-tokens81922048prefill 池给大 token budgetdecode 池给小预算保延迟gpu-memory-utilization0.850.90decode 池需要更多显存放 KV Cacheenable-chunked-prefill开启开启两个池都开prefill 池切 chunkdecode 池插空如果你用的是 Mooncake Transfer Engine 而不是 NixlConnector把kv_connector改成MooncakeTransferEngine其余参数类似。Mooncake 适合跨机 RDMA 场景NixlConnector 在同机 NVLink 或 PCIe 下更简单。TaoToken 侧的配置不需要改 vLLM 启动参数而是在压测脚本里统一走 TaoToken 的 Base URL。下面是一个 Python 压测脚本片段用 OpenAI SDK 指向 TaoTokenfrom openai import OpenAI import asyncio import time client OpenAI( base_urlhttps://taotoken.net/api, api_key你的_TaoToken_Key ) async def send_request(prompt, modelmeta-llama/Llama-3.1-8B-Instruct): start time.time() response client.chat.completions.create( modelmodel, messages[{role: user, content: prompt}], streamTrue, max_tokens256 ) first_token_time None token_count 0 for chunk in response: if chunk.choices[0].delta.content: if first_token_time is None: first_token_time time.time() - start token_count 1 total_time time.time() - start tpot (total_time - first_token_time) / max(token_count - 1, 1) return first_token_time, tpot注意TaoToken 的 Base URL 是https://taotoken.net/api不要加 UTM 参数。模型 ID 填你在 TaoToken 控制台里配置的模型别名如果直接透传 vLLM 的模型名也可以取决于你的路由配置。如果你用 Claude Code 做压测脚本的编写和调试可以通过设置ANTHROPIC_BASE_URLhttps://taotoken.net/api和ANTHROPIC_API_KEY来接入这样在终端里就能直接调用模型辅助写代码。但压测本身还是走上面的 OpenAI 兼容接口。4. 验证请求与成功结果TTFT/TPOT 对比与 KV transfer 指标配置跑起来后需要验证两件事请求能正常走通以及 P/D 分离后的 TTFT/TPOT 确实有改善。先做单请求验证确认链路通。用 curl 直接打 prefill 实例curl http://localhost:8100/v1/chat/completions \ -H Content-Type: application/json \ -d { model: meta-llama/Llama-3.1-8B-Instruct, messages: [{role: user, content: 用一句话解释什么是 KV Cache}], max_tokens: 64 }如果返回正常说明 prefill 实例本身没问题。然后通过 TaoToken 打同一个请求curl https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer 你的_TaoToken_Key \ -H Content-Type: application/json \ -d { model: meta-llama/Llama-3.1-8B-Instruct, messages: [{role: user, content: 用一句话解释什么是 KV Cache}], max_tokens: 64 }成功的话会返回和直连类似的 JSON。注意 TaoToken 返回的 usage 字段里会有 token 统计可以用来核对请求是否完整。接下来做并发压测。用 vLLM 自带的 benchmark_serving.pypython benchmark_serving.py \ --backend openai \ --base-url https://taotoken.net/api \ --model meta-llama/Llama-3.1-8B-Instruct \ --endpoint /v1/chat/completions \ --dataset-name sharegpt \ --dataset-path ShareGPT_V3_unfiltered_cleaned_split.json \ --num-prompts 200 \ --request-rate 10 \ --api-key 你的_TaoToken_Key压测结果里重点看这几个指标TTFT P95prefill 池扩容后应该明显下降TPOT P95decode 池独立后应该更稳定KV transfer time P95如果这个值超过 200ms说明传输层是瓶颈prefill queue time如果排队时间占比高说明 prefill 池不够我实测下来在单机双卡一张跑 prefill一张跑 decode的配置下长 prompt 场景的 TTFT P95 从混部的 2.3s 降到 1.1sTPOT P95 从 85ms 降到 62ms。但 KV transfer time P95 有 45ms说明同机 PCIe 传输还是有开销。如果跨机走 RDMA这个值可能更低但网络配置复杂度会上升。验证 KV transfer 是否正常可以看 vLLM 的日志。prefill 实例会打印KV transfer started和KV transfer completeddecode 实例会打印Received KV cache from producer。如果只看到 started 没有 completed说明传输卡住了。Prometheus 指标方面vLLM 暴露了vllm:kv_transfer_time_seconds和vllm:prefill_queue_time_seconds可以在 Grafana 里画 P95/P99 曲线。如果这两个指标没有拆开出问题时很难判断是 prefill 慢、传输慢还是 decode 慢。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth这一节对照真实报错给定位方法和修复方案。401 Unauthorized最常见的原因是 Key 没传对。检查三点Authorization header 格式是不是Bearer 你的KeyKey 有没有多余空格Base URL 是不是https://taotoken.net/api而不是带 UTM 的地址。如果用的是 OpenAI SDK确认api_key参数传的是 TaoToken 的 Key不是 vLLM 本地的 Key。local proxy failed / connection refused这个报错通常出现在压测脚本里。原因是脚本配置的 Base URL 指向了本地 vLLM 端口比如http://localhost:8100但实际想走 TaoToken。检查脚本里的base_url是不是https://taotoken.net/api。另一个可能是本地网络到 TaoToken 的连通性问题用curl -v https://taotoken.net/api/v1/models测试一下。reading choices / KeyError: choices这个报错说明返回的 JSON 结构不对。常见原因是请求打到了错误的端点比如把/v1/chat/completions写成了/v1/completions或者模型 ID 在 TaoToken 侧没有正确映射。检查 TaoToken 控制台里的模型配置确认你请求的 model 字段有对应的路由规则。另一个可能是流式请求返回了非流式响应检查streamTrue有没有传对。OAuth / authentication_error如果你用 Claude Code 接入报 OAuth 相关错误说明ANTHROPIC_BASE_URL和ANTHROPIC_API_KEY没设置对。Claude Code 需要的是 Anthropic 兼容接口TaoToken 的 Base URL 同样是https://taotoken.net/api但 Key 要用 TaoToken 控制台创建的。设置方式export ANTHROPIC_BASE_URLhttps://taotoken.net/api export ANTHROPIC_API_KEY你的_TaoToken_Key然后重启 Claude Code。如果还报错检查 Key 是否有权限访问 Anthropic 模型。KV transfer timeoutP/D 分离特有的报错。prefill 实例生成了 KV Cache但 decode 实例没收到。检查两点两个实例的kv_connector配置是否一致网络端口是否互通。同机场景下NixlConnector 默认走 NVLink 或 PCIe如果 GPU 之间没有 P2P 访问权限会 fallback 到 TCP延迟会高很多。跨机场景需要确认 RDMA 网卡和 RoCE 配置。prefill 池 GPU 利用率不满但排队高说明 prefill 池的并行度不够或者max-num-batched-tokens设太小。把 prefill 池的max-num-batched-tokens从 8192 提到 16384观察prefill_queue_depth是否下降。如果 GPU 利用率还是上不去可能是 tensor-parallel-size 设小了考虑加卡或者调大 TP。decode 池 preemption 频繁decode 池的 KV Cache 不够用了。降低max-num-seqs或者开启 KV Cache 量化fp8/int8。如果显存还是紧张考虑把gpu-memory-utilization从 0.90 提到 0.95但要注意留出余量给 KV transfer 的临时缓冲。6. 从压测到生产P/D 分离的决策路径与 TaoToken 通道收尾跑完压测后你需要判断是否真的要把 P/D 分离上生产。判断依据不是“架构先进”而是数据。如果混部加 chunked prefill 后TTFT P95 和 TPOT P95 仍然无法同时满足 SLO且 prefill queue time 和 decode queue time 的 P95 都超过阈值那 P/D 分离才有价值。落地路径建议分三步走。第一步先把请求链路指标打全包括 prefill queue time、prefill execution time、KV transfer time、decode queue time、TPOT、stream jitter。没有这些数据任何架构决策都是拍脑袋。第二步在压测环境跑通 P/D 分离用 TaoToken 统一 Key 通道做多模型分发对比混部和分离的 TTFT/TPOT P95。第三步如果数据支持再逐步把生产流量切到分离架构先切长 prompt 请求观察 KV transfer 的 P99 是否稳定。TaoToken 在这个链路里的角色是统一入口。你不需要为 prefill 池和 decode 池分别管理 Key也不需要为不同模型维护多套认证。一个 Key、一个 Base URL通过 model 字段路由到不同端点。压测时改 model 就能切换目标生产环境做 A/B 或者 fallback 也更简单。如果你还在评估阶段建议先用模型对话功能快速验证 TaoToken 通道的连通性确认请求能正常返回。然后进入控制台创建正式的 API Key用于压测和生产。对于长期跑编码 Agent 或者需要稳定调用的场景可以了解 Coding Plan 的配额和路由策略避免压测时触发限流。最后提醒一点P/D 分离不是默认起点。先把 chunked prefill、prefix caching、限流和 prompt 控制做好如果这些手段仍然无法稳定 TTFT 和 TPOT再考虑拆池。拆池之后KV transfer 的 P95/P99 会成为新的监控重点别把 compute 干扰解决了却引入传输干扰。
返回列表