一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

SGLang 并发异常排查:先看显存占用还是请求队列

时间:2026-09-14 16:54:01 编辑:袖梨 来源:一聚教程网

本地单请求运行正常,并不意味着 SGLang 接入业务后也能承受多人并发。当等待时间拉长、请求失败且显存接近满载时,真正需要确认的是请求正在排队,还是在 prefill、decode 等阶段发生了资源分配错误。只有先把故障阶段和证据对应起来,后续调参才有明确依据。

SGLang 一加并发就出问题,先查显存还是队列

场景:SGLang 接进应用后多人同时提问,有人等很久、有人直接失败,团队准备先降并发。结论:92% 显存占用不等于 OOM;要先按"是否在排队/哪个阶段失败"分诊,再考虑 --chunked-prefill-size / --max-running-requests / --mem-fraction-static 等单项参数。产出:5 步分诊法 + 教学 20 请求对照表 + 16 行错误速查卡。 适用版本:SGLang v0.5.19(2026-09-05),资料复核于 2026-09-12;教学数据非 GPU 实测。

TL;DR

  • 场景:本地正常、接入应用后多人并发出现长时间等待和请求失败,团队首选"先降并发"。
  • 结论:显存 92% 不能直接判 OOM;应先按"是否在排队 / 哪个阶段失败 / 哪类资源耗尽"分诊,再在 FAQ 给出的三个方向(prefill 改 --chunked-prefill-size、decode 改 --max-running-requests、改 --mem-fraction-static)中按阶段单选一项。
  • 产出:5 步分诊法(接前/排队/prefill/decode/取消)+ 教学 20 请求对照表(8192→4096 单变量对照,60%→80%,仍未达 95%)+ 16 行错误速查卡。

版本矩阵

项目状态说明
SGLang Production Metrics 文档可访问✅ 已验证https://docs.sglang.io/docs/references/production_metrics 返回 HTTP 200
--enable-metrics 开启 Prometheus 指标✅ 已验证沿用前几轮核查
指标 sglang:num_running_reqs / num_queue_reqs 含义✅ 已验证官方页明确:分别是"the number of running requests"与"the number of requests in the waiting queue"
指标 sglang:time_to_first_token_seconds✅ 已验证官方页含 generate_request 标签的 latency histogram
SGLang FAQ 可访问✅ 已验证https://docs.sglang.io/docs/references/faq 返回 HTTP 200
FAQ OOM 条目给出三个参数方向✅ 已验证贴图忠实摘录:prefill 改 --chunked-prefill-size、decode 改 --max-running-requests、通用改 --mem-fraction-static
SGLang Server Arguments 文档可访问✅ 已验证https://docs.sglang.io/docs/advanced_features/server_arguments 返回 HTTP 200
SGLang v0.5.19(2026-09-05)✅ 已验证沿用前几轮核查
教学 20 请求对照表(8192 vs 4096)✅ 已设计由作者构造的对照数据,非 GPU 实测
资料复核日期 2026-09-12✅ 已标注文中明确
5 张配图 URL 全部可访问✅ 已验证i-blog.csdnimg.cn/img_convert 5 个 URL 全部 200
nvidia-smi 92% 占用直接判定 OOM❌ 已驳斥显存可预先划给缓存;不替代内存分配失败证据
看到排队就调小并发❌ 已驳斥调小可能只是把工作推到更长队列
显存 92% + 请求失败 = 一定是显存问题❌ 已驳斥错误可能发生在 prefill、decode、其他阶段
启动失败用"降低运行请求数"通用答案❌ 已驳斥启动失败要先查初始化日志、模型版本、硬件
三个 FAQ 参数一起调❌ 已驳斥一次只改一项;可能多变量折叠
用 19/20 一次结果就声称稳定 95%❌ 已驳斥20 样本不足,需更多样本和重复验证
浏览器总耗时减服务端平均当网络等待❌ 已驳斥跨机未校准;先同进程内时间间隔
用户点停止即服务端旧计算结束❌ 已驳斥沿请求 ID 看取消是否被接收、任务是否终结
客户端立即重试 + 旧工作仍在 = "并发忽然变大"❌ 已驳斥重试放大了负载,不是真实并发变化
同一长输入 OOM 后原样重发❌ 已驳斥原样重发通常不改变原因
取消后沿用允许迟到完成的统计❌ 已驳斥取消策略下工作量和终止方式都变了
写业务接口的 Agent 因生成超时直接重跑❌ 已驳斥外部动作可能已发生,需要先确认

