
云原生架构下,分布式系统的组件数量呈指数级增长,服务间的调用关系愈发复杂,传统基于预设阈值的监控体系,已无法应对分布式环境下“未知的未知”问题。可观测性作为云原生架构的核心能力,通过系统对外输出的三类核心数据,实现对系统内部状态的深度洞察,支撑故障快速定位、性能优化、容量规划等核心场景。
可观测性是控制论中的核心概念,被引入IT领域后,CNCF给出了明确的定义:可观测性是指通过系统外部输出的数据,理解和推断系统内部状态的能力,无需修改系统代码即可回答关于系统运行的任意问题。
传统监控与可观测性的核心差异清晰明确:

三大支柱并非互相替代的关系,而是互补协同的有机整体,各自承担不可替代的角色:
Metrics是对系统状态的聚合型数值度量,以时间序列的形式存储,核心特征是可聚合、低存储成本、支持实时统计与告警,是触发异常感知的第一入口。
时间序列数据的核心模型由四个要素构成,完全符合Prometheus与OpenTelemetry官方规范:
http_server_requests_seconds_count;status="200"、uri="/api/order";Metrics分为四大核心类型,不同类型的底层逻辑与适用场景完全不同,此处明确区分易混淆的类型边界。
核心易混淆点明确区分:
云原生环境下,Metrics的主流架构分为Pull与Push两种模式,核心差异与适用场景如下。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>observability-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>observability-demo</name>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
spring:
application:
name:order-service
server:
port:8080
management:
endpoints:
web:
exposure:
include:prometheus,health
metrics:
tags:
application:${spring.application.name}
distribution:
percentiles-histogram:
http.server.requests:true
package com.example.observabilitydemo.controller;
import io.micrometer.core.annotation.Timed;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.DistributionSummary;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.atomic.AtomicInteger;
@RestController
@RequestMapping("/api/order")
publicclass OrderController {
privatefinal Counter orderCreateCounter;
privatefinal Counter orderFailCounter;
privatefinal AtomicInteger activeOrderCount;
privatefinal DistributionSummary orderAmountSummary;
public OrderController(MeterRegistry meterRegistry) {
this.orderCreateCounter = Counter.builder("order.create.total")
.description("订单创建总次数")
.register(meterRegistry);
this.orderFailCounter = Counter.builder("order.create.fail.total")
.description("订单创建失败总次数")
.register(meterRegistry);
this.activeOrderCount = new AtomicInteger(0);
Gauge.builder("order.active.count", activeOrderCount, AtomicInteger::get)
.description("当前活跃订单数")
.register(meterRegistry);
this.orderAmountSummary = DistributionSummary.builder("order.amount.summary")
.description("订单金额分布统计")
.publishPercentiles(0.5, 0.9, 0.99)
.register(meterRegistry);
}
@GetMapping("/create/{amount}")
@Timed(value = "order.create.time", description = "订单创建接口耗时")
public String createOrder(@PathVariable Long amount) {
orderCreateCounter.increment();
activeOrderCount.incrementAndGet();
orderAmountSummary.record(amount);
try {
if (amount <= 0) {
thrownew IllegalArgumentException("订单金额不能小于等于0");
}
return"订单创建成功";
} catch (Exception e) {
orderFailCounter.increment();
return"订单创建失败";
} finally {
activeOrderCount.decrementAndGet();
}
}
}
global:
scrape_interval:15s
evaluation_interval:15s
scrape_configs:
-job_name:"spring-boot-application"
metrics_path:"/actuator/prometheus"
static_configs:
-targets:["host.docker.internal:8080"]
Logging是系统运行过程中产生的离散事件记录,每条日志对应一个完整的系统行为事件,附带时间戳、事件上下文、异常堆栈等信息,核心特征是完整、不可变、带上下文,是故障根因定位的核心依据。
12因素应用规范中明确要求,云原生应用应将日志以事件流的形式输出到标准输出与标准错误,不负责日志的存储与持久化,由基础设施统一处理日志的采集、传输、存储与检索,这是云原生日志架构的核心原则。
云原生日志架构分为四个核心层级,实现日志的全链路处理。
业务应用负责生成结构化日志,核心要求是结构化、统一格式、带全链路上下文,避免非结构化的自由文本日志,非结构化日志无法实现高效的检索与聚合分析。
结构化日志的核心字段规范:
负责从容器、节点、应用中采集日志流,主流采集工具为Fluent Bit与Fluentd,其中Fluent Bit资源占用更低,性能更高,是Kubernetes环境下的首选采集工具。
采集层的核心能力:
负责将采集到的日志数据可靠传输到存储层,核心要求是高吞吐、低延迟、高可靠,主流方案分为两类:
负责日志的持久化存储与快速检索,主流引擎为OpenSearch与Elasticsearch,基于倒排索引实现日志的全文检索与聚合分析,支持PB级别的日志数据存储。
二者的适用场景有明确的边界,不可混用:
核心原则:能用Metrics实现的统计与告警,绝对不要用Logging实现,避免不必要的资源浪费。
在原有pom.xml中新增依赖:
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>8.0</version>
</dependency>
在resources目录下创建logback-spring.xml:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
<springProperty scope="context" name="applicationName" source="spring.application.name"/>
<appender name="JSON_CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<includeMdcKeyName>trace_id</includeMdcKeyName>
<includeMdcKeyName>span_id</includeMdcKeyName>
<includeMdcKeyName>user_id</includeMdcKeyName>
<includeMdcKeyName>order_id</includeMdcKeyName>
<customFields>{"service":"${applicationName}"}</customFields>
<timestampPattern>yyyy-MM-dd'T'HH:mm:ss.SSSXXX</timestampPattern>
<writeDurationAsNumber>true</writeDurationAsNumber>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="JSON_CONSOLE"/>
</root>
</configuration>
package com.example.observabilitydemo.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.stereotype.Service;
@Service
publicclass OrderService {
privatestaticfinal Logger log = LoggerFactory.getLogger(OrderService.class);
public void createOrder(Long orderId, Long userId, Long amount) {
MDC.put("order_id", orderId.toString());
MDC.put("user_id", userId.toString());
try {
log.info("开始创建订单");
if (amount <= 0) {
log.error("订单创建失败,金额非法: {}", amount);
thrownew IllegalArgumentException("订单金额非法");
}
log.info("订单创建成功");
} finally {
MDC.remove("order_id");
MDC.remove("user_id");
}
}
}
[SERVICE]
Flush 1
Log_Level info
Daemon off
Parsers_File parsers.conf
[INPUT]
Name tail
Tag kube.*
Path /var/log/containers/*.log
Parser docker
Refresh_Interval 10
Mem_Buf_Limit 5MB
Skip_Long_Lines On
[FILTER]
Name kubernetes
Match kube.*
Kube_URL https://kubernetes.default.svc:443
Kube_CA_File /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
Kube_Token_File /var/run/secrets/kubernetes.io/serviceaccount/token
Merge_Log On
K8S-Logging.Parser On
K8S-Logging.Exclude Off
[OUTPUT]
Name opensearch
Match *
Host opensearch-cluster.default.svc
Port 9200
Index k8s-logs-%Y.%m.%d
Suppress_Type_Name On
Logstash_Format Off
Auto_Index On
分布式链路追踪的理论基础来自Google 2010年发布的Dapper论文,核心目标是还原单次用户请求在分布式系统中的完整流转路径,记录请求经过的每一个服务、组件、中间件的处理细节,解决分布式系统中“请求在哪里变慢了”、“故障发生在哪个环节”的核心问题。
OpenTelemetry规范中,链路追踪的核心数据模型如下:
云原生环境下,链路追踪的架构分为五个核心层级。
负责在业务代码中注入链路追踪的逻辑,分为两种埋点方式:
负责控制链路数据的采集量,高并发分布式系统中,全量采集链路数据会带来极高的存储与计算成本,采样是平衡观测能力与资源成本的核心手段,主流采样策略分为两类:
负责将采集到的链路数据传输到后端存储,OpenTelemetry规范中,统一使用OTLP协议传输链路数据,支持gRPC与HTTP两种传输方式,实现跨厂商的兼容。
负责链路数据的持久化存储与检索,主流存储方案分为两类:
负责链路数据的拓扑分析、检索与可视化,核心能力包括:
三者的核心价值形成完整的互补闭环:
OpenTelemetry Java Agent实现零代码修改的全链路埋点,支持Spring Boot、Dubbo、MySQL、Redis等主流框架与中间件的自动埋点,启动命令如下:
java -javaagent:opentelemetry-javaagent-1.39.0.jar \
-Dotel.service.name=order-service \
-Dotel.traces.exporter=jaeger \
-Dotel.exporter.jaeger.endpoint=http://jaeger:14250 \
-Dotel.logs.exporter=none \
-Dotel.metrics.exporter=none \
-jar observability-demo-0.0.1-SNAPSHOT.jar
package com.example.observabilitydemo.service;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.Scope;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.stereotype.Service;
@Service
publicclass PaymentService {
privatestaticfinal Logger log = LoggerFactory.getLogger(PaymentService.class);
privatefinal Tracer tracer;
public PaymentService(OpenTelemetry openTelemetry) {
this.tracer = openTelemetry.getTracer("com.example.observabilitydemo.service.PaymentService");
}
public void processPayment(Long orderId, Long userId, Long amount) {
Span paymentSpan = tracer.spanBuilder("processPayment")
.setAttribute("order_id", orderId)
.setAttribute("user_id", userId)
.setAttribute("amount", amount)
.startSpan();
try (Scope scope = paymentSpan.makeCurrent()) {
MDC.put("trace_id", Span.current().getSpanContext().getTraceId());
MDC.put("span_id", Span.current().getSpanContext().getSpanId());
log.info("开始处理支付");
paymentSpan.addEvent("支付校验开始");
if (amount > 10000) {
thrownew RuntimeException("支付金额超过限额");
}
paymentSpan.addEvent("支付校验完成");
log.info("支付处理完成");
} catch (Exception e) {
paymentSpan.recordException(e);
log.error("支付处理失败", e);
throw e;
} finally {
paymentSpan.end();
MDC.remove("trace_id");
MDC.remove("span_id");
}
}
}
version: '3.8'
services:
jaeger:
image:jaegertracing/all-in-one:1.58.0
container_name:jaeger
ports:
-"16686:16686"
-"14250:14250"
environment:
-COLLECTOR_OTLP_ENABLED=true
-LOG_LEVEL=info
TraceId是串联Metrics、Logging、Tracing的核心纽带,实现三大支柱的数据完全打通:
完整的故障排查流程,是三大支柱协同的核心价值,流程如下:

OpenTelemetry是CNCF孵化的毕业项目,是当前云原生可观测领域的事实标准,统一了Metrics、Logging、Tracing三大支柱的采集规范、数据模型与传输协议,核心价值在于:
可观测性是云原生分布式系统的核心能力,Metrics、Logging、Tracing三大支柱不是互相替代的关系,而是互补协同的有机整体。 Metrics作为宏观监控的入口,实现异常的快速感知;Tracing作为分布式路径的还原工具,实现故障环节的快速定位;Logging作为事件详情的记录载体,实现根因的精准定位。