真实面经题目 · 原创解析
LLM 服务在 500 并发下如何把 TTFT P99 从 3s 优化到 1.5s?
这题考高并发 LLM 服务的首 token 长尾优化,回答要先建立可观测性,再从排队、调度、prefill/decode、批处理、KV 缓存、prompt 长度、容量和流式链路逐层处理。
真实面经题目 · 原创解析
这题考高并发 LLM 服务的首 token 长尾优化,回答要先建立可观测性,再从排队、调度、prefill/decode、批处理、KV 缓存、prompt 长度、容量和流式链路逐层处理。
我会先定义 TTFT:从服务收到请求到用户侧收到第一个非空 token 的时间,并且题目关注的是 500 并发下 P99 从 3s 到 1.5s,所以不能只说开启 streaming。第一步是做分段 tracing,把网关、鉴权、排队、路由、prompt 构造、检索、tokenize、prefill、调度、首个 decode、网络 flush 都打点,确认 P99 主要耗在排队还是计算。第二步处理排队和容量:限流、优先级队列、负载均衡、热实例、自动扩容、请求隔离和超时降级。第三步优化模型服务:连续批处理参数、prefill/decode 调度、prefix/KV cache、paged attention、合理 batch 等待时间和模型量化或蒸馏。第四步减少输入负担:压缩 system prompt、裁剪历史、优化 RAG 结果、缓存稳定前缀。第五步验证流式链路,确保代理、网关和客户端不会缓冲首 token。最后用同样 500 并发压测看 P50/P95/P99、错误率、吞吐、成本和答案质量,防止只把延迟转移成失败率或质量下降。
在 500 并发目标下,先把 1.5s 预算分配到网关、应用检索、队列、prefill、首 token flush 和客户端接收等阶段,并按 prompt 长度、请求类型和实例负载分桶。TTFT 要明确起点和终点:服务收到请求、模型服务收到请求、还是用户浏览器收到第一个非空 token,口径不同会影响判断。高并发 P99 优化必须做端到端 tracing,把网关、队列、路由、prompt 构造、检索、tokenize、prefill、decode 和网络 flush 分开看。
500 并发下 P99 变差常见原因是队列等待、实例负载不均、冷启动、prefill 被长 prompt 阻塞、batch 参数不合适或下游检索慢。只有定位主要耗时段,才知道该加容量、改调度、压 prompt,还是优化模型 serving。
如果瓶颈在排队,需要做 admission control、优先级队列、请求隔离、负载均衡、热池、自动扩容和合理超时。高价值短请求可以避免被超长请求阻塞;超出容量时要明确降级或拒绝,而不是让所有请求一起排到 P99 失控。
TTFT 主要受排队和 prefill 影响。可以调连续批处理的最大等待时间和 batch 大小,使用 prefix cache 或 KV cache 复用稳定前缀,减少长 prompt 对首 token 的阻塞,必要时做 prefill/decode 资源拆分、paged attention、量化或更小模型路由。吞吐优化不能以牺牲首 token 长尾为代价。
Prompt 越长,prefill 越慢。可以压缩 system prompt,裁剪对话历史,摘要长期上下文,限制 RAG topK,提前缓存模板化前缀,优化检索和 rerank 耗时。很多 TTFT 问题不是模型本身慢,而是上游把过多无效上下文塞进了请求。
开启 streaming 不等于 TTFT 达标,还要确认服务端及时 flush,网关和 CDN 不缓冲,客户端按流解析第一个非空 delta。压测时同时看 P50/P95/P99、错误率、超时率、吞吐、GPU 利用率、单请求成本和答案质量,避免把 3s P99 变成更高失败率。
流式只能让生成后的 token 尽快返回,如果请求还在排队、prefill 很慢、网关缓冲或客户端没有及时解析,TTFT 仍然会高。
优先查长尾队列等待、超长 prompt、实例负载不均、冷启动、检索慢查询、batch 等待时间和下游超时。
可能会。较大的 batch 等待时间有利于吞吐,但会增加首 token 等待。要按 SLO 调 batch 参数,而不是只追求最大吞吐。
首 token 前需要处理输入上下文,prompt 越长 prefill 越重。压缩稳定前缀、裁剪历史和减少无关 RAG 片段可以直接降低 prefill 时间。
要看错误率、超时率、吞吐、GPU 利用率、排队时间、成本、答案质量和不同请求长度分层,否则可能只是把延迟问题转移到了失败或质量下降上。