深度解读

LGTM 可观测性四件套:Grafana、Prometheus、Loki、Tempo 的生产落地

用 Grafana、Prometheus、Loki 和 Tempo 搭出指标、日志、链路追踪与告警闭环,并把采集、存储、查询和排障路径工程化。

CONVEE Research · 阅读时间 7 分钟 · 发布于 2026-06-12

#核心结论

Grafana、Prometheus、Loki、Tempo 不是四个并列面板工具,而是一套可观测性闭环:Prometheus 负责指标,Loki 负责日志,Tempo 负责分布式追踪,Grafana 负责统一查询、展示、告警和跨信号跳转。对 AI 全栈架构师来说,这套组合的价值不只是“能看到监控”,而是把一次生产故障从发现、定位、证据收集到修复验证,压成可重复的工程路径。

需要先纠正一个常见说法:Grafana 官方常把 LGTM 写成 Loki、Grafana、Tempo、Mimir,其中 Mimir 是云原生长期指标存储。很多团队在开源自建或中小规模阶段会用 Prometheus 承担 metrics 层,所以本文讨论的是更常见的自建组合:Grafana + Prometheus + Loki + Tempo。这个组合可以直接起步,但进入大规模或长期保留场景后,要为 Prometheus 增加 remote write、Mimir、Thanos 或 VictoriaMetrics 这类长期存储能力。

#技术背景

可观测性不能只看单一信号。指标告诉团队“什么时候、哪个系统指标异常”,日志告诉团队“异常现场发生了什么”,链路追踪告诉团队“一次请求穿过哪些服务、慢在哪里、失败在哪个 span”。Grafana 的角色是把这些信号放到同一个排障界面里,通过 dashboard、Explore、alert、data source 和 correlation 把上下文串起来。

Prometheus 的核心模型是带 label 的时间序列。它通过 HTTP pull 模型抓取 /metrics,用 PromQL 做聚合、窗口计算和告警规则。Loki 的设计更像“日志版 Prometheus”:它不全文索引日志内容,而是主要索引 stream labels,再把日志压缩成 chunk 放到对象存储或文件系统。Tempo 则是追踪后端,用 OpenTelemetry、Jaeger 或 Zipkin 协议接收 trace,并通过 object storage 降低大规模 trace 保存成本。

新的采集侧建议优先使用 Grafana Alloy 或 OpenTelemetry Collector。Promtail 已经在 2026-03-02 进入 EOL,后续日志采集不要再把 Promtail 作为新项目默认选型。Alloy 可以把 Prometheus 和 OpenTelemetry 管线放到同一套 collector 配置里,覆盖 metrics、logs、traces,适合 Kubernetes 和多环境统一治理。

#组件边界

组件 主要职责 查询语言 / 接口 生产边界
Grafana 仪表盘、Explore、告警、数据源管理、跨信号跳转 Dashboard query、Alert rule、Datasource plugin 不存主数据,重点治理权限、文件夹、告警规则和 datasource 凭据
Prometheus 指标采集、短中期时序存储、规则计算、告警触发 PromQL、remote write、Alertmanager 单节点自治强,但长期存储和全局查询需要扩展层
Loki 日志写入、压缩存储、按 label 查询、LogQL 分析 LogQL、Loki HTTP API 成本低,但 label 设计错误会导致查询慢或存储膨胀
Tempo trace 接收、存储、TraceQL 查询、span metrics OTLP、Jaeger、Zipkin、TraceQL Trace 价值依赖应用埋点、采样策略和 trace_id 贯穿
Alloy / OTel Collector 采集、转换、批处理、转发 telemetry Prometheus scrape、OTLP、Loki write 应作为边车或 DaemonSet 标准件,而不是每个服务单独拼采集脚本

这几个边界要守住。Grafana 不应该被当成数据仓库,Prometheus 不适合保存完整业务事件,Loki 不适合当审计全文检索库,Tempo 也不会替代日志。真正可靠的排障体验来自“职责分开、上下文打通”。

#标准数据流

一条推荐的生产数据流如下:

