Spring Cloud微服务监控与链路追踪:基于Prometheus和OpenTelemetry的全链路可观测性解决方案
引言:为什么需要全链路可观测性?
在现代软件架构中,微服务已成为构建复杂分布式系统的核心范式。然而,随着服务数量的增长、调用链路的复杂化以及部署环境的多样化,传统的单体应用监控手段已无法满足对系统状态的全面掌握需求。
一个典型的微服务架构可能包含数十甚至上百个独立的服务实例,它们通过HTTP、gRPC、消息队列等方式进行通信。在这种环境下,一旦出现性能瓶颈、请求超时或错误率上升,开发团队往往难以快速定位问题根源——是某个服务本身的问题?还是下游依赖异常?或是网络延迟导致的响应缓慢?
这就是“可观测性(Observability)”的价值所在。可观测性不仅包括传统的指标(Metrics)、日志(Logs),还引入了分布式追踪(Tracing)作为第三支柱,三者协同工作,帮助我们从“被动响应”走向“主动洞察”。
本文将围绕 Spring Cloud 微服务生态,深入探讨如何通过 Prometheus + OpenTelemetry 构建一套完整的、生产级别的全链路可观测性解决方案。我们将覆盖:
- 指标采集与可视化
- 分布式链路追踪实现
- 日志与追踪数据关联
- 服务间调用链分析
- 最佳实践与性能优化建议
最终目标是打造一个可扩展、易维护、具备真实故障诊断能力的可观测体系。
一、核心组件概述:Prometheus 与 OpenTelemetry
1.1 Prometheus:强大的时间序列监控系统
Prometheus 是由 SoundCloud 开发并由 CNCF(云原生计算基金会)孵化的开源监控与告警工具。它以其简洁的设计、高效的存储模型和强大的查询语言(PromQL)而闻名。
核心特性:
- 基于拉取(Pull-based)模型,定期从目标端点抓取指标。
- 支持多维度标签(Labels),便于灵活聚合与过滤。
- 内置强大的表达式语言 PromQL,支持复杂的时间序列分析。
- 提供丰富的图形化界面(Grafana 集成良好)。
- 可扩展性强,可通过 Exporter 扩展支持多种外部系统。
⚠️ 注意:虽然 Prometheus 默认采用拉取模式,但也可以通过 Pushgateway 实现推送模式,适用于短生命周期任务。
1.2 OpenTelemetry:统一的可观测性标准
OpenTelemetry (OTel) 是由 CNCF 推动的开源项目,旨在为应用程序提供统一的可观测性数据收集框架。它是 Prometheus 与 Jaeger 等工具的“中间件”,提供了标准化的数据采集接口,并能将数据导出到多种后端(如 Prometheus、Jaeger、Zipkin、Datadog 等)。
OpenTelemetry 的三大支柱:
| 类型 | 功能说明 |
|---|---|
| Metrics | 用于度量系统行为,如请求速率、错误率、延迟等 |
| Traces | 跟踪一次请求在整个微服务链路中的流转过程 |
| Logs | 结构化日志记录,支持与 Trace 和 Metric 关联 |
✅ 关键优势:跨语言、跨平台、厂商无关。无论是 Java、Go、Python 还是 Node.js,都可以使用相同的 SDK 来采集数据。
1.3 两者的协作关系
| 组件 | 角色 | 数据流向 |
|---|---|---|
| Prometheus | 指标采集与存储 | 从 OTel Collector / Application Exporter 拉取 metrics |
| OpenTelemetry | 数据采集与转发 | 从应用中收集 metrics/traces/logs → 输出至 Collector → 导出至 Prometheus/Jaeger 等后端 |
因此,在本方案中,我们以 OpenTelemetry 作为前端数据采集层,通过其 Java SDK 在 Spring Boot 应用中注入埋点;再借助 OpenTelemetry Collector 将数据聚合并导出到 Prometheus(用于指标)和 Jaeger(用于链路追踪)。
二、环境准备与部署架构设计
2.1 架构图概览
+------------------+ +------------------+
| Spring Boot |<------>| OpenTelemetry |
| Microservices | | SDK (Java) |
+------------------+ +--------+---------+
|
+--------------v-------------------+
| OpenTelemetry Collector |
| - 接收 OTLP/HTTP/Metrics/Traces |
| - 多协议支持 |
| - 可选处理(采样、过滤、转换) |
+--------------+-------------------+
|
+--------------------v---------------------+
| Prometheus |
| - 存储 & 查询指标数据 |
| - 提供 PromQL 与 Grafana 集成 |
+--------------------+-------------------+
|
+--------------------v---------------------+
| Grafana |
| - 可视化指标仪表盘 |
| - 支持自定义面板 |
+--------------------+-------------------+
|
+--------------------v---------------------+
| Jaeger |
| - 存储 & 查询链路追踪数据 |
| - 提供分布式追踪可视化界面 |
+------------------------------------------+
📌 说明:
- 所有微服务均集成 OpenTelemetry SDK。
- OpenTelemetry Collector 作为中心节点,负责接收、处理并分发数据。
- Prometheus 专注指标管理,不参与追踪。
- Jaeger 专用于链路追踪。
- Grafana 作为统一的可视化入口,整合所有数据源。
2.2 依赖项安装与配置
(1)启动 Prometheus
# prometheus.yml
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'otel-collector'
static_configs:
- targets: ['otlp-collector:8888']
metrics_path: '/metrics'
params:
'match[]': ['{job="otel-collector"}']
- job_name: 'spring-boot-service'
static_configs:
- targets: ['service-a:8080', 'service-b:8081']
metrics_path: '/actuator/prometheus'
✅ 启动命令示例(Docker):
docker run -d \
--name prometheus \
-p 9090:9090 \
-v $(pwd)/prometheus.yml:/etc/prometheus/prometheus.yml \
prom/prometheus
(2)部署 OpenTelemetry Collector
# otel-collector.yaml
receivers:
otlp:
protocols:
http:
endpoint: "0.0.0.0:4318"
grpc:
endpoint: "0.0.0.0:4317"
exporters:
prometheus:
endpoint: "0.0.0.0:8888"
namespace: "spring_cloud"
const_labels:
job: "otel-collector"
jaeger:
endpoint: "jaeger-all-in-one:14250"
insecure: true
extensions:
health_check:
service:
pipelines:
metrics:
receivers: [otlp]
exporters: [prometheus]
traces:
receivers: [otlp]
exporters: [jaeger]
✅ 启动 Collector(Docker Compose):
version: '3.8'
services:
otel-collector:
image: otel/opentelemetry-collector-contrib:latest
ports:
- "4317:4317"
- "4318:4318"
- "8888:8888"
volumes:
- ./otel-collector.yaml:/etc/otel-collector.yaml
command: ["--config", "/etc/otel-collector.yaml"]
(3)部署 Jaeger(All-in-One)
jaeger:
image: jaegertracing/all-in-one:latest
ports:
- "16686:16686"
- "14268:14268"
- "14250:14250"
访问地址:
http://localhost:16686
三、Spring Boot 应用集成 OpenTelemetry SDK
3.1 Maven 依赖引入
在每个 Spring Cloud 微服务的 pom.xml 中添加以下依赖:
<dependencies>
<!-- OpenTelemetry SDK -->
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk</artifactId>
<version>1.30.0</version>
</dependency>
<!-- OpenTelemetry Exporter for OTLP -->
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp</artifactId>
<version>1.30.0</version>
</dependency>
<!-- Spring Boot Actuator (for /actuator/prometheus) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Spring Cloud Starter OpenTelemetry -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-open-telemetry</artifactId>
<version>2022.0.5</version>
</dependency>
</dependencies>
🔔 版本建议:使用与 Spring Boot 2.7+/3.x 兼容的版本,推荐使用
2022.0.5或更高(基于 Spring Cloud 2022.0.x)。
3.2 启用 OpenTelemetry 并配置导出器
方法一:通过 application.yml 配置(推荐)
# application.yml
spring:
application:
name: order-service
opentelemetry:
exporter:
otlp:
endpoint: http://otel-collector:4318
protocol: http/protobuf
trace:
sampler:
probability: 0.5 # 50% 请求采样,避免数据爆炸
metrics:
enabled: true
export:
interval: 10s
✅ 说明:
endpoint: 指向 OpenTelemetry Collector 的 HTTP 端点(默认 4318)。sampler.probability: 控制链路追踪采样率,生产环境建议设为0.1~0.5。export.interval: 指标导出间隔,控制频率。
方法二:程序代码初始化(高级场景)
@Configuration
public class OpenTelemetryConfig {
@Bean
public OpenTelemetry openTelemetry() {
return OpenTelemetrySdk.builder()
.setResourceBuilder(Resource.getDefault().toBuilder()
.put("service.name", "order-service")
.put("service.version", "1.0.0")
.build())
.setTracerProvider(
SdkTracerProvider.builder()
.setSampler(SamplingPolicy.probabilityBased(0.5))
.build()
)
.setMeterProvider(
SdkMeterProvider.builder()
.build()
)
.setExporter(new OtlpMetricExporter.Builder()
.setEndpoint("http://otel-collector:4318")
.build())
.setExporter(new OtlpTraceExporter.Builder()
.setEndpoint("http://otel-collector:4318")
.build())
.build();
}
}
✅ 优势:可精细化控制资源、采样策略、自定义标签等。
3.3 自动化埋点:HTTP 请求跟踪
当启用 spring-cloud-starter-open-telemetry 后,Spring Boot 会自动为以下操作添加追踪:
- 所有
@RestController的方法调用 @Scheduled定时任务- WebFlux 请求(如有)
- Feign Client 调用(需额外配置)
例如,一个简单的订单服务:
@RestController
@RequestMapping("/api/orders")
public class OrderController {
private final Logger logger = LoggerFactory.getLogger(OrderController.class);
@GetMapping("/{id}")
public ResponseEntity<Order> getOrder(@PathVariable String id) {
logger.info("Fetching order with ID: {}", id);
// 模拟业务逻辑
return ResponseEntity.ok(new Order(id, "Product A", 100));
}
@PostMapping
public ResponseEntity<String> createOrder(@RequestBody Order order) {
try {
Thread.sleep(100); // 模拟耗时
return ResponseEntity.ok("Order created successfully");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
}
}
✅ 无需手动编写
Span,框架自动完成上下文传播。
3.4 手动埋点:自定义追踪与指标
有时我们需要更细粒度的控制。例如,在数据库访问前后插入追踪。
示例:手动创建 Span
@Service
public class OrderService {
private final OpenTelemetry openTelemetry;
private final OrderRepository orderRepository;
public OrderService(OpenTelemetry openTelemetry, OrderRepository orderRepository) {
this.openTelemetry = openTelemetry;
this.orderRepository = orderRepository;
}
public Order findById(String id) {
// 创建新的 Span
Span span = openTelemetry.getTracer("order-service").spanBuilder("find-order-db")
.setAttribute("db.operation", "SELECT")
.setAttribute("db.statement", "SELECT * FROM orders WHERE id = ?")
.startSpan();
try (Scope scope = span.makeCurrent()) {
span.addEvent("Query started");
Order order = orderRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("Order not found"));
span.addEvent("Query completed");
span.setAttribute("db.rows.found", 1);
return order;
} catch (Exception e) {
span.recordException(e);
span.setStatus(Status.ERROR.withDescription(e.getMessage()));
throw e;
} finally {
span.end();
}
}
}
✅ 优势:可精确标注关键路径、添加自定义属性、记录事件。
示例:自定义指标(计数器 + 持久化)
@Component
public class OrderMetrics {
private final MeterRegistry meterRegistry;
private final Counter successCounter;
private final Timer requestTimer;
public OrderMetrics(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.successCounter = meterRegistry.counter("order.create.success.count", "service", "order-service");
this.requestTimer = meterRegistry.timer("order.create.duration.ms", "service", "order-service");
}
public void recordSuccess() {
successCounter.increment();
}
public void recordDuration(long durationMs) {
requestTimer.record(durationMs, TimeUnit.MILLISECONDS);
}
}
✅ 在
createOrder方法中调用:
long start = System.currentTimeMillis();
try {
// ... 业务逻辑
orderMetrics.recordSuccess();
} finally {
orderMetrics.recordDuration(System.currentTimeMillis() - start);
}
四、Prometheus 指标采集与可视化
4.1 Prometheus 如何获取指标?
当 spring-cloud-starter-open-telemetry 启用后,Spring Boot Actuator 会自动暴露 /actuator/prometheus 端点,输出如下格式:
# HELP http_server_requests_seconds_count Total number of HTTP requests.
# TYPE http_server_requests_seconds_count counter
http_server_requests_seconds_count{method="GET",status="200",uri="/api/orders/{id}",} 1.0
# HELP http_server_requests_seconds Sum of HTTP request durations.
# TYPE http_server_requests_seconds histogram
http_server_requests_seconds_bucket{le="0.005",} 0.0
http_server_requests_seconds_bucket{le="0.01",} 0.0
...
http_server_requests_seconds_sum{method="GET",status="200",uri="/api/orders/{id}",} 0.01234
http_server_requests_seconds_count{method="GET",status="200",uri="/api/orders/{id}",} 1.0
✅ 这些指标由 OpenTelemetry SDK 自动转换为 Prometheus 格式,经由 Collector 推送至 Prometheus。
4.2 Grafana 仪表盘搭建
步骤 1:添加 Prometheus 数据源
- 登录 Grafana (
http://localhost:3000) - 进入 Configuration > Data Sources
- 添加新数据源,选择 Prometheus
- URL 填写
http://prometheus:9090
步骤 2:导入官方模板
推荐使用以下模板:
- ID 1860: Prometheus Metrics Dashboard
- ID 16729: Spring Boot Monitoring Dashboard
✅ 导入方式:Dashboard → Import → Paste JSON
步骤 3:自定义面板(示例)
创建一个面板,展示订单服务的请求成功率与延迟:
# 面板标题:订单服务请求延迟与错误率
# 查询语句(PromQL):
rate(http_server_requests_seconds_count{job="spring-boot-service", status=~"5.."}[5m]) /
rate(http_server_requests_seconds_count{job="spring-boot-service"}[5m]) * 100
# 显示为:百分比
另一个面板用于查看平均响应时间:
# 面板标题:平均响应时间(毫秒)
histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{job="spring-boot-service"}[5m])) by (le, uri))
✅ 优势:可实时监控慢请求、识别热点接口。
五、链路追踪:从请求入口到服务调用链
5.1 调用链的生成原理
当客户端发起请求时,OpenTelemetry SDK 会在 HttpServerHandler 层自动创建根 Span,并注入 trace-id 与 span-id 到 HTTP Header(如 traceparent)。
后续每次服务间调用(如 Feign、RestTemplate、WebClient),SDK 会自动提取头信息,建立父子关系,形成完整链路。
5.2 示例:跨服务调用链
假设存在两个服务:
order-service:接收请求,调用inventory-serviceinventory-service:检查库存
OrderService 调用代码:
@FeignClient(name = "inventory-service", url = "http://inventory-service:8080")
public interface InventoryClient {
@GetMapping("/api/inventory/check/{sku}")
boolean checkStock(@PathVariable String sku);
}
// Controller
@PostMapping("/place")
public ResponseEntity<String> placeOrder(@RequestBody OrderRequest request) {
boolean inStock = inventoryClient.checkStock(request.getSku());
if (!inStock) {
return ResponseEntity.badRequest().body("Out of stock");
}
return ResponseEntity.ok("Order placed");
}
✅ 此时,整个调用链会被自动追踪,包括:
order-service的/place请求inventory-service的/api/inventory/check调用- 两者之间的调用耗时、状态码
5.3 查看链路追踪(Jaeger UI)
访问 http://localhost:16686
- 选择服务名:
order-service - 输入时间范围
- 点击某条追踪记录
你会看到类似如下结构:
Root Span: POST /place
├── Span: Call inventory-service
│ ├── Duration: 85ms
│ └── Status: OK
└── Span: DB query (if any)
点击任意子项,可查看详细信息:
- HTTP Headers(traceparent)
- 错误信息
- 事件日志(events)
- Attributes(自定义标签)
✅ 关键价值:快速定位“谁拖慢了整个流程”、“哪个服务返回了错误”
六、日志与追踪的关联(Log Correlation)
6.1 什么是日志关联?
传统日志只能看到“某时间点发生了什么”,但无法知道这是哪次请求、来自哪个用户。通过关联 trace-id,我们可以将日志与追踪链绑定。
6.2 配置 Logback + OpenTelemetry
(1)添加依赖
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-context-propagators</artifactId>
<version>1.30.0</version>
</dependency>
(2)配置 Logback XML
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg %X{trace_id} %X{span_id}%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
✅
%X{trace_id}和%X{span_id}会自动注入当前追踪上下文。
(3)在代码中打印日志
@Value("${spring.application.name}")
private String serviceName;
@GetMapping("/test")
public ResponseEntity<String> test() {
Span currentSpan = Tracer.current().span();
log.info("Processing request in {} service", serviceName);
log.info("Trace ID: {}", currentSpan.getContext().getTraceId());
return ResponseEntity.ok("Hello");
}
✅ 输出示例:
10:23:45.123 [http-nio-8080-exec-1] INFO com.example.OrderController - Processing request in order-service service
10:23:45.124 [http-nio-8080-exec-1] INFO com.example.OrderController - Trace ID: 0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d
6.3 使用 ELK/Splunk 进行集中日志分析
将带有 trace_id 的日志发送到 Elasticsearch,即可在 Kibana 中按 trace_id 过滤,查看完整链路日志。
✅ 优势:结合追踪与日志,实现“一次请求,全链路可见”。
七、最佳实践与性能优化建议
| 实践 | 说明 |
|---|---|
| ✅ 设置合理的采样率 | 生产环境建议 0.1~0.5,避免追踪数据过多影响性能 |
✅ 使用 OtlpTraceExporter |
比 JaegerExporter 更高效,支持批量传输 |
| ✅ 启用压缩(gzip) | 减少网络开销,提升传输效率 |
| ✅ 限制标签数量 | 避免因动态标签导致数据膨胀(如 user.id) |
| ✅ 定期清理旧数据 | 设置 Prometheus retention period(如 15 天) |
| ✅ 监控 Collector 本身 | 用 Prometheus 监控 Collector 内存、吞吐量、丢包率 |
| ✅ 使用分布式追踪分析工具 | 如 Jaeger UI、Tempo、OpenSearch Dashboards |
性能调优建议
- 减少不必要的埋点:仅对关键路径打点。
- 异步导出:使用
async模式导出数据,避免阻塞主线程。 - 批量发送:设置
batch.size=1000,减少网络请求次数。 - 禁用无用功能:如不需要日志传播,关闭
context-propagator。
八、总结:迈向真正的可观测性
通过本方案,我们成功构建了一个基于 Spring Cloud + Prometheus + OpenTelemetry 的全链路可观测性体系。它具备以下特点:
✅ 统一数据采集标准:使用 OpenTelemetry SDK,兼容多语言、多平台
✅ 高可扩展性:支持数百个微服务同时接入
✅ 深度链路分析:精准定位性能瓶颈与错误源头
✅ 联动分析能力:指标 + 追踪 + 日志三位一体
✅ 生产就绪:符合企业级监控要求,支持告警、自动化运维
未来可进一步拓展:
- 集成 AlertManager 告警
- 使用 Tempo 替代 Jaeger(更轻量)
- 引入 AI 异常检测(如 Anomaly Detection in Prometheus)
- 实现基于 OpenTelemetry 的可观测性 API 网关
附录:常用 PromQL 查询示例
| 场景 | PromQL |
|---|---|
| 5xx 错误率 | rate(http_server_requests_seconds_count{status=~"5.."}[5m]) / rate(http_server_requests_seconds_count[5m]) |
| 95% 延迟 | histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket[5m])) by (le)) |
| 按服务统计请求数 | sum(rate(http_server_requests_seconds_count{job="spring-boot-service"}[5m])) by (service) |
| 按路径统计延迟 | histogram_quantile(0.90, sum(rate(http_server_requests_seconds_bucket{uri="/api/orders"}[5m])) by (le)) |
📌 结语:
可观测性不是“锦上添花”,而是现代微服务架构的“生命线”。掌握 Prometheus 与 OpenTelemetry,意味着你掌握了掌控复杂系统的钥匙。从今天起,让每一个请求都有迹可循,让每一次失败都清晰可见。
作者:技术观察者 | 发布于 2025年4月
评论 (0)