文章正文

本地问一句、答一句,服务一直正常。接进应用以后,几个人同时提问,有人等很久,有人的请求直接失败。GPU 显存显示已经用了 92%,于是团队准备先把并发调小。

这可能减少失败,也可能把同一批工作推到更长的队列里。为了看清区别,下面跟随一次教学排障:先辨认"显存高但仍在正常处理"的现场,再找到长请求的输入阶段 OOM,只改一个参数,最后算出为什么错误消失了,服务仍未达标。

全文数值、请求和结果均为作者设计的教学数据,不是 SGLang GPU 实测,也不是通用参数推荐。 我们假设只有一个推理副本,采用同一批 20 个请求复测;业务要求从客户端实际提交开始,8 秒内得到内容完整、质量合格的回答,并希望至少 95% 请求达标。先定这个标准,才能知道改动究竟改善了什么。

显存高、排队和OOM的区别

显存接近满,为什么还不能直接判定故障

推理服务会把显存分给权重、KV Cache 等用途,并为计算留空间。预先划给缓存的空间也会体现在占用里。因此,nvidia-smi 的 92% 只能说明看到了较高占用,不能替代内存分配失败的证据。

先把同一副本、同一时间段的记录放在一起。假设第一次观察时,运行请求数为 8,排队数为 12;随后运行数维持在 8 左右,队列逐渐回落。对应请求最终结束,进程没有重启,保存的该时间窗日志中也没有匹配的 OOM。此时更合理的描述是"存在等待,尚无内存分配失败证据",而不是"显存已经爆了"。

SGLang 生产指标文档说明,可以用 --enable-metrics 开启指标,其中包含 sglang:num_running_reqssglang:num_queue_reqssglang:time_to_first_token_seconds。前两项帮助看运行和排队,后一项观察首 token 等待分布。它们是定位入口,不是完整逐请求诊断。

这一步有几个很容易把结论弄错的细节。运行数为 8,不单独证明运行上限配置就是 8;需要核对实际启动参数和调度约束。队列必须来自这个模型副本,不能拿网关总队列或多个副本的合计去解释单卡现象。服务端统计的 TTFT 也不自动等于浏览器显示第一段字的等待,前面还可能有网关和客户端开销。

如果你只有一张显存截图,缺少请求结果和完整日志,那么正确状态是证据还不够。没有收集到错误不等于没有错误。先补观测,比根据 92% 连降三个参数更有用。

官方运行数与排队数定义

服务还没起来,先别把它当成并发问题

还有一种现场需要先从这条排障路径分出去:业务请求尚未发出,服务就在模型加载或初始化时失败。此时不存在可供解释这次失败的业务请求队列。保存启动日志、模型版本、硬件与完整启动参数,先区分明确的 OOM、通信错误和其他初始化异常。

官方 FAQ把初始化或运行中卡住单独讨论,可能涉及内存、网络通信或其他问题。不能用"降低运行请求数"作为启动失败的通用答案。我们下面的教学记录,前提都是服务已完成启动,并能接收请求;启动耗时与重启损失单独保留。

长文一进来就失败,先看 prefill

继续收集证据后,假设我们获得了另一轮可复现记录:20 条请求里有 16 个短输入、4 个长输入,长请求都没有产生首 token,错误栈和阶段记录共同指向 prefill 内存分配失败。Prefill 是处理输入 token 的阶段;这次真正支持调参方向的是请求关联和错误位置,不是"用户没等到第一句话"。没有首 token 也可能来自路由、网络或初始化问题,不能单独定位 OOM。

