初始化
独立部署(如 online 示例)
telemetry.InitTracing(ctx)- 从环境变量读取配置(
OTEL_SERVICE_NAME,OTEL_EXPORTER_OTLP_ENDPOINT,OTEL_TRACES_SAMPLER_ARG) - 创建 OTLP gRPC Exporter(数据发送器)
- 创建 Resource(标记服务名)
- 创建
TracerProvider(核心引擎),配置WithBatcher(exporter)启动后台 goroutine 批量发送 Span - 注册
TracerProvider到全局(otel.SetTracerProvider(tp)) - 设置 W3C Trace Context 传播器
- 返回
tp.Shutdown关闭函数
- 从环境变量读取配置(
TracerProvider 内部启动一个后台 goroutine(BatchSpanProcessor),把 Span 攒成批量后通过 OTLP gRPC 发给 Collector。默认采样率 10%(可通过 OTEL_TRACES_SAMPLER_ARG 调整)。
作为库使用(如被 llm-d-router 嵌入)
- 不调用
InitTracing,库代码不初始化 Provider - 通过
otel.Tracer("llm-d-kv-cache")获取 Tracer,自动使用宿主应用初始化的全局 Provider - 如果宿主未初始化,Tracer 是 no-op 实现,所有
span.Start()/span.End()零开销
两套遥测系统
Tracing(OpenTelemetry)— 请求级分布式追踪
埋点位置(装饰器模式):
| 位置 | Span Name | 记录的 Attributes |
|---|---|---|
Indexer.ScoreTokens |
llm_d.kv_cache.score_tokens |
model, token_count, block_hit_ratio, pod_count |
TracedScorer.Score |
llm_d.kv_cache.scorer.compute |
algorithm, key_count, score.max, score.avg |
TracedIndex.Lookup |
llm_d.kv_cache.index.lookup |
block_key_count, pod_count |
Span 记录的信息:
- TraceID(关联同一请求的所有 Span,形成调用链树)
- StartTime / EndTime / Duration(自动计算耗时)
- Attributes(自定义键值对,用于调试)
- Status(成功/失败及错误信息)
Metrics(Prometheus)— 聚合指标
指标列表:
| 指标名 | 类型 | 含义 |
|---|---|---|
kvcache_index_admissions_total |
Counter | 累计 Block 写入数 |
kvcache_index_evictions_total |
Counter | 累计 Block 淘汰数 |
kvcache_index_lookup_requests_total |
Counter | 累计 Lookup 调用数 |
kvcache_index_lookup_hits_total |
Counter | 累计缓存命中数 |
kvcache_index_lookup_latency_seconds |
Histogram | Lookup 延迟分布 |
kvcache_index_max_pod_hit_count_total |
Counter | 单次查询单 pod 最大命中数 |
注入方式: NewInstrumentedIndex() 装饰器包装 Index,在 Add/Evict/Lookup 前后通过原子操作实时更新 Counter/Histogram。
暴露原理: promhttp.Handler 遍历 Registry 中所有 Collector,原子读取当前值,格式化为 Prometheus 文本协议返回。不涉及数据库,纯内存操作。
日志打印: StartMetricsLogging() 定时(如 30s)在日志中打印指标摘要。
装饰器模式
原始 Index → NewInstrumentedIndex() → NewTracedIndex() → Indexer 最终使用的 Index
原始 Scorer → NewTracedScorer() → Indexer 最终使用的 Scorer
两个 Hit 指标的区别
LookupHits 和 MaxPodHitCount 当前代码加的是同一个值 maxHit(本次查询中命中最多的 pod 的命中数),但 Prometheus 查询语义不同:
LookupHits:用于计算缓存命中率(hits / lookups)MaxPodHitCount:用于衡量路由质量(最好的 pod 有多少前缀命中)