基于OpenTelemetry 构建完整的可观测性体系的实现

377 阅读2分钟

1. 整体架构

deepseek_mermaid_20250513_8b63b0.png

  • OpenTelemetry:负责采集 Trace(追踪)、Metric(指标)。
  • Loki:收集应用日志(需注入 TraceId)。
  • Prometheus:存储指标数据。
  • Tempo/Jaeger:存储分布式追踪数据。
  • Grafana:统一展示日志、指标、追踪,并通过 TraceId 关联三者。

2. 配置 OpenTelemetry

2.1 添加 OpenTelemetry 依赖

在 pom.xml 中引入:

<dependency>
    <groupId>io.opentelemetry</groupId>
    <artifactId>opentelemetry-api</artifactId>
    <version>1.30.1</version>
</dependency>
<dependency>
    <groupId>io.opentelemetry</groupId>
    <artifactId>opentelemetry-sdk</artifactId>
    <version>1.30.1</version>
</dependency>
<dependency>
    <groupId>io.opentelemetry</groupId>
    <artifactId>opentelemetry-exporter-otlp</artifactId>
    <version>1.30.1</version>
</dependency>

2.2 初始化 OpenTelemetry

在 Spring Boot 启动类中配置:

import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;

@SpringBootApplication
public class MyApp {
    public static void main(String[] args) {
        // 配置 OpenTelemetry
        OpenTelemetry openTelemetry = OpenTelemetrySdk.builder()
            .setTracerProvider(
                SdkTracerProvider.builder()
                    .addSpanProcessor(
                        BatchSpanProcessor.builder(
                            OtlpGrpcSpanExporter.builder()
                                .setEndpoint("http://otel-collector:4317")
                                .build()
                        ).build()
                    )
                    .setResource(Resource.getDefault()
                        .merge(Resource.create(Attributes.of(
                            ResourceAttributes.SERVICE_NAME, "my-service"
                        )))
                    .build()
            )
            .buildAndRegisterGlobal();

        SpringApplication.run(MyApp.class, args);
    }
}

3. 注入 TraceId 到日志

在日志中自动添加 TraceId,便于 Loki 收集后与 Trace 关联。

3.1 配置 Logback

在 logback-spring.xml 中添加 MDC 转换:

xml

复制

下载

运行

<configuration>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - [traceId=%X{traceId}] - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- 自动注入 TraceId -->
    <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator"/>
    <contextListener class="org.springframework.boot.logging.logback.LogbackLoggingSystem"/>
</configuration>

3.2 自动捕获 TraceId

通过 OpenTelemetry 的自动注入,确保日志中的 traceId 字段与当前请求的 TraceId 一致。


4. 配置 OpenTelemetry Collector

部署 Collector 并配置数据转发(示例 otel-collector-config.yaml):

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

exporters:
  prometheus:
    endpoint: "prometheus:9090"
  loki:
    endpoint: "http://loki:3100/loki/api/v1/push"
    labels:
      job: "my-service"
  tempo:
    endpoint: "tempo:4317"
    insecure: true

service:
  pipelines:
    traces:
      receivers: [otlp]
      exporters: [tempo]
    metrics:
      receivers: [otlp]
      exporters: [prometheus]
    logs:
      receivers: [otlp]
      exporters: [loki]

5. Grafana 数据源配置

  1. Loki:用于日志查询。
  2. Prometheus:用于指标查询。
  3. Tempo:用于分布式追踪。

在 Grafana 的 Configuration > Data Sources 中添加三者,并确保地址正确。


6. 实现 Trace-日志-指标联动

6.1 查看 Trace 详情

在 Tempo 数据源中,通过 TraceId 查询完整的调用链路。

6.2 关联日志

在 Grafana Explore 中选择 Loki 数据源,输入查询:

{job="my-service"} | json | traceId="替换为TraceId"

6.3 关联指标

在 Prometheus 中查询与 Trace 相关的指标(如接口耗时):

http_server_duration_seconds_bucket{trace_id="替换为TraceId"}

7. 创建统一监控面板

在 Grafana 中创建 Dashboard,整合以下内容:

  1. 指标图表:显示接口 QPS、平均耗时、错误率。
  2. 日志面板:显示最近错误日志(带 TraceId)。
  3. Trace 列表:显示最近慢请求的 Trace 详情。

8. 验证全链路

  1. 发起一个请求,观察日志中是否包含 TraceId。
  2. 在 Tempo 中通过 TraceId 查看调用链路。
  3. 在 Loki 中通过 TraceId 过滤相关日志。
  4. 在 Prometheus 中查看该请求的指标统计。

常见问题

Q1:日志中未出现 TraceId

  • 检查 Logback 配置的 %X{traceId} 是否正确。
  • 确保 OpenTelemetry 的自动注入已启用。

Q2:Grafana 无法关联数据源

  • 确认所有数据源(Loki、Prometheus、Tempo)在 Grafana 中已正确配置并测试通过。
  • 确保 TraceId 的格式一致(如 16 进制或 Base64 编码)。

总结

通过 OpenTelemetry 统一采集 Trace 和 Metric,配合 Loki 的日志收集,最终在 Grafana 中实现三者的无缝关联。核心步骤包括:

  1. 注入 TraceId 到日志。
  2. 通过 OpenTelemetry Collector 转发数据到对应存储。
  3. 在 Grafana 中通过 TraceId 实现跨数据源查询。