先打开这四条请求的实际输入。如果应用把同一检索段落拼了三遍,优先修正拼接。修复输入会改变工作负载,要保存新样本并重新建立基线,不能把收益冒充为引擎参数调优。若内容确实需要那么长,再考虑输入处理的分块大小。

SGLang FAQ 的 OOM 条目给出的方向是:prefill OOM 可尝试减小 --chunked-prefill-size,代价可能是长输入处理更慢。本例假设当前安装版本接受原配置 8192,本轮只把它改成 4096。两个数只是说明如何设计单变量对照,不表示任何模型都应该采用 4096。

在改动之前,把待复放的工作保存完整。每条请求保留应用 ID、模板后的输入 token 数、脱敏请求体摘要、计划到达偏移、输出上限和答案合格条件。本轮仍然采用 16 短、4 长的相同顺序,不等前一条完成才发下一条,也不自动重试。客户端另记实际发送时刻;若连接池使发送比计划晚,不能把客户端等待混算为服务端排队。

同时保存模型与分词器 revision、精度、硬件、引擎版本、完整启动参数和配置摘要。停止旧进程后,确认新进程实际加载了 4096,再开始复放;配置文件已经改了而接流量的进程没变,后面的比较就失去意义。实验在隔离环境完成,不把重启损失混进稳定运行期的耗时。

缓存状态也要控制。两轮都从相同的业务缓存起点进入,预热请求单独标记并等它结束;冷起点与预热后的结果分别保存。不能先用原配置跑一遍长文,再让新配置直接利用上一轮留下的缓存,并把变快全部归功于减小分块。

完成这些准备后,得到以下教学结果。这里不是 SGLang 输出的原始日志格式,而是从逐请求记录归类后用于手算的表。

同一批 20 个请求,逐条跟踪到终结原配置 8192只改分块为 4096
正常结束且内容、质量合格1620
明确的 prefill OOM 失败40
8 秒内完整合格结束1216
正常合格结束但超过 8 秒44
失败或未达标合计84

先读清楚各行关系:原配置的 16 条正常结果由 12 条及时结束、4 条迟到组成,另有 4 条 OOM;修改后的 20 条都正常,但仍有 4 条迟到。不能把"正常结束"与"8 秒内结束"相加,它们是包含关系。

这轮观察器允许超过 8 秒的请求继续运行到结束,用于区分迟到与失败。8 秒是验收截止线,本轮不是在第 8 秒强制取消。如果实际应用会取消,就另跑一轮启用相同取消策略的对照,不能借上表宣称真实超时用户后来都获得了答案。若真实 OOM 导致进程退出,还必须计入连带失败、未决请求和重启损失;本表不保证引擎遇到 OOM 后只损失那四条。

按全部 20 次提交作分母,达标率从 12/20=60% 提高到 16/20=80%;OOM 从四次变成零次。但 80% 仍低于事先定的 95% 目标。这里消除的是一种错误现象,没有完成容量与等待验收。对 20 个样本而言,95% 至少意味着 19 条达标;即使下一轮碰巧达到 19 条,也需要更多样本和重复验证才能主张稳定服务水平。

官方prefill和decode调整入口

多个人回答到一半失败,再看 decode 压力

不要因为本例剩下四条迟到,就顺手再降低运行请求上限。先看每条迟到在哪一段:客户端提交到得到结果的总时长是一层,服务端接纳、开始计算、首 token、生成结束又是另一层。通过请求 ID 关联这些记录,才能判断是在等资源、处理长输入,还是生成太久。

如果另一个现场的错误发生在多个请求已经开始生成之后,而且分配失败位置明确指向 decode,才转入解码阶段的排查。生成阶段会延长序列,多条长回复一起运行可能形成不同于 prefill 的压力。官方 FAQ 对这种 OOM 的建议之一是降低 --max-running-requests,限制同时运行的请求数。

它不会消除原来的工作量。假设降低后中断减少,队列却更长,就需要把完整回答数、等待和超时一起放回同一批请求;不能只截取"错误为零"那一列。对于刚才的 4096 实验,若要试这个参数,应当另建一轮,明确保留还是回退分块改动,不把多个变化折叠成一次"调低并发"。

