OpenTelemetry 开发实战

2025-11-12T14:11:02+08:00 | 2分钟阅读 | 更新于 2025-11-12T14:11:02+08:00

@

实战目标

在前一篇笔记中,我们了解了 OpenTelemetry 的架构与核心概念。本篇将完成一个完整的开发实战:从 Golang 应用埋点,到 Collector 收集转发,再到 Prometheus 和 Jaeger 后端存储,最后基于采集到的数据进行简单的 AIOps 异常检测。

环境准备

需要部署以下组件:

  • OpenTelemetry Collector:负责接收和转发数据。
  • Prometheus:存储 Metrics。
  • Jaeger:存储 Traces。
  • 示例 Golang 应用:产生 Metrics 和 Traces。

可以使用 Docker Compose 或 Helm 在本地快速搭建:

# docker-compose 简化示例
services:
  otel-collector:
    image: otel/opentelemetry-collector-contrib:latest
    volumes:
      - ./otel-collector-config.yaml:/etc/otelcol-contrib/config.yaml
    ports:
      - "4317:4317"
      - "4318:4318"
      - "8889:8889"
  prometheus:
    image: prom/prometheus:latest
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - "9090:9090"
  jaeger:
    image: jaegertracing/all-in-one:latest
    ports:
      - "16686:16686"
      - "14250:14250"

Golang 应用接入 OpenTelemetry

初始化 TracerProvider

package main

import (
    "context"
    "time"

    "go.opentelemetry.io/otel"
    "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
    "go.opentelemetry.io/otel/sdk/resource"
    sdktrace "go.opentelemetry.io/otel/sdk/trace"
    semconv "go.opentelemetry.io/otel/semconv/v1.17.0"
)

func initTracer() (*sdktrace.TracerProvider, error) {
    ctx := context.Background()
    exp, err := otlptracegrpc.New(ctx, otlptracegrpc.WithEndpoint("localhost:4317"), otlptracegrpc.WithInsecure())
    if err != nil {
        return nil, err
    }
    res, err := resource.New(ctx, resource.WithAttributes(semconv.ServiceName("aiops-demo")))
    if err != nil {
        return nil, err
    }
    tp := sdktrace.NewTracerProvider(
        sdktrace.WithBatcher(exp),
        sdktrace.WithResource(res),
    )
    otel.SetTracerProvider(tp)
    return tp, nil
}

创建 Span 并记录业务操作

func handleRequest(ctx context.Context) {
    tracer := otel.Tracer("aiops-demo")
    ctx, span := tracer.Start(ctx, "handleRequest")
    defer span.End()

    doSomething(ctx)
    span.SetAttributes(attribute.String("user.id", "12345"))
}

记录 Metrics

import (
    "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc"
    sdkmetric "go.opentelemetry.io/otel/sdk/metric"
)

func initMeter() (*sdkmetric.MeterProvider, error) {
    ctx := context.Background()
    exp, err := otlpmetricgrpc.New(ctx, otlpmetricgrpc.WithEndpoint("localhost:4317"), otlpmetricgrpc.WithInsecure())
    if err != nil {
        return nil, err
    }
    mp := sdkmetric.NewMeterProvider(sdkmetric.WithReader(sdkmetric.NewPeriodicReader(exp)))
    return mp, nil
}

// 使用
counter, _ := meter.Int64Counter("request.count")
counter.Add(ctx, 1)

Collector 完整配置

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

processors:
  batch:
    timeout: 1s
    send_batch_size: 1024
  resource:
    attributes:
      - key: environment
        value: production
        action: upsert

exporters:
  prometheusremotewrite:
    endpoint: http://prometheus:9090/api/v1/write
  otlp/jaeger:
    endpoint: jaeger:4317
    tls:
      insecure: true
  logging:
    loglevel: debug

service:
  pipelines:
    metrics:
      receivers: [otlp]
      processors: [batch, resource]
      exporters: [prometheusremotewrite]
    traces:
      receivers: [otlp]
      processors: [batch, resource]
      exporters: [otlp/jaeger]

业务全链路监控方案

实现全链路监控需要做到:

  1. 统一 TraceID 传递:在 HTTP/gRPC 请求头中传递 traceparent
  2. 自动埋点框架:使用 otelgin、otelgrpc 等官方中间件。
  3. 数据库与缓存埋点:对 MySQL、Redis、Kafka 等组件进行埋点。
  4. 上下文透传:通过 Go 的 context.Context 在不同函数间传递 Span。
// HTTP 客户端透传 Trace
import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"

client := &http.Client{Transport: otelhttp.NewTransport(http.DefaultTransport)}
req, _ := http.NewRequestWithContext(ctx, "GET", "http://service-b/api", nil)
client.Do(req)

基于可观测数据的 AIOps 异常检测

采集到 Metrics 后,可以基于时序数据进行异常检测。例如使用 Python 对 Prometheus 查询结果做简单阈值与趋势分析:

import requests
import numpy as np

query = 'rate(request_count_total[5m])'
resp = requests.get('http://localhost:9090/api/v1/query', params={'query': query})
data = resp.json()['data']['result']

for series in data:
    values = [float(v[1]) for v in series['values']]
    mean = np.mean(values)
    std = np.std(values)
    latest = values[-1]
    if latest > mean + 3 * std:
        print(f"异常检测到: {series['metric']}, 当前值 {latest}, 均值 {mean}")

更复杂的场景可以使用:

  • Prophet:检测时序中的趋势变化与异常点。
  • Isolation Forest:多维指标异常检测。
  • LSTM Autoencoder:非线性时序异常检测。

结合 Trace 数据,还可以通过分析调用链延迟分布,定位异常服务;结合日志数据,可以对异常 Span 关联的日志进行聚类,辅助根因分析。

总结

OpenTelemetry 提供了一条从应用到后端的完整可观测性链路。通过合理的埋点、Collector 配置和后端存储选择,可以构建覆盖 Metrics、Traces、Logs 的全链路监控体系。这些可观测数据是 AIOps 异常检测、根因定位和自动修复的基础。

About Me

没什么想介绍的,一个很大众的码农…

喜欢代码,车,马,真的是 🐎

讨厌别人让我给自己的代码写注释 最厌烦别人的程序没有写注释

目标

学AI,加油!加油!