全链路可观测性落地:OpenTelemetry + Prometheus + Grafana + Loki/Tempo(从 0 到可上线)
面向对象:后端/架构/运维/平台工程团队,希望把“出了问题才看日志”升级为“分钟级定位与可量化治理”
交付目标:一套可复制的可观测性平台(Metrics/Logs/Traces),配套埋点规范、仪表盘、告警与故障定位手册
目录
- 总览与交付清单
- 可观测性三件套与选型说明
- 最小可用架构与端口规划
- Docker Compose 一键部署(可直接跑)
- Spring Boot 接入(Metrics/Logs/Traces)
- Node.js 接入(可选)
- Nginx/网关:请求链路贯通(TraceID/RequestID)
- 仪表盘模板与关键指标
- 告警策略:从“报警噪音”到“可行动”
- 故障定位 SOP:30 分钟定位到 1 分钟
- 生产化要点:容量、保留、采样、安全
- 验收清单与交付打包
- FAQ
1. 总览与交付清单
你将得到什么
- 一个能跑起来的可观测性平台(Grafana + Prometheus + Loki + Tempo + OTel Collector)
- 一套“埋点与字段规范”(让跨服务可搜索、可串联)
- 关键仪表盘与告警思路(延迟/错误/饱和度/容量)
- 一份故障定位 SOP(按图索骥)
交付物(建议随文提供)
- docker-compose.yml(平台一键启动)
- Grafana 仪表盘 JSON(建议 2~4 个:服务总览、JVM、慢请求、依赖拓扑)
- 告警规则示例(Prometheus rules)
- 日志字段规范(JSON 模板)
- 故障定位 SOP(值班可用)
2. 可观测性三件套与选型说明
2.1 Metrics(指标)
适合回答:
- “服务慢不慢?慢在哪个分位?”
- “错误率是否升高?哪个接口最异常?”
- “CPU/内存/线程池/GC 是否成为瓶颈?”
2.2 Logs(日志)
适合回答:
- “具体错误栈是什么?发生在什么参数/什么用户/什么版本?”
- “同一次请求在多个服务里发生了什么?”
2.3 Traces(链路追踪)
适合回答:
- “一次请求跨了哪些服务?每段耗时多少?哪里慢?”
- “外部依赖(DB/Redis/HTTP)哪个在拖后腿?”
2.4 为什么推荐 OpenTelemetry
OpenTelemetry(OTel)解决的是“统一标准与采集协议”的问题:
- 统一埋点/采集/导出标准,避免被单一厂商锁死
- Collector 能在边界做数据清洗、采样、脱敏、路由
3. 最小可用架构与端口规划
推荐最小架构(本地/测试/小团队可用):
- Grafana:可视化与告警聚合
- Prometheus:抓取指标
- Loki:日志存储与查询
- Tempo:Trace 存储
- OTel Collector:统一接入与转发
端口规划(示例)
- 3000:Grafana
- 9090:Prometheus
- 3100:Loki
- 3200:Tempo
- 4317:OTLP gRPC(应用上报 traces/metrics/logs)
- 4318:OTLP HTTP(可选)
4. Docker Compose 一键部署(可直接跑)
把下面保存为 docker-compose.yml,直接启动:
services:
grafana:
image: grafana/grafana:latest
container_name: obs-grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_USER=admin
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- ./data/grafana:/var/lib/grafana
depends_on:
- prometheus
- loki
- tempo
restart: unless-stopped
prometheus:
image: prom/prometheus:latest
container_name: obs-prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- ./data/prometheus:/prometheus
restart: unless-stopped
loki:
image: grafana/loki:2.9.6
container_name: obs-loki
ports:
- "3100:3100"
command: -config.file=/etc/loki/local-config.yaml
restart: unless-stopped
tempo:
image: grafana/tempo:latest
container_name: obs-tempo
ports:
- "3200:3200"
- "4317:4317"
command: [ "-config.file=/etc/tempo.yaml" ]
volumes:
- ./tempo.yaml:/etc/tempo.yaml:ro
- ./data/tempo:/var/tempo
restart: unless-stopped
otel-collector:
image: otel/opentelemetry-collector-contrib:latest
container_name: obs-otel-collector
ports:
- "4318:4318"
- "4317:4317"
volumes:
- ./otel-collector.yaml:/etc/otelcol-contrib/config.yaml:ro
restart: unless-stopped
配套配置文件(最小可用)
prometheus.yml(示例:抓取你应用的 /actuator/prometheus)
global:
scrape_interval: 15s
scrape_configs:
- job_name: app
metrics_path: /actuator/prometheus
static_configs:
- targets: ["host.docker.internal:8080"]
tempo.yaml(示例:接收 OTLP 并本地存储)
server:
http_listen_port: 3200
distributor:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
storage:
trace:
backend: local
local:
path: /var/tempo/traces
otel-collector.yaml(示例:接收 OTLP,转发到 Tempo)
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
batch:
exporters:
otlp:
endpoint: tempo:4317
tls:
insecure: true
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlp]
启动:
docker compose up -d
访问:
- Grafana:
http://localhost:3000(admin/admin)
5. Spring Boot 接入(Metrics/Logs/Traces)
5.1 指标:Micrometer + Prometheus
依赖(Maven 示例):
spring-boot-starter-actuatormicrometer-registry-prometheus
配置要点:
- 打开
/actuator/prometheus - 采集 JVM、HTTP Server、数据库连接池等指标
最小配置示例(application.yml):
management:
endpoints:
web:
exposure:
include: health,info,prometheus
endpoint:
health:
show-details: when_authorized
5.2 Trace:OTel Java Agent(最快落地)
如果你追求“最快见效”,推荐先用 Java Agent:
- 不改业务代码
- 先把 Trace 跑通,再逐步补自定义 span 与属性
启动参数示例(仅示例,按你的环境放到启动脚本/容器环境变量):
java \
-javaagent:opentelemetry-javaagent.jar \
-Dotel.service.name=demo-spring \
-Dotel.exporter.otlp.endpoint=http://localhost:4317 \
-Dotel.traces.exporter=otlp \
-jar app.jar
5.3 日志:统一 JSON 字段 + TraceID 贯通
目标:用 Loki 查询时能按 trace_id、service、env、version 快速过滤。
建议字段规范(示例):
timestamplevelserviceenvversiontrace_idspan_idrequest_iduser_id(如有,注意脱敏/权限)pathlatency_mserror(布尔)
6. Node.js 接入(可选)
Node 端建议也用 OTel SDK,上报到 Collector(统一入口):
- 统一服务名、环境、版本
- 统一采样策略
7. Nginx/网关:请求链路贯通(TraceID/RequestID)
原则:入口层必须做到“每个请求都有一个可追踪的 ID”,并透传到后端与日志。
建议做法:
- 若已在应用侧生成 TraceID:入口层透传即可
- 若入口层先生成 RequestID:写入 header,并在后端日志中输出
8. 仪表盘模板与关键指标
建议你至少提供以下 4 个仪表盘(读者最有感):
- 服务总览:QPS、P95、错误率、CPU/内存、实例数
- JVM 运行态:堆/非堆、GC 次数与耗时、线程、类加载
- 接口 TopN:最慢/最热/错误最多
- 依赖总览:DB/Redis/外部 HTTP 的耗时与错误率
黄金指标(建议按服务维度固定输出):
- 延迟(Latency):P50/P90/P95/P99
- 流量(Traffic):QPS
- 错误(Errors):5xx、业务错误码分布
- 饱和度(Saturation):CPU、线程池、连接池、队列长度
9. 告警策略:从“报警噪音”到“可行动”
告警不是越多越好,而是要“可行动”。
建议分级:
- P0:核心链路不可用(错误率暴涨、全站 5xx、关键依赖崩)
- P1:核心链路退化(P95 明显升高、队列堆积、连接池耗尽)
- P2:风险提示(磁盘水位、证书到期、慢查询增长)
告警必须包含:
- 触发条件(阈值与时间窗口)
- 影响范围(服务/接口/地域)
- 处理建议(SOP 入口、回滚/降级开关)
10. 故障定位 SOP:30 分钟定位到 1 分钟
给你一条可复制的定位链路:
- 先看仪表盘:是否是全局问题还是单服务问题
- 看 TopN:最慢/错误最多的接口是哪几个
- 查 Trace:定位慢在 DB 还是外部 HTTP
- 查 Logs:按
trace_id把同一次请求的日志串起来 - 定位后做动作:限流/降级/回滚/扩容/修复
11. 生产化要点:容量、保留、采样、安全
容量与保留
- 日志:明确保留天数与存储成本,避免 Loki 磁盘爆
- Trace:默认全量会很快爆炸,务必做采样与保留策略
采样建议(按环境)
- dev:100%
- test:20%~50%
- prod:1%~10%(关键链路可提高)
安全建议
- 日志脱敏(手机号、身份证、token)
- 访问控制(Grafana 账号、只读角色、最小权限)
- 网络隔离(仅内网访问,必要时加 VPN/堡垒机)
12. 验收清单与交付打包
验收清单
- Grafana 能打开,数据源可用
- Prometheus 能抓到应用指标
- 生成 Trace 后能在 Tempo 中检索并在 Grafana 中跳转查看
- 日志能按
service/env/trace_id查询 - 告警规则能触发一次演练(模拟错误率/延迟升高)
交付打包(建议)
/deploy:compose 与配置/dashboards:Grafana JSON/alerts:规则模板/runbook:故障定位 SOP
13. FAQ
Q:为什么 Grafana 有数据但 Trace 看不到?
A:先检查应用是否把 OTLP 发到了 Collector/Tempo,确认 4317 端口连通,再确认 service.name 是否一致。
Q:日志怎么和 Trace 串起来?
A:关键是日志字段里要有 trace_id,并确保请求入口到下游都透传上下文。
Q:一上生产数据量就爆炸怎么办?
A:第一优先级做采样;第二做保留与降采样;第三按业务价值分层存储。
更多推荐




所有评论(0)