Application / Runtime / Kubernetes / Node
  |-- metrics: /metrics, exporter, OpenTelemetry metrics
  |       -> Prometheus scrape
  |       -> recording rules / alert rules
  |
  |-- logs: stdout, file log, structured JSON
  |       -> Alloy / Fluent Bit
  |       -> Loki labels + compressed chunks
  |
  |-- traces: OpenTelemetry SDK / auto instrumentation
          -> Alloy / OTel Collector
          -> Tempo object storage

Grafana
  -> Prometheus datasource for RED / USE metrics
  -> Loki datasource for service logs
  -> Tempo datasource for request traces
  -> alerting and drill-down links across the three signals

落地时,所有服务必须统一几个基础字段:service.namedeployment.environmentnamespacepodversiontrace_id。其中 service.name 和环境信息适合成为指标、日志和 trace 的共同过滤维度;trace_id 应写入结构化日志,并通过 Grafana derived fields 从 Loki 跳到 Tempo,但不建议把海量唯一 trace_id 当作 Loki label。

#指标层设计

Prometheus 指标层先从 RED 和 USE 两套方法起步。业务服务看 RED:请求速率 rate、错误率、持续时间 histogram。基础设施看 USE:使用率、饱和度、错误数。核心 SLI 应先变成 recording rules,再供 dashboard 和 alert rule 复用,避免每个面板都写一遍复杂查询。

示例 PromQL:

sum by (service) (
  rate(http_requests_total{job="api",status=~"5.."}[5m])
)
/
sum by (service) (
  rate(http_requests_total{job="api"}[5m])
)
histogram_quantile(
  0.95,
  sum by (service, le) (
    rate(http_request_duration_seconds_bucket{job="api"}[5m])
  )
)

指标命名要稳定,label 要克制。可以用 servicemethodroutestatus_code,但不要把 user_idorder_idrequest_id 放进 label。高基数会直接放大内存、索引、查询成本,也会让 Prometheus 在故障时先被监控数据拖垮。

#日志层设计

Loki 的关键不是“把所有日志都收进来”,而是把 label 设计好。推荐 label 控制在低基数字段:clusternamespaceservicepodcontainerlevel。高基数字段放在日志正文中,以 JSON 字段存在,再用 LogQL pipeline 解析。

示例 LogQL:

{namespace="prod", service="checkout"} |= "error"
{namespace="prod", service="checkout"}
| json
| trace_id != ""
| line_format "{{.timestamp}} {{.level}} {{.trace_id}} {{.message}}"

日志格式建议统一为结构化 JSON,至少包含 timestamplevelmessageservicetrace_idspan_idtenanterror.kind。如果日志仍是自由文本,Loki 也能查,但很难稳定地做 trace 跳转、错误聚类和告警去噪。

#追踪层设计

Tempo 的价值来自请求级上下文。接入时不要只给网关加 trace,要让入口服务、核心业务服务、数据库访问、外部 API、队列消费者都带上 span。否则 trace 图会在最关键的位置断掉,只能证明“入口慢了”,不能证明“慢在哪里”。

OpenTelemetry 侧应统一 resource attributes:

service.name: checkout-api
service.version: 2026.06.12-1
deployment.environment: prod
cloud.region: cn-shanghai
k8s.namespace.name: prod

采样策略要分层:开发和灰度环境可以高采样,生产环境默认 head sampling 或 tail sampling;错误请求、慢请求和关键租户请求应提高保留概率。Tempo 与 Prometheus 的 exemplars、Loki derived fields 结合后,可以从 P95 延迟面板直接跳到 trace,再从 trace 跳到同一 trace_id 的日志。

#Grafana 排障路径

一个成熟的 dashboard 不应该只堆图,而应该支持固定排障路径:

  1. 总览层:服务健康、请求量、错误率、P95/P99、饱和度、当前告警。
  2. 服务层:按 serviceroutestatus_code 拆解延迟和错误。
  3. Trace 层:从异常指标 exemplar 跳到 Tempo trace,确认慢 span 和失败 span。
  4. 日志层:从 trace 中的 trace_id 跳到 Loki,查同一次请求的错误栈和业务上下文。
  5. 变更层:叠加 deploy version、feature flag、配置变更和扩缩容事件。

