饮墨

子安饮墨馀三斗,留与卿儿作赋来

用 OpenTelemetry Collector 统一可观测性数据管道:3 步替代 Prometheus + Fluentd + Jaeger 多套架构

痛点:可观测性组件太多,运维成本比业务还高

典型的中大型 Kubernetes 集群里,可观测性栈长这样:

  • Metrics: Prometheus + Grafana
  • Logs: Fluentd/Filebeat → Elasticsearch → Kibana
  • Traces: Jaeger/Zipkin + 各语言 SDK

三套系统、三种配置语法、三条数据管道。升级、扩容、故障排查都要分别处理。新服务接入时,开发要集成三种 SDK。运维花在"监控系统本身"的时间占比越来越高。

核心矛盾:可观测性的三大支柱(Metrics、Logs、Traces)本质上是同一个数据流的不同视角,却被割裂成完全独立的基础设施。

方案:OpenTelemetry Collector 作为统一数据管道

OpenTelemetry(简称 OTel)是 CNCF 毕业项目,目标是提供厂商无关的可观测性标准。其核心组件 OTel Collector 可以同时接收、处理、导出 Metrics + Logs + Traces,一个进程替代多个 Agent。

架构对比

维度 传统方案 OTel Collector 统一方案
Agent 数量 3-4 个 DaemonSet 1 个 DaemonSet
配置语言 Prometheus YAML + Fluentd conf + Jaeger env 统一 YAML
数据格式 各自私有协议 OTLP(开放标准)
后端切换成本 重写 pipeline 改一行 exporter
资源占用(典型值) 800MB-1.2GB/节点 200-400MB/节点

实操:3 步部署 OTel Collector 统一管道

第 1 步:用 Helm 部署 OTel Collector DaemonSet

# 添加 OTel Helm repo
helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts
helm repo update

# 安装为 DaemonSet 模式(每节点一个 Collector)
helm install otel-collector open-telemetry/opentelemetry-collector \
  --namespace monitoring --create-namespace \
  --set mode=daemonset \
  --set image.tag="0.102.0" \
  -f otel-values.yaml

第 2 步:编写统一配置(Metrics + Logs + Traces 一个文件搞定)

otel-values.yaml 核心配置:

config:
  receivers:
    otlp:
      protocols:
        grpc:
          endpoint: 0.0.0.0:4317
        http:
          endpoint: 0.0.0.0:4318
    # 兼容 Prometheus 抓取
    prometheus:
      config:
        scrape_configs:
          - job_name: 'kubernetes-pods'
            kubernetes_sd_configs:
              - role: pod
            relabel_configs:
              - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
                action: keep
                regex: true
    # 采集节点日志
    filelog:
      include: [/var/log/pods/*/*/*.log]
      operators:
        - type: router
          routes:
            - output: parser-json
              expr: 'body matches "^\\{"'
        - id: parser-json
          type: json_parser
          timestamp:
            parse_from: attributes.time
            layout: '%Y-%m-%dT%H:%M:%S.%LZ'

  processors:
    batch:
      timeout: 5s
      send_batch_size: 1024
    memory_limiter:
      check_interval: 1s
      limit_mib: 512
      spike_limit_mib: 128
    k8sattributes:
      extract:
        metadata:
          - k8s.namespace.name
          - k8s.pod.name
          - k8s.deployment.name
      pod_association:
        - sources:
            - from: resource_attribute
              name: k8s.pod.ip

  exporters:
    # Metrics → Prometheus Remote Write
    prometheusremotewrite:
      endpoint: "http://prometheus:9090/api/v1/write"
      resource_to_telemetry_conversion:
        enabled: true
    # Logs → Elasticsearch
    elasticsearch:
      endpoints: ["https://elasticsearch:9200"]
      logs_index: "otel-logs"
      tls:
        insecure_skip_verify: false
        ca_file: /etc/ssl/certs/es-ca.crt
    # Traces → Jaeger (OTLP)
    otlp/jaeger:
      endpoint: "jaeger-collector:4317"
      tls:
        insecure: true

  service:
    pipelines:
      metrics:
        receivers: [otlp, prometheus]
        processors: [memory_limiter, k8sattributes, batch]
        exporters: [prometheusremotewrite]
      logs:
        receivers: [otlp, filelog]
        processors: [memory_limiter, k8sattributes, batch]
        exporters: [elasticsearch]
      traces:
        receivers: [otlp]
        processors: [memory_limiter, k8sattributes, batch]
        exporters: [otlp/jaeger]

