「监控是别人告诉你哪里坏了,可观测性是你自己发现为什么坏了。」 — Charity Majors(Honeycomb CEO)
传统监控(Monitoring)问的是:“系统是不是正常工作?“可观测性(Observability)问的是:“系统为什么是现在这样?“这两个层次的区别,决定了从被动告警到主动探索的根本转变。
一、可观测性的定义
1.1 核心定义
可观测性是系统的一种性质:通过其外部输出(指标、日志、追踪)就能推断其内部状态,无需额外部署代码或注入探针。
可观测性的本质:
系统内部状态 ──可观测性──→ 外部输出
├── Metrics(聚合数值)
├── Logs(离散事件文本)
└── Traces(请求链路图谱)
开发者通过这些输出回答:
- 哪里慢?(Latency/延迟)
- 哪里坏了?(Error/错误)
- 有多少流量?(Traffic/流量)
- 系统饱和了吗?(Saturation/饱和度)
→ Google SRE 的 "Four Golden Signals"
1.2 监控 vs 可观测性
| 维度 | 监控(Monitoring) | 可观测性(Observability) |
|---|---|---|
| 目标 | 检测已知问题 | 探索未知问题 |
| 问题类型 | 「如果 X 发生则报警」 | 「系统为什么是现在这样?」 |
| 数据使用 | 预定义仪表板和告警 | 临时查询、钻取、关联 |
| 工具 | Zabbix/Nagios | Prometheus + Grafana + Jaeger + Loki |
| 思维模式 | 被动告警 | 主动探索 |
| 前置条件 | 预设故障模式 | 高基数、高维度数据 |
二、第一支柱:Metrics(指标)
2.1 什么是指标
指标是随时间聚合的数值测量,回答"有多少/多长时间/多频繁"类问题。
指标的本质:时间序列数据
(timestamp, value, {label1=v1, label2=v2})
示例:
http_requests_total{method="GET", status="200", route="/api/users"} = 15234
cpu_usage_percent{instance="web-01", core="0"} = 45.2
disk_io_bytes{direction="read", device="sda"} = 1024000
2.2 指标类型
| 类型 | 说明 | 示例 | 适用场景 |
|---|---|---|---|
| Counter | 单调递增(可重置) | 请求总数、错误总数、发送字节数 | 累计量 |
| Gauge | 可增可减 | 当前温度、内存使用量、队列长度 | 瞬时值 |
| Histogram | 采样分布,自动分桶 | 请求延迟分布、请求体大小分布 | SLA/SLO 分析 |
| Summary | 分位数计算(客户端计算) | p50/p99 延迟 | 精确分位数(客户端成本高) |
2.3 指标的数据模型
Prometheus 数据模型:
metric_name{label1="value1", label2="value2"} value timestamp
http_requests_total{method="POST", status="500", handler="/checkout"} 17 1690000000
↑ metric name ↑ labels (key-value pairs) ↑ value ↑ ts
高基数问题:
❌ user_requests_total{user_id="12345"}
→ user_id 有几万个值,cardinality 爆炸,存储和查询变慢
✅ user_requests_total 只按 method、status、route 分维度
→ user_id 放入 Logs/Traces
2.4 指标适合的问题
✅ 适合:
- "过去 5 分钟的平均请求延迟是多少?"
- "哪个服务的错误率最高?"
- "CPU 使用率的趋势是什么?"
- "按地区划分的 QPS 分布?"
❌ 不适合:
- "这个用户的某个请求为什么失败了?" → 需要 Logs/Traces
- "具体的错误堆栈是什么?" → 需要 Logs
三、第二支柱:Logs(日志)
3.1 什么是日志
日志是带有时间戳的离散事件记录,回答"发生了什么/在什么上下文/什么顺序"类问题。
{
"timestamp": "2026-08-13T14:32:01.234Z",
"level": "ERROR",
"service": "payment-svc",
"trace_id": "abc123",
"span_id": "def456",
"message": "Payment processing failed",
"error": "timeout connecting to bank API",
"user_id": "user_789",
"order_id": "order_456",
"duration_ms": 30000,
"retry_count": 3,
"context": {
"amount": 199.99,
"currency": "CNY",
"payment_method": "alipay"
}
}
3.2 日志级别
| 级别 | 使用场景 | 生产环境比例 |
|---|---|---|
| DEBUG | 开发调试,详细流程 | 关闭 |
| INFO | 关键流程节点 | 70% |
| WARN | 异常但能恢复 | 20% |
| ERROR | 功能失败需干预 | 9% |
| FATAL | 系统崩溃 | <1% |
3.3 结构化日志 vs 非结构化日志
非结构化(❌ 难解析):
2024-08-13 14:32:01 [ERROR] Payment failed for user=user_789, order=order_456,
amount=199.99, reason=timeout
结构化(✅ 可索引、可查询):
{"timestamp":"2024-08-13T14:32:01Z","level":"ERROR","event":"payment_failed",
"user_id":"user_789","order_id":"order_456","amount":199.99,"reason":"timeout"}
3.4 日志适合的问题
✅ 适合:
- "这个订单在支付环节出了什么错误?"
- "系统在这个时间点有什么异常?"
- "完整的请求处理流程是什么样的?"
- "找出所有涉及这个用户的操作记录"
❌ 不适合:
- "过去一小时的平均响应时间?" → Metrics 更高效
- "这个请求经过了哪些服务?" → Traces 更直观
四、第三支柱:Traces(追踪)
4.1 什么是追踪
追踪是记录请求在分布式系统中完整路径的因果链,回答"请求去了哪里/每个环节花了多久/哪里是瓶颈”。
Trace(追踪)= 一次端到端请求
├── Trace ID(全局唯一)
└── Spans(片段,描述每个操作)
├── Span ID
├── Parent Span ID(形成树形结构)
├── Operation Name
├── Start/End Time → Duration
├── Tags(元数据:service、method、status)
├── Logs(事件:如 "cache miss")
└── SpanContext(传播到下游)
示例 Trace:
[ Trace: trace_abc ]
├── [Span: GET /api/checkout] 0ms-200ms service=ui
│ ├── [Span: validate-cart] 5ms-25ms service=cart-svc
│ ├── [Span: process-payment] 30ms-180ms service=payment-svc
│ │ ├── [Span: check-inventory] 35ms-60ms service=inventory-svc
│ │ ├── [Span: auth-user] 65ms-95ms service=auth-svc
│ │ └── [Span: call-bank] 100ms-170ms service=payment-svc
│ └── [Span: send-email] 185ms-195ms service=notification-svc
4.2 头传播与上下文传递
请求头中的追踪上下文:
traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01
tracestate: rojo=00f067aa0ba902b7,congo=t61rcWkgMzE
traceparent 格式:
{version}-{trace_id}-{parent_id}-{trace_flags}
version = 00
trace_id = 16 bytes hex(全局唯一)
parent_id = 8 bytes hex(当前 span id)
trace_flags = 01(sampled)/ 00(未采样)
4.3 采样策略
| 策略 | 说明 | 适用 |
|---|---|---|
| 头部采样 | 决定整棵树是否采集 | 简单、低开销 |
| 概率采样 | 随机采集 1% / 0.1% | 高吞吐量系统 |
| 尾部采样 | 采集全部,保留异常的 Span | 存储成本高但精准 |
| 自适应采样 | 根据流量动态调整 | 智能但复杂 |
4.4 追踪适合的问题
✅ 适合:
- "这个慢请求在哪个服务花了最多时间?"
- "服务 A 调用服务 B 的延迟分布?"
- "两个服务之间的调用关系是什么样的?"
- "找到所有经过支付服务且响应时间 > 2s 的请求"
❌ 不适合:
- "系统的总请求量是多少?" → Metrics
- "查看请求的原始响应体?" → Logs
五、三大支柱对比
| 维度 | Metrics | Logs | Traces |
|---|---|---|---|
| 数据形态 | 时间序列数值 | 离散结构化文本 | 因果树状结构 |
| 存储成本 | 低(聚合度高) | 高(原始数据量大) | 中(取决于采样率) |
| 查询速度 | 毫秒级 | 秒级(需索引) | 毫秒-秒级 |
| 基数(Cardinality) | 低(可控标签) | 高(每条记录独特) | 中(Trace ID + Spans) |
| 最佳问题 | “有多少/频率/趋势” | “发生了什么/上下文” | “请求去了哪里/瓶颈” |
| 告警能力 | 最强 | 弱 | 中 |
| 根因定位 | 指出方向 | 提供细节 | 定位位置 |
| 代表工具 | Prometheus/VictoriaMetrics | Loki/ELK/Splunk | Jaeger/Tempo/Zipkin |
六、第四/第五支柱
6.1 Events(事件)
事件是对系统行为更有意义的抽象,介于日志和追踪之间。“用户购买完成"是一个事件,由多个日志和 Spans 组成。
{
"event_type": "user_purchase_completed",
"timestamp": "2026-08-13T10:00:00Z",
"user_id": "u123",
"order_id": "o456",
"total_amount": 299.99,
"payment_method": "wechat_pay",
"items_count": 3,
"duration_ms": 2500,
"trace_id": "trace_abc"
}
6.2 Profiling(剖析/性能分析)
Continuous Profiling(持续性能分析):
├── CPU Profiling — 找出热点函数
├── Memory Profiling — 内存分配分析
├── Goroutine/Thread Profiling — 并发分析
├── Block/Mutex Profiling — 锁竞争分析
└── IO Profiling — 磁盘/网络 IO 分析
工具:
- Go: pprof(内置)
- Java: async-profiler
- Python: py-spy
- 通用: Parca, Pyroscope, Grafana Profiles
6.3 RUM(Real User Monitoring)
RUM = 从真实用户浏览器采集性能数据
├── 页面加载时间(Web Vitals: LCP, INP, CLS)
├── 请求延迟(API Response Time)
├── JS 错误(Error Rate)
├── 会话回放(Session Replay)
└── 用户路径分析
工具:Datadog RUM, New Relic Browser, Sentry Performance
七、实际场景:如何选择工具
场景:收到告警「支付服务 P99 延迟 > 2s」
排查流程:
1. Metrics → 确认问题范围和影响
- "P99 延迟确实从 500ms 飙升到 3s"
- "只影响 /v2/payments 接口,其他接口正常"
- "问题从 14:32 开始,持续 15 分钟"
2. Traces → 定位延迟发生在哪个环节
- "trace_id: abc123 显示总延迟 3.2s"
- "调用银行接口占 2.8s(正常 200ms)"
- "银行服务是瓶颈"
3. Logs → 获取错误细节和上下文
- "call-bank 日志显示连接超时"
- "银行服务商 14:30-14:50 维护公告"
4. Metrics → 验证恢复情况
- "14:50 后延迟恢复正常"
---
结论:Metrics 发现问题,Traces 定位位置,Logs 解释原因
八、可观测性成熟度模型
Level 1: 基础监控
├── 使用传统监控工具(Nagios/Zabbix)
├── 基于阈值的简单告警
└── 事后排查靠 SSH 登机器查日志
Level 2: 指标驱动
├── Prometheus + Grafana
├── Dashboard 覆盖核心指标
├── 告警基于 Four Golden Signals
└── 有基本的指标查询能力
Level 3: 全链路可观测
├── Metrics + Logs + Traces 三支柱齐全
├── OpenTelemetry 标准化
├── 日志结构化
├── 分布式追踪覆盖核心链路
└── 告警降噪 + 分优先级
Level 4: 数据驱动 SRE
├── SLO/SLI 定义清晰
├── 错误预算管理
├── Burn Rate 告警
├── 自动化运维
└── 事后复盘变成常态
Level 5: 智能可观测
├── 异常检测(非阈值)
├── 根因自动关联
├── 容量预测
├── 自动修复(Self-healing)
└── AI 辅助决策
参考与延伸阅读
- Google SRE Book — Monitoring
- The Three Pillars of Observability(Honeycomb)
- OpenTelemetry Concepts
- Prometheus Best Practices
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。