Metrics / Logs / Traces 三支柱与 OpenTelemetry 采集
0. 元信息
- 主题路径:
docs/topics/observability-and-sre/subtopics/metrics-logs-traces/README.md - 父主题:
observability-and-sre - 主分类:工程技术
- 辅助分类:计算机基础
- 适合对象:会用 Docker / Linux、能写 Python 或 Go 后端服务的开发者
- 建议周期:1~2 周(每周 8~10 小时,重点是 Collector 配置与多语言串联)
- 前置知识:
observability-and-sre父主题 §0;linux-dev-env、docker-basics、network;至少一门后端语言 - 最终目标:能讲清 Metrics / Logs / Traces 三者各自回答什么问题,用 OpenTelemetry SDK + Collector 串联多语言服务,并在 Grafana 中三向跳转
1. 学习路线
三支柱定义(Metrics / Logs / Traces)
→ 高基数 / 低基数 / wide events
→ OpenTelemetry 数据模型(Resource / Instrumentation / Span / Metric / Log)
→ OTel SDK 自动注入与手动埋点(Python / Go / Node 任选两门)
→ OTel Collector 架构(Receiver / Processor / Exporter)
→ W3C Trace Context 上下文传播
→ 采样策略(head / tail / ratio)
→ 与 Prometheus / Loki / Tempo / Grafana 联动
2. 阶段周数分配(34 周,每天 1.52 小时)
精简子主题按”概念 → 采集 → 上下文 → 后端”四段推进。
| 阶段 | 主题 | 周数 | 备注 |
|---|---|---|---|
| 1 | 三支柱定义与数据模型 | 0.5 周 | Metrics / Logs / Traces + 高/低基数 |
| 2 | OpenTelemetry SDK | 1 周 | Resource / Instrumentation / Span |
| 3 | OTel Collector 架构 | 0.5 周 | Receiver / Processor / Exporter |
| 4 | 上下文与采样 | 0.5 周 | W3C Trace Context + 采样策略 |
| 5 | 后端对接 | 1 周 | Prometheus / Loki / Tempo / Grafana |
| 6 | 综合项目(全链路追踪 demo) | 1 周 | 含 README + 复盘 |
选 3 周方案时把第 4/5 阶段压成 0.5 周。每周留 0.5 天复盘。
3. 九阶段表
| 阶段 | 核心知识 | 实践产出 | 可观察学会标准 |
|---|---|---|---|
| 1 | 三支柱定义 | 一份对比表 | 能解释「多少 / 为什么 / 哪里」 |
| 2 | 高基数 vs 低基数 | 一个 Prometheus 指标反例 | 能说清 user_id 作 label 的代价 |
| 3 | OTel 数据模型 | Resource / Span / Metric / Log 四件套示例 | 能解释 Context Propagation |
| 4 | OTel SDK 自动注入 | Python opentelemetry-instrument Flask Demo | 一键埋点 |
| 5 | OTel SDK 手动埋点 | 写一个 @trace 装饰器 / tracer.start_as_current_span | 自定义 Span |
| 6 | OTel Collector | receivers / processors / exporters 配置 | 串联两语言 |
| 7 | Trace Context | traceparent 头 | 跨服务 traceid 串联 |
| 8 | 采样策略 | head + tail sampling | 控制成本 |
| 9 | 三向跳转 | Grafana 联动 Prometheus / Loki / Tempo | 用 traceid 反查日志与指标 |
关键陷阱:把 Metrics 当 Logs;Trace 全采样;不调 Collector batch 撑爆内存;忽略 Context Propagation;高基数 label 撑爆 TSDB。
4. 第一周任务
| 日 | 任务 | 当天交付 |
|---|---|---|
| Day 1 | 装 Docker / Compose / Python / Go;自检 | 环境清单 |
| Day 2 | 起一个 Prometheus + Grafana + Alertmanager Compose 栈 | Compose YAML + 看板 |
| Day 3 | 写最小 Flask / FastAPI 服务,暴露 /metrics(prometheus_client) | Python 服务 + RED 指标 |
| Day 4 | 用 client_golang 写 Go 服务指标 | Go 服务指标 |
| Day 5 | 装 OTel Collector,配置 OTLP receiver;接入 Python / Go SDK | Collector 配置 + 双语言 SDK |
| Day 6 | 接入 Loki;写结构化日志;用 Grafana 查日志 | Loki 数据源 + 日志查询 |
| Day 7 | 步骤 A:跑通「最小可观测闭环」(指标 + 日志 + Trace + Grafana + Alertmanager);步骤 B:补齐 4 类边界(抓取失败 / Collector 重启 / 日志丢 / traceid 断链) | 闭环 Compose + 故障记录 |
5. 阶段通用验收
- 不看答案独立重写 OTel Collector 配置;
- 用自己的话解释 Metrics / Logs / Traces 各自回答什么问题;
- 画一张图:服务 → SDK → Collector → 后端 → Grafana;
- 测试正常路径、Collector 重启、抓取失败、日志丢、traceid 断链;
- 至少准备 3 组自定义数据;
- 记录 P50/P95/P99、错误率、饱和度、SLI 命中率;
- 能修改既有服务加 OTel、加告警。
6. 最终验收
- 独立画出三支柱与 OTel 采集架构图;
- 完成至少 8 个实验;
- 串联 Python / Go / Node 中至少两语言;
- 用 traceid 在 Grafana 反查日志与指标。
7. 综合项目
实现「多语言三支柱 Demo」:Python API + Go Worker + Node 前端,OTel SDK 接入,OTel Collector 串联,输出到 Prometheus / Loki / Tempo,Grafana 看板三向跳转。成果合入父主题首选综合项目。
本主题贡献
三支柱只有通过 OTel SDK + Collector 用同一个 traceid 串起来,才能在 Grafana 中做三向跳转。本子主题负责讲清”Metrics 多少 / Logs 为什么 / Traces 哪里”在 OTel 数据模型(Resource / Span / Metric / Log)下的对应实体,避免把 metrics 当 logs、把 trace 全采样撑爆后端,并把 W3C Trace Context 跨服务传播当成 Span 拼接的物理基础。
3 职责
- 用 OTel SDK(Python / Go / Node 任两门)做自动注入 + 手动埋点,把业务 span + attribute 写进自定义代码。
- 用 OTel Collector 的 receivers / processors / exporters,把 OTLP 数据分流到 Prometheus / Loki / Tempo。
- 用 W3C Trace Context(
traceparent/tracestate)做跨服务 traceid 串联,并用 tail sampling 控制成本。
4 交付物
- 一份 OTel Collector 配置(otlp receiver + batch / tail_sampling processor + prometheusremotewrite / loki / otlphttp exporters),含 memory_limiter 防 OOM。
- 一份 Python + Go 双语言服务(OTel SDK 自动注入 + 手动 span),traceid 在 Grafana 中贯通,附
FlaskInstrumentor/client_golang接入示例。 - 一份 tail sampling 策略(head 1% + tail 100% 错误/慢),含 batch / memory 调优前后对比与 sampler 决策日志。
- 一份 Grafana 三向跳转看板(metric → trace via traceID → log via Loki label),含 tracesToLogsV2 + tracesToMetrics 配置。
3 指标
- traceid 跨服务贯通率 100%(任意业务请求 traceid 在 metrics / logs / traces 三处命中)。
- 采样后存储 Span 数 ≤ 全采样 5%(tail sampling 后样本数 / 全采样样本数)。
- Collector batch / memory 调优后 OOM 0 次(重启日志 + memory limiter 指标)。
OpenTelemetry Documentation、Prometheus Documentation、Grafana Documentation、Charity Majors: Observability Engineering。复制前核对 LICENSE。
8. 推荐资料
OpenTelemetry Documentation、Prometheus Documentation、Grafana Documentation、Charity Majors: Observability Engineering。复制前核对 LICENSE。
9. 学习资料汇聚(v0.3 自包含)
9.1 背景与动机
可观测性最早是控制论术语。2010 年代初分布式系统复杂度上升,Twitter、Uber、LinkedIn 把内部监控平台逐步开源。2014 年 Prometheus 借鉴 Borgmon 思路发布。2017 年 OpenTelemetry 把 Metrics / Logs / Traces 三件套合并到同一 SDK 与协议。今天 OTel 已是 CNCF GA 项目,被绝大多数后端框架默认集成。
9.2 概念地图
flowchart LR
Service[微服务] --> SDK[OTel SDK]
SDK --> Auto[自动埋点]
SDK --> Manual[手动埋点]
SDK --> Exporter[OTLP Exporter]
Exporter --> Collector[OTel Collector]
Collector --> Prom[Prometheus]
Collector --> Loki[(Loki)]
Collector --> Tempo[(Tempo)]
Prom --> Grafana
Loki --> Grafana
Tempo --> Grafana
Context[W3C Trace Context] -.traceparent.-> Service
9.3 基础知识讲解
9.3.1 论文 / 规范
| 资料 | 用法 |
|---|---|
| OpenTelemetry Specification | 数据模型与协议 |
| W3C Trace Context Level 1 | traceparent / tracestate 头 |
| OpenMetrics | Prometheus 暴露格式 |
| Prometheus 查询规范 | PromQL |
9.3.2 书
| 书 | 用法 |
|---|---|
| Charity Majors et al., Observability Engineering(O’Reilly, 2022) | 三支柱与 wide events |
| Brendan Gregg, Systems Performance(2nd ed., 2020) | 性能方法 |
9.3.3 博客 / 文档
| 资料 | 用法 |
|---|---|
| OpenTelemetry Blog | 实战 |
| Grafana Blog | Loki / Tempo |
| Charity Majors | 可观测工程 |
| Honeycomb Blog | wide events |
9.3.4 人物
| 人物 | 关注点 |
|---|---|
| Charity Majors | Honeycomb / 可观测 |
| Björn Rabenstein | Prometheus |
| Frederic Branczyk | Prometheus / OpenMetrics |
| Bryan Boreham | Grafana Pyroscope / Faro |
9.3.5 方法
- SLI-first:先选 SLI 再决定采集什么;
- Tail sampling for cost:成本敏感场景用 tail sampling;
- Wide events for unknown-unknowns:高基数 + 上下文;
- Context propagation everywhere:traceid 跨服务。
9.3.6 重点训练材料
- OpenTelemetry 官方文档
- Prometheus 文档与 PromQL 教程
- Grafana 文档
- Charity Majors 系列博文
9.4 经典问题与经典案例
| # | 问题 | 最简答案 |
|---|---|---|
| 1 | 三支柱谁先 | 先 Metrics,再 Logs,最后 Traces |
| 2 | 高基数怎么避免 | label 用低基数(status / method) |
| 3 | Trace 采样策略 | head 1% + tail 100% |
| 4 | traceid 怎么传播 | W3C Trace Context traceparent 头 |
| 5 | Collector batch 怎么调 | 看 memory / batch_size / timeout |
| 6 | Prometheus 高基数代价 | TSDB 索引膨胀 |
| 7 | 结构化日志怎么写 | JSON + trace_id / span_id |
| 8 | Grafana 三向跳转 | 用 traceID 变量 |
| 9 | OTel SDK 怎么选语言 | Python opentelemetry-distro |
| 10 | 业务 span 怎么写 | 用 tracer.start_as_current_span + attributes |
9.5 学习难点
| 难点 | 为什么会卡 | 突破路径 |
|---|---|---|
| 高基数 vs 低基数 | label 选错 | 看 Prometheus 文档 + 反例 |
| Context 传播 | 跨服务断链 | 用 W3C Trace Context + 自动注入 |
| Tail sampling | 资源消耗 | 用 OTel Collector tail_sampling processor |
| Collector 调优 | batch / memory / retry | 看官方 tuning 文档 |
9.6 技术标准与接口
9.6.1 Entity
| 名称 | 版本 | 组织 | 状态 |
|---|---|---|---|
| OpenTelemetry | 1.x | CNCF | GA |
| OTel Collector | contrib | CNCF | GA |
| Prometheus | 2.x | 社区 | 活跃 |
| Grafana | 10.x | Grafana Labs | 活跃 |
| Loki | 2.x | Grafana Labs | 活跃 |
| Tempo | 2.x | Grafana Labs | 活跃 |
9.6.2 Scope
三支柱覆盖可观测的不同维度;OTel 是跨语言 SDK 与协议;Prometheus / Loki / Tempo 是开源后端。
9.6.3 Structure
OTel SDK 接口:MeterProvider、TracerProvider、LoggerProvider。OTel Collector 配置:receivers / processors / exporters。Prometheus 数据模型:metric + label。
9.6.4 Ecosystem
监控:Prometheus / Datadog;日志:Loki / ELK;Trace:Tempo / Jaeger;告警:Alertmanager / PagerDuty。
9.6.5 Depth Tiers
| 层级 | 能力 |
|---|---|
| L0 | 知道三支柱 |
| L1 | 能读懂 OTel 配置 |
| L2 | 能装 Collector + SDK + 后端 |
| L3 | 能调优 + 多语言串联 |
| L4 | 能设计可观测平台 |
本子主题目标:L3。
9.6.6 Source
- OpenTelemetry Documentation
- Prometheus Documentation
- Grafana Documentation
- 引用版本快照日期:2026-07-30。
10. 常见误区
- 把 Metrics 当 Logs;
- Trace 全采样;
- 不调 Collector batch;
- 忽略 Context Propagation;
- 高基数 label 撑爆 TSDB;
- 结构化日志不带 trace_id;
- 不做采样;
- 不接 Grafana;
- 自动埋点不覆盖自定义代码;
- 不监控 Collector 自身。
11. 所有知识点分类(统一规则)
- 编程语言;2. 数据结构与算法;3. 计算机基础;4. 工程技术;5. Web 与后端;6. 前端与客户端;7. 数据与人工智能;8. 项目与职业能力;9. 安全与可靠性。
本计划归属:工程技术 主 + 安全与可靠性 辅。
代码块 1:OTel Collector 配置
# otel-collector-config.yaml
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
batch:
timeout: 5s
send_batch_size: 1024
tail_sampling:
decision_wait: 10s
policies:
- name: errors
type: status_code
status_code: { status_codes: [ERROR] }
- name: slow
type: latency
latency: { threshold_ms: 500 }
exporters:
prometheusremotewrite:
endpoint: http://prometheus:9090/api/v1/write
otlphttp/tempo:
endpoint: http://tempo:4317
tls: { insecure: true }
loki:
endpoint: http://loki:3100/loki/api/v1/push
service:
pipelines:
traces:
receivers: [otlp]
processors: [tail_sampling, batch]
exporters: [otlphttp/tempo]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [prometheusremotewrite]
logs:
receivers: [otlp]
processors: [batch]
exporters: [loki]
代码块 2:Python OTel 自动注入
# api.py
from flask import Flask
from opentelemetry.instrumentation.flask import FlaskInstrumentor
from opentelemetry.instrumentation.requests import RequestsInstrumentor
from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
app = Flask(__name__)
FlaskInstrumentor().instrument_app(app)
RequestsInstrumentor().instrument()
@app.get("/")
def hello():
return "hello"
# 启动: opentelemetry-instrument python api.py
# 或手动: tracer = trace.get_tracer(__name__)
# with tracer.start_as_current_span("manual"):
# ...
代码块 3:W3C Trace Context 头
GET /api HTTP/1.1
Host: api.example.com
traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01
tracestate: congo=t61rcWkgMzE
traceparent 格式:{version}-{trace_id}-{parent_span_id}-{flags}。flags 01 表示采样,00 表示不采样。
代码块 4:三向跳转 Grafana 看板
{
"title": "SLO Overview",
"panels": [
{
"title": "Error Budget",
"targets": [{ "expr": "sum(rate(http_requests_total{job=\"api\",status=~\"5..\"}[5m])) / sum(rate(http_requests_total{job=\"api\"}[5m]))" }]
},
{
"title": "Trace from this point",
"type": "traces",
"targets": [{ "query": "{ service.name = \"$service\" && status = error }", "queryType": "traceql" }]
},
{
"title": "Logs",
"type": "logs",
"targets": [{ "expr": "{job=\"api\"} |= \"$trace_id\"" }]
}
]
}