前置知识: 云计算

可观测性

6 min中级

可观测性三支柱:日志、指标、分布式追踪的原理、工具与实践详解。

知识点地图

  • 知识类别:可观测性——日志/指标/追踪三支柱、Prometheus 与 OpenTelemetry 生态的配置实操、告警设计与监控体系分层。
  • 解决什么问题:系统出问题时「靠什么解释原因」:数据采集了没有、指标怎么查、告警响不响、三支柱能否用 trace_id 串起来。
  • 什么时候用到:接入 Prometheus 抓取与告警规则;设计 SLO 与错误预算;给新服务补监控面板;排障时定位「该看哪个支柱」。

前置知识

可观测性回答一个问题:当系统行为不符合预期时,你能不能仅凭系统对外 暴露的数据解释原因。三大支柱(日志/指标/追踪)分别回答「发生了什么、 现在什么状态、请求经过了哪里」,三者用 trace_id 串起来才是完整的排错 闭环。本文以 Prometheus/Loki/Tempo 与 OpenTelemetry 生态为主线。

1. 可观测性概述

1.1 三大支柱

支柱描述核心问题
日志 (Logs)离散事件记录发生了什么?
指标 (Metrics)聚合数值数据现在什么状态?
追踪 (Traces)请求链路追踪请求经过了哪里?

1.2 监控 vs 可观测性

对比项监控可观测性
方式预定义仪表盘探索式查询
问题已知问题未知问题
数据指标为主日志+指标+追踪
思维被动告警主动探索

2. 日志

2.1 日志级别

级别用途
ERROR错误,需要立即处理
WARN警告,可能的问题
INFO重要业务事件
DEBUG调试信息
TRACE详细追踪

2.2 结构化日志

json
{
  "timestamp": "2026-06-14T10:30:00Z",
  "level": "INFO",
  "service": "order-service",
  "trace_id": "abc123",
  "span_id": "def456",
  "message": "Order created",
  "user_id": "user-789",
  "order_id": "order-101",
  "duration_ms": 45
}

2.3 日志架构

plaintext
应用 → Fluentd/Filebeat → Kafka → Logstash → Elasticsearch → Kibana
                                    或
应用 → Fluent Bit → Loki → Grafana

2.4 ELK vs EFK vs PLG

栈组件特点
ELKElasticsearch + Logstash + Kibana功能全面、资源消耗大
EFKElasticsearch + Fluentd + KibanaFluentd 替代 Logstash
PLGPrometheus + Loki + Grafana轻量、与指标统一

3. 指标

3.1 指标类型

类型描述示例
Counter单调递增计数器请求总数、错误总数
Gauge可增可减的值当前连接数、内存使用
Histogram分布统计请求延迟分布
Summary分位数统计P50/P95/P99 延迟

3.2 Prometheus

数据模型:

plaintext
metric_name{label1="value1", label2="value2"} value timestamp

http_requests_total{method="GET", path="/api/users", status="200"} 1234

抓取配置(prometheus.yml)——K8s 环境用服务发现自动发现带注解的 Pod:

yaml
global:
  scrape_interval: 15s
  evaluation_interval: 15s

rule_files:
  - 'alerts/*.yml'

scrape_configs:
  - job_name: 'kubernetes-pods'
    kubernetes_sd_configs:
      - role: pod
    relabel_configs:
      - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
        action: keep          # 只抓带 prometheus.io/scrape: "true" 注解的 Pod
        regex: true

  - job_name: 'node-exporter'
    static_configs:
      - targets: ['node-exporter:9100']

relabel_configs 的 keep 动作是「注解即订阅」模式:应用 Pod 只要在部署清单里加两个注解(prometheus.io/scrape: "true" 与端口注解),Prometheus 自动开始抓取——扩缩容、发布新 Pod 都不需要改监控配置。

告警规则(alerts/app-alerts.yml)——三个最常见的生产规则模板:

yaml
groups:
  - name: app-alerts
    rules:
      - alert: HighErrorRate
        expr: rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) > 0.05
        for: 5m                # 持续 5 分钟才触发,过滤瞬时抖动
        labels:
          severity: critical
        annotations:
          summary: '高错误率: {{ $labels.instance }}'
          description: '5xx 错误率超过 5%,当前值: {{ $value | humanizePercentage }}'

      - alert: HighLatency
        expr: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) > 1
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: '高延迟: {{ $labels.instance }}'
          description: 'P95 延迟超过 1s,当前值: {{ $value }}s'

      - alert: PodCrashLooping
        expr: rate(kube_pod_container_status_restarts_total[15m]) > 0
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: 'Pod 崩溃重启: {{ $labels.namespace }}/{{ $labels.pod }}'

for: 子句与告警原则的「避免噪音」对应:没有它,单次超时就会拉响 P0。易错点:rate() 只对 Counter 用;对 Gauge 用 rate 得到的是无意义的差值序列。

Grafana 仪表盘关键面板——概览层四件套:

