追踪和调试#
LMCache MP 模式可以将每个 StorageManager 公共 API 调用记录到一个二进制 跟踪文件 中,并通过 lmcache trace replay 在新服务器上重新发出这些调用。该功能旨在用于:
回归排查 — 捕获生产工作负载,然后在调查中的构建上重放,以离线重现错误。
性能特征化 — 在真实的存储级访问模式下测量 L1/L2 延迟分布,无需 vLLM 或 GPU。
配置调整 — 针对不同的 L1 大小、逐出策略和 L2 适配器重放相同的跟踪,以比较它们在相同输入下的行为。
备注
跟踪记录与 ``--enable-tracing``(OTel spans)是 独立 的。OTel 跟踪将 实时 spans 导出到 OTLP 端点以进行在线可观察性;跟踪记录则持久化一个可重放的二进制文件以供离线分析。两者可以同时启用。
记录跟踪#
记录默认是**关闭的**。通过将``--trace-level storage``添加到``lmcache server``来启用它:
# Explicit output path
lmcache server \
--l1-size-gb 100 --eviction-policy LRU \
--trace-level storage --trace-output /tmp/run.lct
# Implicit timestamped path under $TMPDIR
lmcache server \
--l1-size-gb 100 --eviction-policy LRU \
--trace-level storage
# → INFO log: "trace recording enabled (level=storage); no
# --trace-output given, writing to
# /tmp/lmcache-trace-<pid>-<UTC>.lct"
通过服务器正常驱动流量(vLLM 请求、基准测试脚本等)。在通过 EventBus 停止路径接收到 SIGTERM 时,跟踪文件会被干净地关闭 — 不需要 --stop-tracing 命令。
捕获的内容:
每个被装饰的
StorageManager调用的完全限定名称(例如StorageManager.reserve_write、StorageManager.submit_prefetch_task)。每个调用的输入参数(
keys,layout_desc,mode,extra_count,external_request_id, …)。每次调用的墙钟时间和单调时间戳。
一个包含文件格式版本、跟踪模式版本、开始时间戳以及活动的
StorageManagerConfig的 SHA-256 摘要的头部,以便重放可以标记不匹配的配置。
未捕获的内容:
KV 张量字节。 重放练习的记账和控制逻辑;重放时的有效载荷为零。即使在长时间运行的情况下,跟踪文件也保持有限。
在
MPCacheEngine、消息队列或 GPU 复制代码中的调用。这些层超出了storage跟踪级别的范围。
开销:
关闭:每次
StorageManager调用进行一次布尔检查。实际上是免费的。开启:编码和文件 I/O 在 EventBus 排水线程上进行,不在请求路径上。实际上,这对请求延迟没有明显影响。
检查追踪#
在重放之前,lmcache trace info 打印一个一屏的摘要:
lmcache trace info /tmp/run.lct
Trace file: /tmp/run.lct
level: storage
format_version: 1
trace_schema_version: 1
duration: 226.691s
sm_config_digest: 0f685d8a...
total_records: 1318
ops:
lmcache.v1.distributed.storage_manager.StorageManager.finish_read_prefetched: 133
lmcache.v1.distributed.storage_manager.StorageManager.finish_write: 349
lmcache.v1.distributed.storage_manager.StorageManager.read_prefetched_results.__enter__: 96
lmcache.v1.distributed.storage_manager.StorageManager.read_prefetched_results.__exit__: 96
lmcache.v1.distributed.storage_manager.StorageManager.reserve_write: 349
lmcache.v1.distributed.storage_manager.StorageManager.submit_prefetch_task: 295
使用此功能来检查您打算重放的跟踪是否涵盖了预期的操作组合和持续时间。
重放跟踪#
lmcache trace replay FILE 重新发出每个记录的调用,使用您提供的 CLI 标志构建的 全新 StorageManager。重放端的配置由 您选择,而不是从录音中复制。这是该功能的主要价值——您可以在相同的输入上比较不同的 L1/L2 设置。
最小调用:
lmcache trace replay /tmp/run.lct \
--l1-size-gb 100 --eviction-policy LRU
--l1-size-gb 和 --eviction-policy 是必需的,就像在 lmcache server 上一样。服务器接受的任何存储管理器标志在这里也有效(--l2-adapter、--l1-use-lazy、--l2-store-policy 等);运行 lmcache trace replay --help 获取完整列表。
节奏控制。 驱动程序始终遵循记录的调用间隔时间,通过休眠来使每次调度与其记录的 t_mono 偏移对齐。没有“尽可能快”的模式:StorageManager 的读写是异步的,并且存在跨调用依赖关系(例如,检索可能依赖于先前的 L2 加载完成),因此压缩记录的间隔会导致内部队列竞争,从而导致非确定性的检索未命中。如果重放主机比记录主机慢,循环会简单地滞后于记录的时间表。
输出。 每次重放默认都会打印一个终端指标表,并写入每个 qualname 的 CSV:
=================== Trace Replay Result ======================
--------------------------- Overall --------------------------
Trace level: storage
Records replayed: 1318
Records skipped: 0
Records failed: 0
Replay duration (s): 226.69
Config digest: match (0f685d8a)
--------------------- Per-Op Latency (ms) --------------------
reserve_write count: 349
reserve_write mean: 0.16
reserve_write p50: 0.13
reserve_write p99: 0.93
...
每条记录的附加输出由以下内容控制:
标志 |
目的 |
|---|---|
|
聚合摘要文件的目录。默认:当前目录。 |
|
跳过 |
|
还会写入 ``trace_replay_summary.json``(按资格名称的计数 / 平均值 / p50 / p90 / p99 / 最小值 / 最大值,以及总持续时间)。 |
|
除了 INFO 日志外,还将每条记录打印一行 |
|
将每个重放记录写入一个 JSON 对象到 |
|
抑制终端指标表。聚合文件仍然会被写入。 |
即使没有 --verbose,驱动程序也会在 INFO 级别记录每个调度。
[1/1318] OK lmcache...StorageManager.reserve_write (0.252ms)
[2/1318] OK lmcache...StorageManager.finish_write (0.032ms)
...
进度数字来自对跟踪文件的廉价预扫描,因此您总是看到 [N/total] 而不仅仅是一个运行计数器。
重放期间的监控#
重放驱动程序在构造重放端 StorageManager 之前初始化了完整可观察性 EventBus。因此,内部事件(L1/L2 生命周期、逐出时钟、存储/检索发布等)在重放期间通过一个实时总线流动,标准订阅者——日志记录、指标、OTel 跟踪——可以附加到这些事件上。
在 lmcache trace replay 上可用的与服务器接受的相同可观察性 CLI 标志:
标志 |
效果 |
|---|---|
|
完全关闭 EventBus。没有订阅者会触发。 |
|
跳过 OTel 指标初始化和指标订阅者。对于仅想要日志时,避免绑定 Prometheus 端口非常有用。 |
|
跳过日志订阅者。 |
|
启用 OTel span 订阅者。需要 |
|
将指标/追踪导出到 OTLP gRPC 收集器(例如 |
|
用于拉取模式下 Prometheus |
|
生命周期直方图的采样率。计数器始终计算所有事件。 |
典型的监控设置:
原始日志轨迹(SM/L1/L2 事件到 stdout):
LMCACHE_LOG_LEVEL=DEBUG lmcache trace replay /tmp/run.lct \
--l1-size-gb 100 --eviction-policy LRU \
--disable-metrics
以拉取模式的 Prometheus 指标:
lmcache trace replay /tmp/run.lct \
--l1-size-gb 100 --eviction-policy LRU \
--prometheus-port 9095
# scrape http://localhost:9095/metrics from another terminal
OTel 指标 + 跟踪到收集器:
lmcache trace replay /tmp/run.lct \
--l1-size-gb 100 --eviction-policy LRU \
--otlp-endpoint http://localhost:4317 \
--enable-tracing
备注
--trace-level 和 --trace-output 标志是 仅记录 的,不被 lmcache trace replay 接受。重放不会写入新的追踪文件。
注意、提示和注意事项#
当重放环境不同时,预期会出现未命中的情况。 在重放开始时,CLI 会打印一个可见的警告横幅:
==============================================================================
!! REPLAY ENVIRONMENT MISMATCH MAY CAUSE RETRIEVE MISSES !!
==============================================================================
由于 KV 负载未被捕获,并且重放端的配置和主机速度可能与录制时不同,因此在录制时命中的检索调用在重放时可能会未命中——例如,在录制的检索发出时已完成的异步 L2 加载在重放的检索触发时可能仍在进行中。将未命中的检索计数视为重放环境的信号,**而不是**跟踪中的缺陷。
配置摘要不匹配是信息性的,而不是致命的。 无论摘要是否匹配,重放始终会运行。 不匹配仅告诉您重放端的 StorageManagerConfig 与记录时不同——这通常正是您所期望的(在同一跟踪上比较两个配置)。
Prometheus 端口绑定。 服务器的 --prometheus-port 默认值为 9090。在同一端口上与服务器并发运行 lmcache trace replay 或同时运行两个重放将会失败。请在第二次运行时传递不同的 --prometheus-port 或 --disable-metrics。
跟踪记录开销。 记录发生在 EventBus 排出线程上,而不是请求处理线程上。当禁用时(默认),门控是一个单一的布尔检查,因此关闭记录的生产构建不会产生可测量的成本。
跟踪文件未加密。 参数如 ObjectKey 块哈希以明文形式写入。请像对待缓存哈希日志一样小心处理跟踪文件。
向前兼容性。 头部携带格式版本和追踪模式版本。读取器会拒绝未知版本的文件,而不是默默地产生垃圾。捕获的 API 表面变化(追踪方法上的新参数、新的编解码器标签)会提升模式版本;框架变化会提升格式版本。
可扩展性。 该格式旨在适应未来的追踪 **级别**(mq、gpu)。在现有级别中添加一个新的追踪方法只需在记录端进行装饰,并在重放端注册一个处理程序 — 无需格式更改。
另请参阅#
追踪记录 — 可观察性页面中的短小
Trace Recording部分专注于记录端标志。docs/design/v1/mp_observability/trace.md在源代码树中 — 完整设计文档:架构、重放调度器、上下文管理器配对、统计收集器和测试矩阵。