输出长度同样需要保留证据。查询订单状态只需要一段短回答,却允许无限展开,会让个别请求占用很久;但把所有输出强行截短也可能丢掉任务结果。限制输出前先写清所需内容,重测后同时记录实际 token 数、结束原因和答案完整性。更短的回答如果缺了用户要的信息,不能算作本例的合格结束。

降低静态显存比例,有什么代价

官方 FAQ 还给出减小 --mem-fraction-static 的方向,让运行时计算获得更多空间;相应地,KV Cache 内存池预算会缩小,最大并发与峰值吞吐也可能受影响。因此"显存曲线变低"不是独立的成功标准,仍要回到同一批请求的结果。

在我们的 prefill 案例里,已有明确的阶段证据,所以第一轮选择分块参数。若再考虑静态比例,需要说明新证据:是否仍发生内存分配失败,缓存预算是否已经成为容量约束,哪些请求因此等待。不要因为三个参数都出现在 FAQ 的 OOM 条目里,就认为应该一起调低。

错误类型也不能省略。非法内存访问或进程异常退出可能涉及内核、版本或内存等原因,先保留完整错误与复现条件。把它们全部归为"参数太激进",会让后面的每一轮实验都围绕未经确认的根因旋转。

请求只是排队时,应用也要做一点事

回到表中修改后的四条迟到请求。继续观察到终结的方式帮助我们定位,但实际客服不一定愿意一直等。应用需要明确等待多久后停止、如何告知用户,以及是否取消后端任务。这是另一组需要验证的行为,不能用一次 GPU 参数实验顺便宣布已经完成。

例如,用户在第 8 秒点击停止,前端不再显示,连接也关闭了,但这些事件本身不证明服务端的旧计算已经结束。沿同一请求 ID 查看取消是否被接收、任务是否终结,以及资源和请求计数是否回落。若客户端立即重试,而旧工作仍在执行,两次计算可能重叠;看起来是"并发忽然变大",实际却是应用重试放大了负载。

重试策略要按错误分类。瞬时连接故障可以有受限重试;同一个超长输入反复触发同一 OOM,原样重发通常不会改变原因。对已经调用写业务接口的 Agent,还要先确认外部动作是否发生,不能因为生成答案超时就重跑整条业务操作。

验证取消时,仍保存原来的 20 个请求,明确哪些会到达截止线、哪些会被取消、有没有重试,并单列该策略下的有效完成数和资源终结证据。取消后的计数不能直接套用允许迟到完成的那张表,因为工作量与终止方式已经变了。

取消与重试需要分开验证

下一次改配置前,留下能复现这次问题的材料

改参数前后记录同一组请求

补齐四条迟到请求的时间线时,要小心时钟。客户端和服务端没有校准,不能拿客户端提交时间直接减服务端接纳时间来算网络等待。分别计算各自时钟域内的时长,再按请求 ID 关联;需要跨机器分段时,先建立可用的时钟或 tracing 条件,并保留误差说明。

服务端 TTFT histogram 可以展示同窗口的分布变化,却不能替代 R17 这一条请求的完整经历。应用 ID、输入长度和错误阶段需要日志或 tracing 提供,也不能宣称默认 /metrics 已经包含逐请求记录。只有 20 个样本时,先看逐条明细和计数,不用一个看似精确的 p99 掩盖样本不足。

如果迟到主要发生在接纳前或排队中,下一轮才有理由验证接纳、分流或容量方案;若接纳很快、输入处理段长,继续检验长短输入的干扰;若首 token 很快但结束迟,回到输出长度与解码段。这些方向都需要阶段记录支持,不能凭用户说"卡"替他选好参数。

本轮最后应当留下的结论是:"相同 20 请求、相同缓存起点下,只把分块从 8192 改为 4096,教学记录中的 prefill OOM 从 4 次降到 0,8 秒达标率从 60% 升到 80%,仍未达到 95%。保留原配置与新配置、请求明细和错误证据,接着查四条迟到;取消策略尚未在本轮验证。"