告警也要按这条路径设计。不要给每个指标都配告警,而是围绕用户影响做 SLO/SLI:错误率、延迟、可用性、队列积压、成本异常。告警内容里必须带 Grafana dashboard 链接、Prometheus 查询、Loki 查询模板、Tempo trace 入口和 runbook 链接,否则值班人员还要重新组装上下文。

#Kubernetes 部署建议

小规模集群可以这样起步:

  1. kube-prometheus-stack 部署 Prometheus、Alertmanager、Grafana 和基础 Kubernetes dashboard。
  2. Loki 采用 single binary 或 simple scalable mode,日志先保留 7 到 14 天。
  3. Tempo 采用 single binary,后端接 S3 兼容对象存储。
  4. Alloy 以 DaemonSet 收集节点和容器日志,以 Deployment 接收 OTLP traces。
  5. 应用统一接入 OpenTelemetry SDK,并把 trace_id 注入日志 MDC / context。

中大型集群要把存储和查询层拆开:Prometheus remote write 到长期存储;Loki 使用对象存储和读写分离;Tempo 使用对象存储、compactor、querier 和 ingester 分层;Grafana datasources、dashboards、alert rules 用 GitOps 管理。否则一旦 dashboard、告警和 datasource 都在 UI 里手工维护,环境复制和事故复盘会变得不可控。

#最小 Helm 落地样例

下面这组命令适合做实验环境或小规模起步模板,生产环境必须锁定 chart 版本,并把 values 文件纳入 GitOps。不要继续使用已经废弃的 loki-stack 图表,也不要让 Loki、Tempo 在生产里长期依赖本地磁盘。

helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update

kubectl create namespace observability --dry-run=client -o yaml | kubectl apply -f -

helm upgrade --install kube-prometheus-stack prometheus-community/kube-prometheus-stack \
  --namespace observability \
  --values values/prometheus-stack.yaml

helm upgrade --install loki grafana/loki \
  --namespace observability \
  --values values/loki.yaml

helm upgrade --install tempo grafana/tempo \
  --namespace observability \
  --values values/tempo.yaml

helm upgrade --install alloy grafana/alloy \
  --namespace observability \
  --values values/alloy.yaml

最小 values 可以先这样分层:

# values/prometheus-stack.yaml
grafana:
  enabled: true
  adminPassword: "${GRAFANA_ADMIN_PASSWORD}"

prometheus:
  prometheusSpec:
    retention: 15d
    scrapeInterval: 30s
    evaluationInterval: 30s
    externalLabels:
      cluster: prod-a
# values/loki.yaml
deploymentMode: SingleBinary
loki:
  auth_enabled: false
  commonConfig:
    replication_factor: 1
  storage:
    type: filesystem
singleBinary:
  replicas: 1
# values/tempo.yaml
tempo:
  reportingEnabled: false
  retention: 168h
  receivers:
    otlp:
      protocols:
        grpc:
        http:
# values/alloy.yaml
alloy:
  configMap:
    create: true
    content: |
      logging {
        level = "info"
      }

      otelcol.receiver.otlp "default" {
        grpc {}
        http {}

        output {
          traces = [otelcol.exporter.otlp.tempo.input]
        }
      }

      otelcol.exporter.otlp "tempo" {
        client {
          endpoint = "tempo.observability.svc.cluster.local:4317"
          tls {
            insecure = true
          }
        }
      }

这组配置故意保持最小:Prometheus 先解决指标,Loki 和 Tempo 先能跑通本地链路,Alloy 先作为 OTLP 入口。进入生产前要把 Loki 切到对象存储和 scalable/microservices 模式,把 Tempo 切到对象存储或 distributed chart,把 Grafana 密码和 datasource 凭据改成 Secret,把 ingress、TLS、RBAC、NetworkPolicy、resource requests/limits、备份和升级策略补齐。

#Grafana Datasource 配置

Grafana datasource 建议用 provisioning 文件管理,而不是手工在 UI 里点。这样环境重建、回滚和审计都有明确版本。下面示例假设 Prometheus、Loki、Tempo 都在 observability namespace 内,并且 Grafana 能通过集群内 DNS 访问它们:

# grafana/provisioning/datasources/observability.yaml
apiVersion: 1
prune: true

datasources:
  - name: Prometheus
    type: prometheus
    uid: prometheus
    access: proxy
    url: http://kube-prometheus-stack-prometheus.observability.svc.cluster.local:9090
    isDefault: true
    jsonData:
      timeInterval: 30s
      exemplarTraceIdDestinations:
        - name: trace_id
          datasourceUid: tempo

  - name: Loki
    type: loki
    uid: loki
    access: proxy
    url: http://loki-gateway.observability.svc.cluster.local
    jsonData:
      derivedFields:
        - name: TraceID
          matcherRegex: '"trace_id":"([A-Za-z0-9]+)"'
          datasourceUid: tempo
          url: '$${__value.raw}'

  - name: Tempo
    type: tempo
    uid: tempo
    access: proxy
    url: http://tempo.observability.svc.cluster.local:3200
    jsonData:
      tracesToLogsV2:
        datasourceUid: loki
        spanStartTimeShift: -5m
        spanEndTimeShift: 5m
        filterByTraceID: true
        filterBySpanID: false
      tracesToMetrics:
        datasourceUid: prometheus
      serviceMap:
        datasourceUid: prometheus

这份配置的关键点是固定 uid。Prometheus exemplar、Loki derived fields、Tempo traces-to-logs 都依赖 datasource UID 做内部跳转。如果 UID 在不同环境里漂移,面板可以显示,但跨信号跳转会断。

日志字段也要和 datasource 配置匹配。应用输出 JSON 日志时至少要保证:

{
  "timestamp": "2026-06-12T10:30:00.000Z",
  "level": "error",
  "service": "checkout-api",
  "trace_id": "0af7651916cd43dd8448eb211c80319c",
  "span_id": "b7ad6b7169203331",
  "message": "payment provider timeout"
}

如果日志字段叫 traceIdtraceID,就要同步调整 Loki matcherRegex,不要让应用、采集器和 Grafana 各用一套命名。

#成本与容量控制

成本控制的核心是三件事:label cardinality、采样、retention。

指标层:限制高基数 label,给关键指标建 recording rules,Prometheus 本地保留短周期数据,长期数据 remote write。

日志层:日志 label 只放低基数字段,正文压缩进 chunk;高频 debug 日志默认不进生产 Loki,或者只保留短周期;按 namespace、tenant、service 设置 ingestion limit。

追踪层:默认采样,错误和慢请求优先保留;trace payload 不要塞大对象、Prompt 全文或敏感数据;span attribute 要有治理清单,避免把隐私字段写入 trace。

Grafana 层:dashboard 查询要设时间窗口和变量默认值,避免打开首页就扫全量日志或超长时间序列;告警规则要做分组、抑制和静默策略,避免告警风暴。

#风险边界

第一,Loki 不等于 Elasticsearch。它非常适合按 label 和时间窗口查服务日志,但不适合做任意字段的强全文检索和复杂审计检索。如果合规审计需要精确全文查询,应保留专门审计存储。

第二,裸 Prometheus 不等于长期指标平台。Prometheus 单节点自治和故障时可用性很强,但跨集群全局查询、多年保留、海量 cardinality 和多租户隔离需要额外架构。

第三,Tempo 不会自动让系统可追踪。没有统一 OpenTelemetry 规范、没有跨服务 context propagation、日志不带 trace_id,Tempo 只能保存碎片化 trace,排障价值会大幅下降。

第四,不要在 2026 年的新项目里继续默认 Promtail。Promtail 已 EOL,采集标准件应转向 Grafana Alloy、OpenTelemetry Collector 或团队已经标准化的日志 agent。