json5
{
  dashboard: {
    title: 'Application Overview',
    panels: [
      { title: '请求速率 (QPS)', type: 'timeseries',
        targets: [{ expr: 'sum(rate(http_requests_total[5m]))' }] },
      { title: '错误率', type: 'gauge',
        targets: [{ expr: 'sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m]))' }] },
      { title: 'P95 延迟', type: 'timeseries',
        targets: [{ expr: 'histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))' }] },
      { title: 'CPU 使用率', type: 'timeseries',
        targets: [{ expr: 'sum(rate(container_cpu_usage_seconds_total{namespace="production"}[5m])) by (pod)' }] },
    ],
  },
}

仪表盘 JSON 建议随 GitOps 仓库管理(Grafana provisioning),与告警规则同源可审计。

PromQL 查询:

plaintext
# 请求速率(每秒)
rate(http_requests_total[5m])

# P99 延迟
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))

# 错误率
rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m])

# 按 service 分组
sum(rate(http_requests_total[5m])) by (service)

3.3 四大黄金信号

信号描述指标
延迟请求处理时间P50/P95/P99
流量请求量QPS
错误失败率Error Rate
饱和度资源使用率CPU/Memory/Disk

3.4 RED 方法

指标描述
Rate请求速率
Errors错误率
Duration请求延迟

3.5 USE 方法

指标描述
Utilization使用率
Saturation饱和度
Errors错误数

4. 分布式追踪

4.1 核心概念

概念描述
Trace一次请求的完整链路
Span链路中的一个操作
SpanContext跨进程传递的上下文
Baggage跨 Span 传播的键值对

4.2 OpenTelemetry

统一可观测性标准,合并了 OpenTracing 和 OpenCensus。

架构:

plaintext
应用 → OTel SDK → OTel Collector → 后端(Jaeger/Tempo/...)

代码示例:

python
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter

# 配置
provider = TracerProvider()
processor = BatchSpanProcessor(OTLPSpanExporter(endpoint="otel-collector:4317"))
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)

# 使用
tracer = trace.get_tracer("my-service")
with tracer.start_as_current_span("process-order") as span:
    span.set_attribute("order.id", "12345")
    # 业务逻辑

4.3 追踪后端

工具特点
JaegerCNCF 项目,功能全面
Zipkin老牌追踪系统
TempoGrafana 生态,对象存储
SkyWalkingAPM+追踪

5. 告警

5.1 告警原则

原则描述
可操作性每个告警都应有明确动作
避免噪音减少无效告警
分级P0-P3 分级
升级超时自动升级

5.2 AlertManager 配置

yaml
route:
  receiver: 'slack'
  group_by: ['alertname', 'service']
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h
  routes:
    - matchers:               # 新版 Alertmanager 用 matchers(旧 match 已弃用)
        - severity="critical"
      receiver: 'pagerduty'
      repeat_interval: 1h

receivers:
  - name: 'slack'
    slack_configs:
      - channel: '#alerts'
  - name: 'pagerduty'
    pagerduty_configs:
      - routing_key: 'xxx'    # 旧字段 service_key 已废弃

6. 可观测性最佳实践

实践描述
关联三大支柱trace_id 贯穿日志、指标、追踪
语义约定使用 OpenTelemetry 语义约定
采样策略尾部采样保留异常请求
SLO/SLI定义服务等级目标和指标
仪表盘分层概览→服务→实例

6.1 监控体系分层总览

plaintext
指标采集 → 数据存储 → 可视化 → 告警 → 通知
   │          │          │        │       │
Prometheus   TSDB     Grafana  Alert   Slack/钉钉
CloudWatch   CloudWatch AWS     SNS     Email/SMS
Datadog      Datadog   Datadog  Monitor PagerDuty
层级工具关注点
基础设施CloudWatch、Node ExporterCPU/内存/磁盘/网络
应用层APM、自定义指标延迟/错误率/吞吐量
业务层自定义指标、日志分析订单量/转化率
安全层GuardDuty、WAF 日志异常访问/攻击检测

选型直觉:全套自建(Prometheus + Grafana + Alertmanager)适合有平台团队、多云或有合规自治要求的组织;托管全家桶(CloudWatch/Azure Monitor/Datadog)用付费换运维。混合很常见——业务指标进自建 Prometheus,云资源指标留在 CloudWatch,Grafana 双数据源统一出图。

小结

  • 初学者要点:三支柱各答一个问题,trace_id 是串联三者的线索;指标 选型记四类(Counter/Gauge/Histogram/Summary),延迟看分位数(P99) 不看平均值;告警必须「可操作」,不能指示动作的告警删掉比留着好。
  • 进阶注意:RED 用于服务(请求视角)、USE 用于资源(基础设施视角)、 四大黄金信号是告警 SLI 的骨架;OpenTelemetry 是事实标准——SDK 出点、 Collector 中转、协议对接任意后端,避免被单一 APM 厂商绑定;高流量 系统用尾部采样(保留慢/错请求)平衡成本与排错能力;SLO 驱动的 错误预算(Error Budget)把「告警多少」变成可计算的工程决策。