同时写清回退条件:目标错误未改善、同批达标完成数减少,或者短请求出现不可接受的退化,就恢复保存的原配置。更新模型或运行时后重新复放。一次调整的价值在于让问题范围缩小,并留下下一步能继续核查的证据;"进程不再报错"还不是多人服务已经可用的证明。

参考资料

  • SGLang FAQ:OOM 与常见运行问题
  • SGLang 服务端参数
  • SGLang 生产指标

资料复核于 2026-09-12。官方链接支撑按阶段排查的方向与指标定义;20 请求、92% 显存、8192→4096 对照及所有结果属于教学构造,未执行 GPU 压测。具体选项与可用值仍需核对安装版本。

配图保持方法示意与官方原文的区别;图上 2026-09-06 来源检查日期保留,相关说明于 2026-09-12 复核。20 请求对照与验收计算由正文教学表承担,不是图中展示的实测结果。


错误速查卡

症状根因定位修复
nvidia-smi 92% 直接判定 OOM显存可预先划给缓存;不等于内存分配失败同时看请求结果、错误栈、运行/排队指标补观测后再决定改参数;不要凭显存截图连降三个参数
看到排队就调小并发调小只是把工作推到更长队列区分"在排队"与"哪个阶段失败"先分诊再决定调哪一项
启动失败用"降低运行请求数"通用答案启动失败不存在业务请求队列看启动日志、模型版本、硬件、完整启动参数先区分 OOM / 通信错误 / 其他初始化异常
prefill OOM 后顺手调 --max-running-requests错误阶段不在 decode看错误栈 + 阶段记录prefill 改 --chunked-prefill-size;decode 才改 --max-running-requests
三个 FAQ 参数一起调多变量折叠,无法定位收益一次只改一项 + 保留原配置拆轮次:每个改动独立对照
19/20 一次结果就声称稳定 95%样本不足20 样本规模 + 单次扩样本 + 重复验证
浏览器总耗时减服务端平均当网络等待跨机未校准同进程内时间间隔用同进程时钟 + request_id 串联
用户点停止即服务端旧计算结束停止显示/连接关闭不等于服务端终结沿请求 ID 查取消是否被接收、任务状态、资源计数单独验证取消策略
客户端立即重试 + 旧工作仍在 = "并发忽然变大"重试放大负载看请求 ID 重复、重叠执行按错误分类重试;先确认旧工作终结
同一长输入 OOM 后原样重发OOM 原因未变看错误阶段与输入长度先处理输入或资源根因,不原样重发
取消后沿用允许迟到完成的统计工作量与终止方式已变取消策略下计数条件不同取消策略单独跑一轮对照
写业务接口的 Agent 因生成超时直接重跑外部动作可能已发生沿请求 ID 查业务接口是否已执行重跑前先确认业务动作是否完成
应用层把"队列增长"全归因于服务端并发网关/客户端/服务端混算各自时钟域内时间间隔request_id 关联各观察点
觉得 FAQ 都提到就该一起调多变量一次只改一项拆轮次,保留可恢复的原配置
凭"显存曲线变低"宣布成功曲线不替代容量与等待同一批请求的达标率仍要回到业务验收
凭"用户说卡"替他选参数缺乏阶段证据阶段记录 + 错误日志先分诊,按阶段选参数方向

作者:武子康的个人博客 发布日期:2026-09-14(资料复核 2026-09-12) 核查依据:SGLang Production Metrics 页(HTTP 200,含 sglang:num_running_reqs / num_queue_reqs 指标定义)、FAQ 页(HTTP 200,含 CUDA OOM 三个参数方向)、Server Arguments 页(HTTP 200);SGLang v0.5.19(2026-09-05)。本文 5 张配图 URL 全部 HTTP 200;20 请求对照与所有数值为作者教学构造,未执行 GPU 压测;具体选项与可用值仍需核对安装版本。

热门栏目