第 3 步:应用侧接入(以 Python 服务为例)

# requirements.txt 新增:
# opentelemetry-api==1.25.0
# opentelemetry-sdk==1.25.0
# opentelemetry-exporter-otlp==1.25.0
# opentelemetry-instrumentation-fastapi==0.46b0

from opentelemetry import trace, metrics
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader

# 统一指向 OTel Collector
OTEL_ENDPOINT = "http://otel-collector:4317"

# Traces
trace_provider = TracerProvider()
trace_provider.add_span_processor(
    BatchSpanProcessor(OTLPSpanExporter(endpoint=OTEL_ENDPOINT, insecure=True))
)
trace.set_tracer_provider(trace_provider)

# Metrics
metric_reader = PeriodicExportingMetricReader(
    OTLPMetricExporter(endpoint=OTEL_ENDPOINT, insecure=True),
    export_interval_millis=10000,
)
metrics.set_meter_provider(MeterProvider(metric_readers=[metric_reader]))

# 业务代码直接用
tracer = trace.get_tracer("my-service")
meter = metrics.get_meter("my-service")
request_counter = meter.create_counter("http_requests_total")

with tracer.start_as_current_span("handle_request"):
    request_counter.add(1, {"method": "GET", "path": "/api/users"})

一套 SDK、一个 Endpoint、Metrics + Traces 同时上报。Logs 通过 Collector 的 filelog receiver 自动采集,应用零改动。

避坑:3 个常见问题

1. 内存 OOM:Collector 处理高流量时被 Kill

原因:默认无内存限制,高峰期 batch 堆积导致 OOM。

解决:必须配置 memory_limiter processor,并放在 pipeline processors 列表的第一个位置

processors:
  memory_limiter:
    check_interval: 1s
    limit_mib: 512       # 硬上限
    spike_limit_mib: 128 # 突发缓冲

同时 K8s resources.limits 要大于 limit_mib,建议设为 1.5 倍(768Mi)。

2. Prometheus 指标丢失:抓取目标找不到

原因k8sattributes processor 需要 ServiceAccount 有 Pod list 权限,否则 relabel 失败。

解决:确认 Helm Chart 的 RBAC 配置:

clusterRole:
  create: true
  rules:
    - apiGroups: [""]
      resources: ["pods", "namespaces"]
      verbs: ["get", "list", "watch"]

3. 日志重复采集:filelog receiver 重启后重读

原因:Collector 重启后 checkpoint 丢失,重新从文件头读取。

解决:启用 file_storage 扩展持久化 offset:

extensions:
  file_storage:
    directory: /var/lib/otelcol/file_storage

receivers:
  filelog:
    storage: file_storage
    include: [/var/log/pods/*/*/*.log]

并将 /var/lib/otelcol/ 挂载为 hostPath 或 PVC。

总结

迁移收益 效果
Agent 数量 3-4 → 1,DaemonSet 维护成本直降
节点内存占用 减少 40-60%(实测)
新服务接入 1 套 SDK + 1 个 Endpoint,5 分钟搞定
后端替换 改 exporter 配置即可,不动应用代码
数据关联 TraceID 贯穿 Metrics/Logs/Traces,排障效率翻倍

迁移建议:不需要一步到位。先部署 Collector 作为 Proxy 模式接收 OTLP,新服务直接对接;老服务保留现有 Agent,逐步迁移。Prometheus 可以继续用——Collector 的 prometheus receiver 完全兼容现有 scrape 配置,平滑过渡零风险。

OpenTelemetry 已经是 CNCF 活跃度第二的项目(仅次于 Kubernetes),2026 年 Logs 规范也已 GA。现在上车,正是时候。

您还没有登录,请登录后发表评论。