可观察性#

LMCache 多进程模式提供三种互补的可观察性模式:**指标**(通过 OTel 的 Prometheus 计数器)、**日志**(带有可选 OTel 日志转发的 Python 日志)和 **追踪**(OTel 跨度用于每个请求的延迟)。

这三种模式都由一个内部 EventBus 驱动,该总线将生产者(L1Manager、StorageManager、MPCacheEngine)与订阅者解耦。

快速开始#

默认情况下,**指标**和**日志记录**是启用的;**追踪**是禁用的。不需要额外的标志:

lmcache server \
    --l1-size-gb 100 --eviction-policy LRU

要启用追踪,请提供 OTLP 端点:

lmcache server \
    --l1-size-gb 100 --eviction-policy LRU \
    --enable-tracing --otlp-endpoint http://localhost:4317

配置#

参数

默认

描述

--disable-observability

关闭

主开关:完全禁用 EventBus(没有注册任何指标、日志或追踪订阅者)。

--disable-metrics

关闭

跳过指标订阅者(Prometheus 端点未启动)。

--disable-logging

关闭

跳过日志订阅者。

--enable-tracing

关闭

注册追踪订阅者。需要 --otlp-endpoint

--event-bus-queue-size

10000

事件总线队列中最大事件数,超过后将进行尾部丢弃。

--otlp-endpoint

(无)

