观测、Tracing 与调试抓手#
这章解决什么问题#
这一章解决的是“当系统已经跑起来之后,出了问题先看哪里”。如果前面章节主要回答“系统怎样设计、代码在哪里”,这一章则回答“当请求异常、延迟波动、输出不稳定,或者你要定位瓶颈时,哪些 observability 和 debug 入口最值得先抓”。
这类内容不能混进前面的主线章节里讲。因为它们更多是操作层,而不是结构层。但如果完全不单独成章,读者又会在真正出问题时不知道该从 metrics、logging、trace、request dump 还是 crash dump 开始。
为什么 observability 需要独立章节#
官方 docs/advanced_features/observability.md 已经把 observability 分成三块:Production Metrics、Logging、Request Dump and Replay / Crash Dump and Replay。这种划分很有代表性,因为它说明 SGLang 并没有把“观测”理解成只有 Prometheus 指标,而是把 metrics、logs 和可复现材料都纳入观测体系。
更进一步,docs/references/production_request_trace.md 明确说 request trace 的实现落在 python/sglang/srt/observability/req_time_stats.py。这很重要,因为它把“文档层讲 tracing”与“源码层定义 request stage”连到了一起。也就是说,观测不是外围运营面板,而是 runtime 自己的一部分。
下面这张图的职责,是把 metrics、trace 和 dump / replay 这三种抓手放进同一条排障路径里。这样读者不必再靠记忆去猜“到底先看哪个”,而是能直接看出从轻量观测到重型复现的升级顺序。
flowchart TD
A["异常 / 延迟 / 输出不稳定"] --> B["Metrics\n--enable-metrics / /metrics"]
B --> C{"问题是整体性的\n还是个别请求?"}
C -->|整体趋势| D["Prometheus / production_metrics"]
C -->|单请求 / 阶段性| E["Trace\n--enable-trace / OTLP / Jaeger"]
E --> F["req_time_stats.py\nRequestStage slices"]
D --> G["需要更具体样本?"]
F --> G
G -->|是| H["Request dump / crash dump"]
H --> I["scripts/playground/replay_request_dump.py"]
G -->|否| J["回到对应 runtime 模块定位"]这张图相对于段落的增量,是把“趋势问题”“阶段问题”“复现问题”拆成三个不同层次。后文再谈具体 flags 和文件路径时,读者就不会把所有调试手段混成一个平面列表。
metrics、trace、dump / replay 分别适合解决什么问题#
metrics 适合回答“系统整体现在怎么样”。docs/references/production_metrics.md 说明了 Prometheus metrics 的导出方式,docs/advanced_features/observability.md 则强调用 --enable-metrics 启动后可以通过 /metrics 暴露。对排查吞吐、队列积压、请求量变化来说,这通常是第一层信号。
trace 更适合回答“单个请求在链路里卡在哪里”。production_request_trace.md 指出可以通过 --enable-trace 和 --otlp-traces-endpoint 打开 tracing,并把 request stage 导出到 OpenTelemetry / Jaeger。这里的关键价值不是“看图更漂亮”,而是能把 TOKENIZE、API_SERVER_DISPATCH、REQUEST_PROCESS、PREFILL_FORWARD、DECODE_LOOP 这些阶段拉开看。
request dump / replay 和 crash dump 则更像“把故障现场留下来”。observability.md 说明可以通过 configure_logging 配置 request dump folder,也可以用 --crash-dump-folder 保留崩溃前几分钟的请求,再用 scripts/playground/replay_request_dump.py 重放。这些能力特别适合复现难以稳定重现的问题。
调试时先用哪条路径#
一个更稳的顺序通常是:先看 metrics 确认问题是整体性的还是个别请求;如果是个别请求或阶段性延迟,再看 trace;如果 trace 还不够,就启用 request dump 或 crash dump,把问题样本重放出来。这样做的原因很简单:越往后,证据越具体,但成本也越高。
这里不要把这些工具混成一个“调试大全”。metrics 更适合回答趋势问题,trace 更适合回答阶段问题,dump / replay 更适合回答复现问题。把它们分别放回各自最擅长的场景,比在日志里盲搜关键词更有效。
典型现象与起手检查#
如果现象是“整体吞吐变差、队列积压变重”,先从 metrics 侧确认系统级趋势,再回到 scheduler 或 cache 章节中的对应路径。
如果现象是“个别请求延迟离谱、阶段性卡顿”,优先看 trace,尤其是 RequestStage 的阶段分布。
如果现象是“线上偶发异常、难以复现”,就应该尽快把 request dump 或 crash dump 打开,把问题从‘感觉’变成‘样本’。
这些起手顺序看似朴素,但正是把前文架构图、生命周期图和调度图真正转化为工程操作的地方。没有这一层,前面的理解很容易停留在纸面。
一个更适合发布稿的结尾提醒#
优秀技术书在排障章节里通常不会只告诉你“有哪些工具”,还会告诉你“应该先做什么,不应该先做什么”。对这一章来说,最重要的提醒只有一句:不要一出问题就先钻实现细节,而要先判断自己面对的是趋势问题、阶段问题,还是复现问题。
只要这个判断顺序对了,metrics、trace 和 replay 才会真正组成一套工具链,而不是三组分散的命令。
一个最小的排障工作流示例#
如果把前面的讨论压成一个最小工作流,可以写成下面这样:
1. 先看 metrics:确认是整体退化还是个别请求异常
2. 再看 trace:确认卡在 request lifecycle 的哪个阶段
3. 如仍无法复现,打开 request dump / crash dump
4. 拿 replay 样本回到对应章节中的代码路径继续追这个工作流的意义,不在于它能替代经验,而在于它把“全书前半部分讲的系统主线”真正变成了排障顺序。这样,调试章节就不只是工具清单,而是和整本书的逻辑闭环真正连在一起。
为什么这章放在最后仍然重要#
很多技术书在最后部分会变弱,因为作者把“原理已经讲完”当成收尾。但真正成熟的系统书往往恰恰相反:越到后面,越要把前面的理解重新变成可操作路径。观测、trace、replay 这一层之所以值得保留到最后,是因为它要求读者同时调用前面几乎所有章节的知识。
只有当你已经知道 request lifecycle 的 handoff、runtime architecture 的边界、scheduler 与 cache 的职责、execution model 的循环位置时,你才会真正看懂 metrics 或 trace 里那些阶段标签到底在说什么。这也是本章为什么不是附录,而是正文的最后一层。
本章对应哪些代码路径#
这一章最重要的锚点包括 docs/advanced_features/observability.md、docs/references/production_metrics.md、docs/references/production_request_trace.md、python/sglang/srt/observability/req_time_stats.py、python/sglang/profiler.py 与 scripts/playground/replay_request_dump.py。
要继续深挖,推荐顺序是:先看 observability 文档理解能力面,再看 production metrics / request trace 文档理解实际使用方式,最后回到 req_time_stats.py 看 request stage 是怎样定义出来的。这样能把“操作抓手”和“源码实现”接在一起。
小结#
这一章的核心不是列更多工具名,而是帮你建立一个排障顺序:先看 metrics,再看 trace,再决定是否进入 dump / replay。只要这个顺序清楚,扩展和维护时的调试成本就会下降很多,也更容易把观测结果映射回前面章节讲过的主链路与模块边界。
叶王 © 2013-2026 版权所有。如果本文档对你有所帮助,可以请作者喝饮料。