可观测
可观测性是指通过系统输出的日志、链路、指标,在不修改系统的情况下推断出内部状态。Metrics 告诉你「有问题」,Traces 告诉你「问题在哪条链路」,Logs 告诉你「具体发生了什么」。
微服务越多,可观测性越重要。没有可观测性,发现问题靠运气,定位问题靠猜。
三大支柱
| 支柱 | 定义 | 工具 |
|---|---|---|
| Metrics | 数值型定量测量(QPS、CPU) | Prometheus, Micrometer |
| Logs | 带时间戳的离散事件记录 | ELK, Loki |
| Traces | 单次请求的完整调用路径 | Jaeger, Zipkin |
Metrics
Metrics 是系统运行状态的量化指标,用于直观反映系统健康状况。
四种指标类型
| 类型 | 说明 | 示例 |
|---|---|---|
| Counter | 单调递增 | 请求总数、错误总数 |
| Gauge | 任意增减的瞬时值 | 内存使用量 |
| Histogram | 统计分布,支持分位数 | 延迟分布(P99) |
| Summary | 客户端计算分位数 | 响应时间 P50/P95 |
Prometheus + Grafana
Prometheus 使用 Pull 模式主动拉取指标,与 Kubernetes 原生集成,自动发现服务。
scrape_configs:
- job_name: 'spring-boot-app'
static_configs:
- targets: ['localhost:8080']
metrics_path: '/actuator/prometheus'Logs
Logs 记录系统运行时的离散事件,是排查问题的重要依据。
结构化日志
传统日志难以机器解析,推荐结构化格式(JSON),且必须携带 TraceId 用于关联链路追踪。
{
"timestamp": "2026-04-14T10:00:00Z",
"level": "ERROR",
"traceId": "abc123def456",
"service": "order-service",
"message": "下单失败",
"error": "库存不足"
}日志收集架构
日志框架选择
应用中不可直接使用日志系统(Log4j、Logback)中的 API,应依赖使用日志框架门面(SLF4J)。推荐使用 SLF4J:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger logger = LoggerFactory.getLogger(Test.class);日志级别使用
| 级别 | 使用场景 |
|---|---|
| ERROR | 系统逻辑出错、异常、重要错误 |
| WARN | 用户输入参数错误、刚上线时的业务行为信息 |
| INFO | 运行信息、状态变化 |
| DEBUG | 开发环境调试,生产环境禁止输出 |
| TRACE | 详细追踪信息 |
日志规范
- 所有日志文件至少保存 15 天(有些异常以"周"为频次发生)
- 根据国家法律,网络安全相关记录留存不少于六个月
- 字符串变量拼接使用占位符方式:
logger.debug("id: {}", id) - trace/debug/info 级别必须进行开关判断
- 避免重复打印日志,设置
additivity=false - 生产环境禁止
System.out和e.printStackTrace() - 异常日志包含现场信息和堆栈信息:
logger.error("params:{}", params, e)
日志配置示例
<configuration>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/home/admin/app/logs/app.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>/home/admin/app/logs/app.log.%d{yyyy-MM-dd}</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="com.example" level="INFO" additivity="false">
<appender-ref ref="FILE"/>
</logger>
<root level="WARN">
<appender-ref ref="FILE"/>
</root>
</configuration>Traces
Traces 记录单个请求在分布式系统中的完整调用路径,用于定位问题链路。
TraceId / SpanId 机制
每个 Span 记录:服务名、开始时间、持续时间、状态、自定义标签。
Jaeger vs Zipkin
| 维度 | Zipkin | Jaeger |
|---|---|---|
| 来源 | Uber(CNCF 毕业) | |
| 存储 | 内存、MySQL、Cassandra | Elasticsearch、Cassandra |
| 适用 | 轻量,中小项目 | 大规模系统 |
Spring Boot 集成
management:
tracing:
sampling:
probability: 1.0 # 生产建议 0.1TraceId 自动透传(HTTP Header、MQ 消息头),日志自动携带。
OpenTelemetry
OpenTelemetry(OTel)是 CNCF 托管的统一可观测性规范,由 OpenTracing + OpenCensus 合并而来,核心目标是避免厂商锁定,用一套 API 对接任意后端。
推荐新项目使用 OTel,与 Kubernetes 生态深度集成。
告警原则
| 原则 | 说明 |
|---|---|
| SLO 驱动 | 基于用户体验指标设置告警 |
| 减少噪音 | 告警必须有行动意义 |
| 分级处理 | P0(立即响应)、P1(1小时内)、P2(工作时间) |
实践路径
| 阶段 | 方案 |
|---|---|
| 基础 | Prometheus + Grafana(指标)+ ELK(日志) |
| 进阶 | 加入 Jaeger(链路追踪),日志携带 TraceId |
| 云原生 | OTel + Grafana 全家桶 |
常见问题处理
Prometheus 抓不到指标
- 确认应用暴露了
/actuator/prometheus端点 - 检查防火墙是否放行 Prometheus 的抓取端口
- 确认
scrape_configs中的targets地址正确
日志不携带 TraceId
- 确认引入了 Sleuth 或 OTel 依赖
- 检查日志格式是否包含
%X{traceId}(Logback)或对应占位符 - 确认 TraceId 透传中间件(MQ、HTTP Header)配置正确