OTLP gRPC 端点(例如 http://localhost:4317)。用于导出指标(推送模式)和跟踪。

--prometheus-port

9090

Prometheus /metrics HTTP 端点的端口。

--service-instance-id

(未设置,默认 UUID v4)

此 MP 服务器实例的标识符。作为 OTel 资源属性 service.instance.id 附加到每个指标和跨度上。当未传递该标志时,默认为启动时生成的随机 UUID v4。传递 --service-instance-id=\"\" 以强制设置显式空值。请参阅 全局资源属性

--metrics-sample-rate

0.01

跟踪生命周期直方图的块/块的比例 (0, 1.0]。计数器始终计算所有事件。默认值为 1%。

--trace-level

(无)

在给定级别启用跟踪记录。目前仅支持 storage``(记录 ``StorageManager 公共 API 调用以便离线重放)。未设置时,跟踪记录处于关闭状态。有关详细信息,请参见 追踪记录

--trace-output

(无)

写入跟踪文件的路径。如果在设置了 --trace-level 的情况下省略此项,将在 $TMPDIR 下生成一个带时间戳的文件(lmcache-trace-<pid>-<UTC>.lct),并在 INFO 级别记录其路径。

环境变量:

变量

默认

描述

LMCACHE_LOG_LEVEL

INFO

控制所有 LMCache 日志记录器的日志级别。有效值:DEBUGINFOWARNINGERRORCRITICAL

指标#

通过 OpenTelemetry 计数器收集指标,并通过进程内的 Prometheus /metrics HTTP 端点导出(默认端口 9090)。当设置 --otlp-endpoint 时,指标也会推送到 OTel 收集器。

All metrics use the lmcache_mp. prefix (multiprocess). On Prometheus, dots are converted to underscores and counters get a _total suffix (e.g. lmcache_mp_l1_read_chunks_total).

全局资源属性#

每个由 MP 服务器导出的指标和跨度都携带在启动时构建的资源级属性。这些属性标识生成遥测的进程,并且与每个指标的属性(例如 cache_salt)是正交的。

属性

命令行标志 / 配置

未设置时的默认值

service.instance.id

--service-instance-id / ObservabilityConfig.service_instance_id

在启动时生成的随机 UUID v4。

资源属性附加到 MeterProvider / TracerProvider 并通过 OTLP 传播到每个导出的数据点。在 Prometheus 中,SDK 资源属性出现在 target_info 系列上,而不是每个时间序列上——这是标准的 OTel 行为。

L1 指标#

指标

类型

描述

lmcache_mp.l1_read

计数器

Number of chunks read from L1.

lmcache_mp.l1_write

计数器

Number of chunks written to L1.

lmcache_mp.l1_evicted

计数器

Number of chunks evicted by the EvictionController.

lmcache_mp.l1_eviction_loop_ticks

计数器

L1 逐出循环迭代(每个周期,无论水位线是否被跨越)。由 L1_EVICTION_LOOP_TICK 驱动。

lmcache_mp.l1_eviction_loop_triggered

计数器

L1 逐出循环迭代,其中 usage >= watermark 且逐出策略实际运行。两个计数器区分“循环仍在运行”和“逐出已触发”——在调试完成速度快于 1 Hz 轮询周期的短期基准时,这一点很重要。

L1 块生命周期直方图#

通过 L1LifecycleSubscriber 进行采样的(默认 1%)块级生命周期跟踪。只有采样的块会对直方图产生贡献;上述计数器始终计算所有事件。采样是确定性的(基于哈希),因此相同的键总是会得到相同的决策,且没有内存开销。

指标

类型

描述

lmcache_mp.l1_chunk_lifetime

直方图

每个采样块从分配到逐出的时间。

lmcache_mp.l1_chunk_idle_before_evict

直方图

每个采样块从最后访问到逐出的时间。

lmcache_mp.l1_chunk_reuse_gap

直方图

同一块的连续访问(读取或写入)之间的时间间隔。

lmcache_mp.l1_chunk_evict_reuse_gap

直方图

逐出到下次重用的时间(上限为 300 秒)。

存储管理器真实重用指标#

SMLifecycleSubscriber 发出的工作负载级重用直方图,由面向调用者的 StorageManager 事件驱动(SM_READ_PREFETCHED_FINISHEDSM_WRITE_FINISHED)。 存储/预取控制器的内部读锁释放被排除,因此信号仅反映用户驱动的访问。

两个直方图都标记有 cache_salt 以实现每个租户的隔离。每个块的每次读取和写入(无论是否采样)都会使每个盐值的访问计数器增加,因此块间隙反映了真实的存储量;直方图本身仅记录通过(确定性、基于哈希的)采样门的块的间隙。

指标

类型

描述

lmcache_mp.real_reuse_gap

直方图(标签:cache_salt

块的最后一次访问(读取或写入)与下一次读取之间的时间间隔。捕获存储成本——一个存储块在访问之间静止了多久。仅在读取事件中发出。

lmcache_mp.real_reuse_gap_objects

直方图(标签:cache_salt

每个 cache_salt 的访问计数器在同一块的两次读取之间的间隙。捕获存储量——在此块等待下一个读取时发生了多少次块访问。在采样块的读取事件中发出。

L2 指标#

指标

类型

描述

lmcache_mp.l2_store_submitted

计数器

Number of L2 store requests submitted.

lmcache_mp.l2_store_submitted_objects

计数器

Number of chunks submitted for L2 store.

lmcache_mp.l2_store_completed

计数器 (属性: l2_name)

Number of L2 store requests completed, labeled by adapter type.

lmcache_mp.l2_store_completed_objects

计数器

Number of chunks successfully stored to L2.

lmcache_mp.l2_prefetch_lookup

计数器

L2 预取查找请求的数量。

lmcache_mp.l2_prefetch_lookup_objects

计数器

Number of chunks submitted for L2 prefetch lookup.

lmcache_mp.l2_prefetch_hit

计数器

Number of prefix chunks found in L2 lookup.

lmcache_mp.l2_prefetch_load_submitted

计数器

Number of L2 prefetch load requests submitted.

lmcache_mp.l2_prefetch_load_submitted_objects

计数器

Number of chunks submitted for L2 load.

lmcache_mp.l2_prefetch_load_completed

计数器

Number of chunks successfully loaded from L2.

lmcache_mp.l2_load_completed

计数器 (属性: l2_name)

Number of per-adapter L2 load requests completed, labeled by adapter type.

The l2_name-labeled counters (l2_store_completed and l2_load_completed) exist so dashboards can compute per-backend IOPS on demand via rate(lmcache_mp_l2_store_completed_requests_total{l2_name="..."}[1m]) (and the equivalent for loads). No separate *_iops metric is exported; keeping the raw counter lets dashboard users pick their own window.

失败与健康计数器#

在专用的 lmcache_mp.health OTel 计量器上发出的健康监测计数器。由 L1FailureMetricsSubscriberL2FailureMetricsSubscriber 驱动,这些订阅者在启用指标时会自动注册。所有三个计数器都携带 model_name``(从每个 ``ObjectKey 中提取),以便操作员可以在 Prometheus /metrics 端点上按模型进行切片。

指标

类型

描述

lmcache_mp.l1_allocation_failure

计数器

reserve_write 期间发生 L1 内存分配失败(OOM)。通过 during ∈ {l1_store, l2_prefetch} 标记,以区分用户发起的存储与预取触发的分配,以及 model_name

lmcache_mp.l1_read_failure

计数器

L1 reserve_read 失败。标记为 during ∈ {l2_store, l1_retrieve},reason ∈ {not_found, write_locked},加上 model_name后查找异常计数器,而不是缓存未命中计数器——在 MP 模式下,reserve_read 仅在成功查找后调用,因此任何非零值都表示查找/保留竞争或意外逐出,健康运行时应保持接近零。

lmcache_mp.l2_prefetch_failure

计数器

Chunks that L2 reported present at lookup but failed to land in L1. Tagged by reason ∈ {l1_oom, not_found} plus model_name. l1_oom means L1 had no room to receive the prefetched object; not_found means the adapter returned no data despite a positive lookup (e.g. concurrent delete).

一旦 L2 适配器区分反序列化错误和缺失对象,将会将 reason=serde_failure 值作为附加的、非破坏性的扩展添加到 l2_prefetch_failure 中——当这项功能上线时,无需进行仪表板迁移。

有关完整的设计原理(包括哪些事件类型驱动每个计数器以及为什么推迟 lmcache_instance_id),请参阅源树中的 docs/design/v1/mp_observability/METRICS.md

查找命中率指标#

按令牌级别计数器,其比例表示由查找请求的令牌中,从 L1 或 L2 服务的令牌的比例。L0(GPU 前缀缓存)故意被排除在外——它是 vLLM 所有的,无法从 LMCache 中观察到。

指标

类型

描述

lmcache_mp.lookup_requested

计数器(属性:model_name, cache_salt

提交查找的总令牌数(L1+L2 令牌级命中率的分母)。仅计算与块对齐的令牌。

lmcache_mp.lookup_hit

计数器(属性:model_name, cache_salt

在查找过程中在 L1 或 L2 中找到的总令牌数(L1+L2 令牌级命中率的分子)。仅计算连续前缀命中。

这两个计数器由同一事件(MP_LOOKUP_PREFETCH_END)驱动,因此它们在每次完成查找时总是一起增加。提前退出的查找对两者都贡献 0,而放弃的查找则对两者都没有贡献。

model_namecache_salt 属性在查找时从 IPCCacheEngineKey 中捕获,以便仪表板可以计算每个模型或每个租户的命中率。cache_salt 可能具有高基数(每个租户或隔离域一个条目);如果存储成本重要,请在抓取时通过 metric_relabel_configs 丢弃它。

PromQL 查询命中率:

# Aggregate (all models, all salts):
rate(lmcache_mp_lookup_hit_tokens_total[5m])
/ rate(lmcache_mp_lookup_requested_tokens_total[5m])

# Per-model:
sum(rate(lmcache_mp_lookup_hit_tokens_total[5m])) by (model_name)
/ sum(rate(lmcache_mp_lookup_requested_tokens_total[5m])) by (model_name)

L0 (GPU) 块生命周期直方图#

通过 L0LifecycleSubscriber 采样(默认 1%)GPU KV Cache 块生命周期跟踪。在重新分配时(当块被分配不同的令牌时)检测逐出。采样使用随机选择,并带有一个 _skipped 集(受物理 GPU 块有限数量的限制)。

所有 L0 直方图都带有 instance_idmodel_name OTel 属性,从而支持在 Prometheus 中按实例和按模型进行指标切片(例如 lmcache_mp_l0_block_lifetime_seconds{instance_id=\"12345\",model_name=\"llama-7b\"})。

指标

类型

描述

lmcache_mp.l0_block_lifetime

直方图

每个采样的 GPU 块从分配到逐出的时间。

lmcache_mp.l0_block_idle_before_evict

直方图

从最后访问到逐出的时间(每个采样的 GPU 块)。

lmcache_mp.l0_block_reuse_gap

直方图

同一 GPU 块的连续访问之间的时间间隔。

L0 ↔ L1 吞吐量直方图#

每个请求的 GPU↔CPU 复制吞吐量通过 L0L1ThroughputSubscriber 进行记录。每个存储/检索请求为相应的直方图贡献一个样本:total_bytes / (end_ts - start_ts),单位为 GB/s。时间戳来自在 GPU cupy 流上发布的 MP_{STORE,RETRIEVE}_{START,END} 事件,因此它们反映了真实的 GPU 流复制时间——而不是 Python/锁的开销。

All throughput histograms are emitted with engine_id (vLLM worker instance id), device (e.g. "cuda:3"), and model_name OTel attributes, enabling per-worker, per-device, and per-model slicing in Prometheus (e.g. lmcache_mp_l0_l1_store_throughput_GB_per_second{engine_id="0",device="cuda:3",model_name="meta-llama/Llama-3.1-8B"}).

指标

类型

描述

lmcache_mp.l0_l1_store_throughput

直方图

每个请求的 GPU→CPU (L0→L1) 存储吞吐量(单位:GB/s)。

lmcache_mp.l0_l1_load_throughput

直方图

每个请求的 CPU→GPU (L1→L0) 加载吞吐量(GB/s)。

L1 ↔ L2 吞吐量直方图#

Per-request throughput of L1↔L2 transfers via L2ThroughputSubscriber. The store path correlates L2_STORE_SUBMITTEDL2_STORE_COMPLETED by (adapter_index, task_id). The load path correlates the per-adapter L2_LOAD_TASK_SUBMITTEDL2_LOAD_TASK_COMPLETED events by (request_id, adapter_index); the request-level L2_PREFETCH_LOAD_* events used by the chunk-count counters aggregate across adapters and cannot be attributed to a specific l2_name.

时间戳跨越 提交 → 完成,因此持续时间包括适配器队列、网络和磁盘 I/O — 该值为 字节 / 端到端延迟,而不是原始传输速率。使用这些直方图来比较适配器类型并捕捉回归;当您需要纯粹的复制时间吞吐量时,请使用 L0↔L1 直方图。

All L1↔L2 throughput histograms carry a single l2_name OTel attribute — the registered adapter type (e.g. "fs", "nixl_store", "mooncake_store") — enabling per-backend slicing in Prometheus (e.g. lmcache_mp_l2_store_throughput_GB_per_second{l2_name="nixl_store"}).

指标

类型

描述

lmcache_mp.l2_store_throughput

直方图

L1→L2 store throughput in GB/s per request.

lmcache_mp.l2_load_throughput

直方图

每对(请求,适配器)的 L2→L1 加载吞吐量(单位:GB/s)。

引擎计数器#

与 MP 服务器通过 retrieve() 返回给每个 vLLM 工作线程相关的工作线程范围计数器。通过 ``worker_id``(vLLM 工作线程实例 ID)标记——与可能出现在其他指标上的任何调度器范围 ID 不同。

指标

类型

描述

lmcache_mp.num_chunks_loaded

计数器(属性:worker_id, model_name, cache_salt

加载到引擎中的 LMCache 块的总数,按所有 retrieve() 完成的总和计算。可以按工作者、模型和租户/隔离域(cache_salt)进行切片。cache_salt 可能具有高基数;如果存储成本很重要,请在抓取时使用 metric_relabel_configs 丢弃它。

可观察的仪表盘#

通过 register_gauge 注册的时间点状态快照(基于拉取的 OTel 可观察量度)。

这三个正在进行的指标携带两个属性,即使注册了多个相同后端类型的适配器,也能区分它们——与 lmcache_mp.l2_store_completed 具有相同形状:

  • l2_name — 注册的适配器类型(例如 "fs", "nixl_store", "mooncake_store")。

  • adapter_index — 控制器适配器列表中的位置。

没有正在进行的工作的适配器不会为该抓取发出数据点。

指标

类型

描述

lmcache_mp.active_prefetch_jobs

可观察仪表

当前正在进行的预取作业数量。持续的高值可能表示 L2 后端缓慢或轮询延迟。

lmcache_mp.l1_memory_usage_bytes

可观察仪表

当前在 L1 中占用的字节数。持续上升而没有达到平稳状态通常表示存在泄漏;在配置的 --l1-size-gb 达到饱和时表示工作集超过了容量。

lmcache_mp.l1_usage_ratio

可观察仪表

L1 使用/总比率 (0.01.0),在抓取时从 L1Manager.get_memory_usage() 采样。当计量目标尚未连接或 total_bytes 为零时返回 0.0,因此在抓取期间回调不会触发。与逐出水位线 (默认 0.8) 进行比较,以判断逐出循环是否低于或高于触发阈值。

lmcache_mp.l2_usage_bytes

ObservableGauge (attr: l2_name)

Bytes currently held in each L2 adapter, sampled at scrape time from adapter.get_usage(). One observation per configured adapter, tagged by l2_name (the adapter type, e.g. "fs", "nixl_store", "mooncake_store"). Parallel to l1_memory_usage_bytes for the L2 tier — use it to see how much each L2 backend currently holds. Adapters whose get_usage() raises are skipped silently rather than poisoning the observation, so a missing datapoint for one l2_name can mean either "not configured" or "adapter errored on this scrape" — cross-check with the L2 store/load counters.

lmcache_mp.num_inflight_l2_stores

可观察的仪表 (属性: l2_name, adapter_index)

每个适配器当前正在执行的 L2 存储任务。 持续的非零值表明适配器无法跟上 L1 → L2 写入速率。

lmcache_mp.num_inflight_l2_loads

可观察的仪表 (属性: l2_name, adapter_index)

每个适配器当前正在执行的 L2 → L1 预取加载任务。与 num_inflight_l2_stores 配对,以查看给定后端是以读取流量还是写入流量为主。

lmcache_mp.inflight_load_memory_usage_bytes

可观察的仪表 (属性: l2_name, adapter_index)

每个适配器保留的 L1 字节,用于正在进行的 L2 → L1 预取加载。随着正在进行的字节和 l1_memory_usage_bytes 的增加,预取保留正在挤占可缓存数据。每个适配器的字节归属遵循每个请求的 load_plan 位图,因此跨适配器求和时不会重复计算。

事件总线自我监控#

EventBus 本身的健康指标,由 EventBusSelfMetricsSubscriberlmcache.event_bus OTel 计量器上注册。这些指标通过 EventBus 访问器直接观察总线状态,并在每次 OTel 抓取时报告——它们不是由事件驱动的,因此丢弃或失败的订阅者无法使其静默。

使用它们来回答:EventBus 是否能够跟上发布者,是否有任何事件被丢弃,以及是否有任何订阅者回调抛出异常?非零的 dropped_events_total 或持续非零的 drain_lag_seconds 表明总线处于 --event-bus-queue-size 并且正在尾部丢弃;请提高该标志或调查慢速订阅者。

指标

类型

描述

lmcache_mp.event_bus.queue_depth

可观察仪表

事件总线中当前排队的事件(在抓取时的 len(_queue))。

lmcache_mp.event_bus.drain_lag_seconds

可观察仪表

自最旧的排队事件发布以来的秒数;当为空时为 0.0。值上升意味着排出线程落后。

lmcache_mp.event_bus.dropped_events_total

可观察计数器

由于 EventBus 队列达到 --event-bus-queue-size,累计丢弃的事件。

lmcache_mp.event_bus.subscriber_exceptions

可观察计数器 (属性: subscriber_name)

由 EventBus 分发期间由订阅者回调引发的累计异常,按 subscriber_name 标记(对于绑定方法为失败回调的拥有类,对于自由函数为 __qualname__)。

有关完整的设计原理及支持每个指标的进程内访问器,请参见源代码树中的 docs/design/v1/mp_observability/METRICS.mddocs/design/v1/mp_observability/event-bus.md

Prometheus 抓取配置#

将 LMCache 服务器添加为 Prometheus 抓取目标:

scrape_configs:
  - job_name: "lmcache-mp"
    static_configs:
      - targets: ["<lmcache-host>:9090"]

日志记录#

日志订阅者通过 Python 的标准 logging 模块为存储、检索、查找、L1 和 StorageManager 事件发出调试级别的消息。

当安装了 OpenTelemetry 时,init_logger 会自动附加一个 OTel LoggingHandler,以便将日志记录转发到任何配置的 OTel LoggerProvider。该处理程序遵循 LMCACHE_LOG_LEVEL 环境变量。

LMCACHE_LOG_LEVEL=DEBUG lmcache server ...

关键日志消息:

级别

消息

信息

X 秒内存储了 N 个令牌

信息

Retrieved N tokens in X seconds

信息

Prefetch request completed (L1+L2): N/M prefix hits

调试

MP store start: session=... device=...

调试

MP retrieve end: session=... retrieved_count=...

追踪#

备注

--enable-tracing 要求 设置 --otlp-endpoint。如果在没有 OTLP 端点的情况下启用追踪,服务器将拒绝启动,因为没有本地回退用于追踪导出。

当启用追踪时(--enable-tracing --otlp-endpoint <URL>),追踪订阅者会从 START/END 事件对创建 OTel spans:

  • mp.store — 从 MP_STORE_STARTMP_STORE_END

  • mp.retrieve — from MP_RETRIEVE_START to MP_RETRIEVE_END

  • mp.lookup_prefetch — from MP_LOOKUP_PREFETCH_START to MP_LOOKUP_PREFETCH_END

每个跨度携带事件元数据作为跨度属性(例如 devicestored_countfound_count)。

在任何 OTel 兼容的后端中查看追踪,例如 JaegerGrafana Tempo

# Start Jaeger all-in-one (OTLP gRPC on 4317)
docker run -d --name jaeger \
    -p 16686:16686 -p 4317:4317 \
    jaegertracing/all-in-one:latest

# Start LMCache with tracing
lmcache server \
    --l1-size-gb 100 --eviction-policy LRU \
    --enable-tracing --otlp-endpoint http://localhost:4317

每个请求的命中率属性#

每个会话都被包装在一个按请求的根跨度中——标准 MP 路径的 request 和 CacheBlend 路径的 cb.request——它将所有子跨度(mp.storemp.retrievemp.lookup_prefetch)嵌套在其下。当查找阶段结束时,根跨度会用三个 OTel 属性进行注释,这些属性总结了请求级别的缓存命中率:

属性

OTel 类型

描述

hit_tokens

int

从 L1+L2 服务的令牌(分子)。

requested_tokens

int

用于查找的块对齐令牌(分母)。

hit_rate

float

hit_tokens / requested_tokens; 0.0 当分母为零时。存储为预计算的浮点数,因为跟踪用户界面(Tempo, Jaeger)无法在查询时从两个整数属性中推导出它。

属性在处理 MP_LOOKUP_PREFETCH_END``(标准 MP 路径)或 ``CB_LOOKUP_END``(CacheBlend 路径)时被写入——当根跨度仍然打开时。**仅存储请求**在未调用 ``lookup_prefetch_start() 时不会为查找阶段发出结束事件,因此它们的根跨度将不会携带这些属性。

示例 TraceQL 查询 (Grafana Tempo):

# Requests with less than 50% cache hit rate
{ name = "request" && span.hit_rate < 0.5 }

# Full cache hits only
{ name = "request" && span.hit_rate = 1.0 }

# Complete misses (lookup ran but nothing was cached)
{ name = "request" && span.requested_tokens > 0 && span.hit_tokens = 0 }

有关完整的事件到跨度映射以及将子跨度链接回根的注册模式,请参见源树中的 docs/design/observability/request-event-span.md

追踪记录#

备注

跟踪记录与 --enable-tracing``(OTel spans)是 **不同的**。跟踪记录捕获每个对二进制文件的 ``StorageManager 公共 API 调用,以便可以在后续进行测试、回归查找和基准测试时 重放 相同的工作负载——无需 vLLM,并且最终无需 GPU。--enable-tracing 将实时 OTel spans 导出到 OTLP 端点以进行在线可观察性。这两个功能是独立的,可以一起使用。

当设置 --trace-level storage 时,LMCache 会将每次对 StorageManager.{reserve_write, finish_write, submit_prefetch_task, read_prefetched_results, finish_read_prefetched} 的调用记录到一个二进制文件中,以便后续重放。

记录默认是**关闭的**,关闭时几乎没有开销(每个``StorageManager``调用只需进行一次布尔检查)。开启时,记录发生在 EventBus 排出线程上,而不在请求路径上。

捕获跟踪#

带有显式输出路径:

lmcache server \
    --l1-size-gb 100 --eviction-policy LRU \
    --trace-level storage --trace-output /tmp/run.lct

$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"

在关闭时(SIGTERM 由 EventBus 停止路径处理),跟踪文件会被干净地关闭。

重放#

重放记录的追踪,以及用于驱动、监控和导出重放结果的完整 CLI 标志集,详见其独立页面: 追踪和调试

捕获了什么(以及未捕获的内容)#

捕获:

  • 每个被装饰的 StorageManager 调用的完全限定名称。

  • 每个调用的输入参数(例如 keys, layout_desc, mode, extra_count, external_request_id)。

  • 每个调用的墙钟时间和单调时间戳。

  • 一个包含跟踪模式版本、开始时间和活动的 StorageManagerConfig 的 SHA-256 摘要的头部,以便重放可以检测到不匹配的配置。

未捕获:

  • KV 张量字节。重放练习的记账和控制逻辑;重放时的有效载荷为零。

  • MPCacheEngine、消息队列或任何 GPU 复制代码中的调用。这些层级在存储跟踪级别中是 超出范围 的。

文件格式#

一个长度前缀的 msgpack 流:

[4-byte big-endian length][msgpack Header]
[4-byte big-endian length][msgpack Record]
[4-byte big-endian length][msgpack Record]
...

Header 包含一个魔术前缀 (LMCT)、一个格式版本、跟踪级别 (今天是 storage)、一个跟踪模式版本、开始时间戳和 StorageManagerConfig 摘要。每个 Record 包含一个相对时间戳、一个墙钟时间戳、完全限定的调用位置 (qualname) 和一个参数字典。

该格式故意具有可扩展性:未来的跟踪 **级别**(mqgpu)将共享此布局,并使用 level 头字段进行区分。额外捕获的操作会添加新的 qualname 字符串,而不会提升格式版本。

有关完整的设计原理,请参见源代码树中的 docs/design/v1/mp_observability/trace.md