#验证清单

  1. 每个服务是否暴露 /metrics 或 OpenTelemetry metrics,并能被 Prometheus 或 Alloy 稳定采集。
  2. Prometheus 是否有 RED / USE dashboard、recording rules、核心 SLO alert rules。
  3. Loki label 是否只包含低基数字段,日志正文是否包含 trace_idspan_idlevelservice
  4. Tempo 是否能查到入口服务到核心依赖的完整 trace,慢请求和错误请求是否提高采样率。
  5. Grafana 是否配置了 Loki derived fields 和 Tempo datasource,能从日志跳 trace、从 trace 找日志。
  6. 告警是否包含 dashboard、PromQL、LogQL、TraceQL 或 trace 入口,以及 runbook。
  7. 是否演练过一次真实故障路径:指标触发、trace 定位、日志取证、修复后指标回落。
  8. 是否有 retention、采样、ingestion limit 和 dashboard 查询窗口,避免可观测系统本身成为成本和稳定性风险。

#AI 应用指标清单

AI 应用不要只复用传统 HTTP dashboard。模型调用、RAG、Agent 和成本都要变成一等可观测对象。OpenTelemetry 的 GenAI 语义约定仍处在发展阶段,但已经给出了值得采用的命名方向,例如 gen_ai.client.token.usagegen_ai.client.operation.duration。落地时要明确版本策略,避免不同 SDK 发出互不兼容的字段。

方向 推荐指标 关键维度 告警或排障用途
模型调用 gen_ai.client.operation.duration gen_ai.provider.namegen_ai.request.modelgen_ai.operation.name 判断模型供应商、模型版本或操作类型导致的延迟抖动
Token 成本 gen_ai.client.token.usage gen_ai.token.typegen_ai.request.modeltenant 识别输入膨胀、输出异常、缓存失效和租户成本异常
RAG 检索 rag_retrieval_duration_secondsrag_retrieval_hits_total indextop_krerankertenant 判断向量库、重排器或知识源是否拖慢回答
RAG 质量 rag_answer_citation_coverage_ratiorag_retrieval_empty_total knowledge_basequery_type 识别无引用回答、召回为空和知识库新鲜度问题
Agent 工具 agent_tool_calls_totalagent_tool_call_duration_secondsagent_tool_call_errors_total tool_nameapproval_requiredresult 定位外部工具失败、审批阻塞和超时重试
Agent 任务 agent_steps_totalagent_task_duration_secondsagent_task_aborts_total agent_nametask_typestop_reason 发现步骤爆炸、循环调用和人工接管频率
安全治理 ai_policy_blocks_totalai_sensitive_output_blocks_total policy_namerisk_typetenant 追踪提示注入、越权工具调用和敏感信息拦截
业务结果 ai_user_corrections_totalai_handoff_totalai_resolution_ratio featureuser_segment 判断 AI 功能是否真的减少人工处理,而不是只增加调用量

这些指标的 label 仍然要克制。tenantmodeltool_name 可以成为稳定维度,promptuser_iddocument_idrequest_id 不应该进入指标 label。Prompt、检索片段和模型输出如果需要审计,应进入受控日志或事件存储,并经过脱敏、采样和权限隔离。

AI dashboard 可以按三层组织:第一层看业务体验,包括成功率、人工接管率、P95 延迟和单位请求成本;第二层看模型与 RAG,包括 token、模型错误、召回为空、引用覆盖和重排耗时;第三层看 Agent 与安全,包括工具失败、审批耗时、策略阻断和异常终止。这样值班人员能先判断用户影响,再下钻到模型、数据或工具链。

#采用建议

建议先接入一条核心业务链路,而不是全站一次性铺开。第一阶段只做服务指标、基础日志和 Grafana dashboard;第二阶段接入 OpenTelemetry trace 和 trace_id 日志关联;第三阶段再做 SLO 告警、采样策略、长期存储和 GitOps 化配置。这样团队可以在一次真实故障里验证闭环,而不是先投入大量时间搭出一套没人用的监控平台。

对 AI 系统来说,还要把模型调用、RAG 检索、Agent 工具调用和成本指标纳入同一套可观测性语言。一个可用的 AI dashboard 至少应该回答:哪个模型慢、哪个检索源命中差、哪个工具调用失败、哪类用户请求成本异常、一次异常回答对应哪条 trace 和哪段日志。四件套的最终目标不是“监控很多”,而是让复杂系统在出问题时仍然能被解释、被定位、被修复。

证据来源

修订记录

最近修订:2026-06-12。CONVEE 在原始证据或架构判断变化时更新本文。

相关内容

返回评测与可观测专题