指标(Metrics)是可观测性的地基:它用最小的成本回答「系统现在到底怎么样」。Micrometer 是 JVM 生态的事实标准指标库,OpenTelemetry 则把指标、日志、链路统一到一套语义与传输协议中。本文聚焦指标工程的完整链条,从 Micrometer 模型、维度设计、OTLP 导出到 Grafana 大盘与告警。
前置基础可先阅读 Java 监控诊断与可观测性 与 日志框架、MDC 与分布式链路追踪。
1. 可观测性三大支柱与指标定位
1.1 三大信号的分工
| 信号 | 回答的问题 | 数据形态 | 成本 |
|---|---|---|---|
| 指标 Metrics | 现在怎么样 | 聚合数值 | 低 |
| 日志 Logs | 发生了什么 | 事件文本 | 中 |
| 链路 Traces | 出在哪一步 | 调用关系 | 高 |
1.2 指标的价值
指标可以无限期低成本保留、可以跨服务横向对比、可以驱动自动伸缩与告警,因此成为 SRE 告警的事实载体。链路与日志负责事后定位,指标负责事前预警。
2. Micrometer 指标模型
2.1 Meter、MeterId 与 Tag
Micrometer 的核心抽象是 Meter,每个 Meter 由唯一的 MeterId 标识,MeterId 由名称加一组 Tag(键值对)组成。Tag 是指标的多维切片,也是告警聚合的维度。
Meter.Id id = new Meter.Id(
"http.server.requests", // 名称
Tags.of("uri", "/orders", // 维度标签
"method", "POST"),
null, null, Type.TIMER);
2.2 指标类型
| 类型 | Micrometer 类 | 语义 | 典型场景 |
|---|---|---|---|
| Counter | Counter | 单调递增计数 | 请求总数、错误数 |
| Gauge | Gauge | 当前瞬态值 | 队列长度、连接数 |
| Timer | Timer | 耗时分布 | 接口延迟 |
| DistributionSummary | DistributionSummary | 数值分布 | 响应体大小 |
| LongTaskTimer | LongTaskTimer | 长任务进行中时长 | 批处理耗时 |
2.3 命名规范与单位
命名三段式:<域>.<对象>.<动作>
例:http.server.requests、db.pool.active、order.created
单位约定:Timer 以秒为单位,字节类指标带 bytes 后缀
基数约束:Tag 取值必须是有限集合,禁止把 orderId 作为标签
3. MeterRegistry 与多注册表
3.1 CompositeMeterRegistry
应用常需要同时把指标送往多个后端。CompositeMeterRegistry 把多个注册表聚合成一个门面:
CompositeMeterRegistry registry = new CompositeMeterRegistry();
registry.add(new PrometheusMeterRegistry(PrometheusConfig.DEFAULT));
registry.add(new OtlpMeterRegistry(OtlpConfig.DEFAULT, Clock.SYSTEM));
3.2 全局注册表
Spring Boot 中 MeterRegistry 由自动配置注入,且天然是 Composite。业务代码统一注入 MeterRegistry,而不是绑定到具体后端:
@Service
public class OrderMetricsService {
private final Counter orderCreated;
public OrderMetricsService(MeterRegistry registry) {
this.orderCreated = Counter.builder("order.created.total")
.description("累计创建的订单数")
.register(registry);
}
public void onCreated(String channel) {
orderCreated.increment(); // 基本计数
orderCreated.increment(); // 或按标签递增
}
}
3.3 维度设计要点
- 有限基数:标签值来自枚举或固定集合,绝不使用订单号、用户 ID。
- 高基数拆走:需要按请求维度分析时改用日志或链路,不要堆标签。
- 统一命名:跨服务遵循统一前缀,便于大盘聚合。
4. OpenTelemetry 与 OTLP 导出
4.1 OpenTelemetry 集成
OpenTelemetry(OTel)是云原生可观测性的统一标准。通过 OTel SDK 桥接 Micrometer,指标既能被 Prometheus 拉取,也能经 OTLP 推送到 Collector 再分发到任意后端:
# application.yml
management:
otlp:
metrics:
export:
url: http://otel-collector:4317
step: 30s
tracing:
sampling:
probability: 0.1
4.2 从 Micrometer 桥接到 OTel
引入 micrometer-registry-otlp 后,Micrometer 指标以 OTLP 协议导出,同时保留 Prometheus 端点:
// 依赖 io.micrometer:micrometer-registry-otlp
// 与 io.micrometer:micrometer-registry-prometheus 可并存
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-otlp</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
4.3 OTLP Collector 分发架构
Java 应用 ──OTLP──> OTel Collector ──> Prometheus / ClickHouse / 云端
│
└──/actuator/prometheus──> Prometheus 直接拉取
Collector 承担「接入统一、后端可换」的职责,业务侧只需面向 OTLP 输出,后端的增删不影响应用。
5. Prometheus 采集与 Grafana 大盘
5.1 Scrape 配置
# prometheus.yml
scrape_configs:
- job_name: order-service
metrics_path: /actuator/prometheus
static_configs:
- targets: ["order-service:8080"]
labels:
service: order-service
5.2 RED 与 USE 方法
| 方法 | 含义 | 监控对象 | 示例指标 |
|---|---|---|---|
| RED | 速率、错误、耗时 | 服务请求 | 请求 QPS、5xx 率、P99 延迟 |
| USE | 利用率、饱和度、错误 | 基础设施 | CPU 利用率、队列深度、磁盘错误 |
// RED 三件套在 Spring 中由 actuator 自动暴露
// http.server.requests 已包含 count、sum、bucket 三个维
5.3 Grafana 面板设计
大盘遵循「顶层概要、中层趋势、底层明细」三层:
第一行:全局 QPS、错误率、P99 延迟(服务健康总览)
第二行:JVM 内存、GC 停顿、线程数、连接池
第三行:各接口分维度趋势、依赖调用延迟、队列积压
// 常用 PromQL 片段
// P99 延迟:histogram_quantile(0.99, sum(rate(http_server_requests_seconds_bucket[5m])) by (le))
// 错误率:sum(rate(http_server_requests_seconds_count{status=~"5.."}[5m])) /
// sum(rate(http_server_requests_seconds_count[5m]))
6. 应用级自定义指标
6.1 业务埋点设计
业务指标直接反映经营状态,比基础设施指标更贴近用户价值。设计原则是「一个指标回答一个问题」:
@Service
public class PaymentMetrics {
private final DistributionSummary amountSummary;
private final Counter failureCounter;
public PaymentMetrics(MeterRegistry registry) {
this.amountSummary = DistributionSummary.builder("payment.amount")
.baseUnit("CNY")
.publishPercentiles(0.5, 0.95)
.register(registry);
this.failureCounter = Counter.builder("payment.failure.total")
.tag("cause", "unknown")
.register(registry);
}
}
6.2 Timer 记录慢调用
Timer 的典型用法是包住一次调用,自动记录耗时分布与计数:
Timer timer = Timer.builder("outbound.http.latency")
.tag("target", "search-service")
.publishPercentileHistogram()
.register(registry);
return timer.record(() -> restTemplate.postForObject(url, req, Resp.class));
6.3 自定义 MeterBinder
需要把第三方组件的内部状态暴露为指标时,实现 MeterBinder 并在启动时绑定:
@Component
public class LiquibaseMetricsBinder implements MeterBinder {
private final ObjectProvider<DataSource> dataSourceProvider;
@Override
public void bindTo(MeterRegistry registry) {
Gauge.builder("db.pool.active", this, self -> {
HikariDataSource ds = (HikariDataSource) dataSourceProvider.getObject();
return ds.getHikariPoolMXBean().getActiveConnections();
})
.register(registry);
}
}
7. 告警
7.1 SLO 与告警分级
告警要围绕服务等级目标(SLO)设计,而不是对每个指标都设阈值:
P0 页面级:核心链路错误率超标、主流程不可用
P1 页面级:P99 延迟恶化、容量逼近上限
P2 邮件级:依赖故障、非核心功能降级
7.2 告警规则示例
Prometheus 告警规则避免使用 Go 模板,直接给出可读的标签与注解:
groups:
- name: business-alerts
rules:
- alert: PaymentErrorRateHigh
expr: rate(payment_failure_total[5m]) > 0.02
for: 10m
labels:
severity: critical
annotations:
summary: 支付失败率超过 2%
description: 近 5 分钟支付失败率异常,需立即排查
- alert: OrderP99High
expr: histogram_quantile(0.99,
sum(rate(http_server_requests_seconds_bucket{uri="/api/v1/orders"}[5m]))
by (le)) > 1.5
for: 5m
labels:
severity: warning
7.3 告警疲劳与抑制
- 收敛:同类告警聚合,避免同一故障重复轰炸。
- 抑制:已知问题窗口内自动静默相关告警。
- 消除:告警必须附带可执行的排查步骤,否则只是噪音。
8. 总结
| 主题 | 核心要点 |
|---|---|
| 指标模型 | Meter 由名称与 Tag 组成,类型决定语义 |
| 注册表 | Composite 门面,面向后端多写 |
| 标准导出 | Micrometer 桥接 OTLP,Collector 统一分发 |
| 大盘 | RED 看服务、USE 看资源,三层面板设计 |
| 业务埋点 | 一个指标回答一个问题,标签基数受限 |
| 告警 | 围绕 SLO 分级,收敛与抑制防疲劳 |
可观测性工程不是堆工具,而是建立「指标定义 → 标准导出 → 大盘可视化 → 分级告警」的闭环。Micrometer 负责把业务事实变成标准指标,OTLP 负责让指标顺畅流向任意后端,而真正产生价值的是围绕 SLO 设计的那一套告警与复盘机制。
延伸阅读
- Java 监控诊断与可观测性 — Actuator、Arthas 与 JFR 的诊断补充
- 日志框架、MDC 与分布式链路追踪 — 三大信号中的日志与链路
- JVM 性能调优与 GC 优化 — 大盘中 JVM 指标的含义
- Java 微服务治理深化:熔断限流降级、灰度发布与全链路压测 — 告警与容量治理的协同
- Spring Boot 核心原理与自动配置 — Actuator 与指标自动装配
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。