核心结论

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 设计错误会导致查询慢或存储膨胀
Tempotrace 接收、存储、TraceQL 查询、span metricsOTLP、Jaeger、Zipkin、TraceQLTrace 价值依赖应用埋点、采样策略和 trace_id 贯穿
Alloy / OTel Collector采集、转换、批处理、转发 telemetryPrometheus 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.durationgen_ai.provider.namegen_ai.request.modelgen_ai.operation.name判断模型供应商、模型版本或操作类型导致的延迟抖动
Token 成本gen_ai.client.token.usagegen_ai.token.typegen_ai.request.modeltenant识别输入膨胀、输出异常、缓存失效和租户成本异常
RAG 检索rag_retrieval_duration_secondsrag_retrieval_hits_totalindextop_krerankertenant判断向量库、重排器或知识源是否拖慢回答
RAG 质量rag_answer_citation_coverage_ratiorag_retrieval_empty_totalknowledge_basequery_type识别无引用回答、召回为空和知识库新鲜度问题
Agent 工具agent_tool_calls_totalagent_tool_call_duration_secondsagent_tool_call_errors_totaltool_nameapproval_requiredresult定位外部工具失败、审批阻塞和超时重试
Agent 任务agent_steps_totalagent_task_duration_secondsagent_task_aborts_totalagent_nametask_typestop_reason发现步骤爆炸、循环调用和人工接管频率
安全治理ai_policy_blocks_totalai_sensitive_output_blocks_totalpolicy_namerisk_typetenant追踪提示注入、越权工具调用和敏感信息拦截
业务结果ai_user_corrections_totalai_handoff_totalai_resolution_ratiofeatureuser_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 和哪段日志。四件套的最终目标不是“监控很多”,而是让复杂系统在出问题时仍然能被解释、被定位、被修复。