当系统从单体拆成几十个微服务后,一次用户请求会跨越多个服务。出问题时你常常不知道卡在哪个环节——这正是可观测性的价值。OpenTelemetry(简称 OTel)是一套厂商中立的可观测性标准,用统一 API 与协议采集 Trace、Metric、Log 三大信号,再导出到任意后端。它最大的好处是”一次埋点、任意后端”,避免被某家 APM 厂商锁定。
一、微服务为什么离不开 OpenTelemetry
单体应用里,一次请求的处理路径都在同一个进程内,打日志、看堆栈就能定位问题。但在微服务架构下,一个下单请求可能依次经过网关、用户服务、库存服务、支付服务、消息队列,任何一跳变慢或报错,用户体验都会受损。传统手段在跨进程场景下几乎失明。
OpenTelemetry 的出现,就是为了解决”埋点标准不统一”的痛点。它由 CNCF 毕业,已成为云原生可观测性的事实标准。你只需要用一套 SDK 和语义约定采集数据,后端可以今天用 Jaeger、明天换 Tempo,数据采集层完全不用改。
二、OTel 的三大信号
1. Trace:分布式追踪的骨架
Trace 记录一次请求在多个服务间的完整调用链路,每个节点称为一个 Span。所有 Span 共享同一个 TraceID,于是你能在追踪系统里看到”谁调用了谁、每一跳各花了多久”,快速锁定慢调用。
2. Metric:时序指标
请求量、错误率、延迟(即经典的 RED 指标)等聚合数据,OTel 原生就能产出,并天然对接 Prometheus 这类时序数据库。
3. Log:结构化日志
当日志被打上 TraceID 后,你可以从一条调用链直接跳到对应的日志行,排障时不再需要在多个系统之间手动比对时间戳。
三、三步接入:自动埋点 + OTLP
多数语言都提供了官方 SDK 或 instrumentation 库,大部分场景无需手写埋点。以 Python 为例,安装增强包后,通过设置环境变量即可自动为常见框架(Flask、Django、requests、SQLAlchemy 等)注入追踪:
pip install opentelemetry-distro opentelemetry-exporter-otlp
opentelemetry-bootstrap -a install
# 启动应用时注入环境变量即可自动埋点
OTEL_SERVICE_NAME=order-service \
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318 \
OTEL_TRACES_EXPORTER=otlp \
python app.py
如果需要在代码里手动创建 Span(例如标注一段关键业务逻辑),可以显式使用 SDK:
from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.http.trace import OTLPSpanExporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
provider = TracerProvider()
provider.add_span_processor(
BatchSpanProcessor(OTLPSpanExporter(endpoint="http://otel-collector:4318/v1/traces"))
)
trace.set_tracer_provider(provider)
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("checkout") as span:
span.set_attribute("order.total", 19900)
# 你的业务逻辑……
四、用 OpenTelemetry Collector 统一收口
Collector 是 OTel 的”数据中转站”,负责接收(Receiver)、处理(Processor)、导出(Exporter)。推荐用 OTLP 协议统一入站,再分发到不同后端,避免每个服务都直连多个存储。
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
batch: {}
memory_limiter:
check_interval: 1s
limit_mib: 512
exporters:
otlphttp/jaeger:
endpoint: http://tempo:4318
prometheus:
endpoint: 0.0.0.0:8889
loki:
endpoint: http://loki:3100/loki/api/v1/push
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [otlphttp/jaeger]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [prometheus]
其中的 memory_limiter 非常关键:当采集流量突增时,它能防止 Collector 自身 OOM,是生产环境的必选项。
五、Trace 落地:对接 Jaeger / Tempo
把 Trace 导出到 Jaeger 或 Grafana Tempo 后,就能看到火焰图和调用拓扑。Tempo 配合 Grafana 还能和 Prometheus 监控面板、Loki 日志聚合 做统一查询——在 Grafana 里从一条 Metric 告警直接下钻到对应 Trace 和日志,排障体验拉满。
六、信号与后端怎么搭配
| 信号 | 推荐后端 | 用途 | 本站相关 |
|---|---|---|---|
| Trace | Jaeger / Tempo | 调用链可视化 | — |
| Metric | Prometheus + Grafana | 指标告警面板 | p=304 |
| Log | Loki | 日志聚合检索 | p=1269 |
| 网关流量 | Envoy 接入 OTel | 入口统一埋点 | p=1338 |
七、在 Kubernetes 里落地
在 K8s 中推荐用 DaemonSet 部署 Collector 做”网关模式”,业务 Pod 通过环境变量把 OTLP 端点指向集群内的 Collector Service;也可以借助 OpenTelemetry Operator,用 CRD 管理采集配置并自动给工作负载注入 instrumentation,无需改动业务镜像。
# 业务 Deployment 注入环境变量
env:
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "http://otel-collector.observability.svc:4317"
- name: OTEL_SERVICE_NAME
value: "order-service"
---
# Collector 网关模式 DaemonSet(节选)
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: otel-collector
namespace: observability
spec:
selector:
matchLabels:
app: otel-collector
template:
metadata:
labels:
app: otel-collector
spec:
containers:
- name: collector
image: otel/opentelemetry-collector-contrib:latest
args: ["--config=/etc/otel/config.yaml"]
八、生产避坑清单
| 坑 | 现象 | 解法 |
|---|---|---|
| 采样率 100% | 流量大时存储爆仓、成本飙升 | 用 head / tail sampling,默认采样 10%~20% |
| 日志未注入 TraceID | 链路和日志对不上 | 在日志 MDC 中注入 trace_id |
| Collector 单点 | 采集中断、丢数据 | 网关模式多副本 + 内存限流 |
| 跨进程上下文丢失 | 链路断裂成多段 | 确保 HTTP / gRPC 传播器开启 W3C 标准 |
九、小结
OpenTelemetry 用一套开放标准把 Trace、Metric、Log 串起来,是微服务可观测性的事实标准。落地路径很清晰:先用 SDK 自动埋点,再用 Collector 统一收口,最后接入 Prometheus、Grafana、Loki 形成闭环。结合 GitHub Actions 的 CI/CD 与 Docker Compose 编排、Nginx 反向代理,你就能在容器化环境里端到端掌握系统健康;进一步还能把 Envoy 网关流量 与 k3s 集群指标 统一进同一套面板,真正打通可观测性。




