文章目录
- [1. 基础概念](#1. 基础概念)
-
- [1.1 可观测性](#1.1 可观测性)
- [1.2 指标定义](#1.2 指标定义)
- [1.3 数据结构](#1.3 数据结构)
- [2. 指标名称(Metric Name)](#2. 指标名称(Metric Name))
-
- [2.1 核心概念](#2.1 核心概念)
- [2.2 指标命名规范](#2.2 指标命名规范)
- [2.3 跨平台兼容](#2.3 跨平台兼容)
- [3. 标签(Tag)](#3. 标签(Tag))
-
- [3.1 核心概念](#3.1 核心概念)
- [3.2 标签编写规范](#3.2 标签编写规范)
-
- [3.2.1 ✅ 推荐规范写法](#3.2.1 ✅ 推荐规范写法)
- [3.2.2 ❌ 禁止反模式](#3.2.2 ❌ 禁止反模式)
- [3.3 全局公共标签](#3.3 全局公共标签)
-
- [3.3.1 核心概念](#3.3.1 核心概念)
- [3.3.2 两种配置方式](#3.3.2 两种配置方式)
- [3.3.3 最佳实践](#3.3.3 最佳实践)
- [3.4 低基数标签](#3.4 低基数标签)
- [3.5 高基数标签](#3.5 高基数标签)
- [4. 指标数值(Value)](#4. 指标数值(Value))
- [5. 时间戳(Timestamp)](#5. 时间戳(Timestamp))
1. 基础概念
1.1 可观测性

云原生计算基金会(CNCF)行业标准定义:可观测性,指仅依靠系统对外输出的外部信号,推断系统内部运行状态的能力。
可观测性 (Observability) 是衡量复杂分布式系统的核心属性:系统通过向外持续产出遥测数据(指标、链路追踪、日志),使开发运维人员仅凭外部信号,反向推导系统内部运行状态。
区别于传统监控只能识别预先定义的已知问题,可观测性体系擅长排查从未遇到的未知异常,是微服务、云原生系统稳定性建设的基础能力。
可观测性三大支柱:
- 指标
Metrics:宏观聚合数据(QPS、耗时、错误率、队列堆积),用于告警、大盘、趋势分析; - 分布式追踪
Tracing:单次请求完整链路,用于定位慢调用、依赖故障; - 日志
Logging:详细业务上下文,用于精准问题定位。
在
Spring云原生生态中,Micrometer整套组件正是构建JVM应用可观测能力的标准化基础设施。
1.2 指标定义
指标 (Metrics)是可观测性三大支柱 之一,是对系统、业务运行状态的数值型时序采集数据。
核心特征:
- 定时采样,存储为时序数据;
- 纯数字,支持聚合、计算、告警、可视化;
- 性能开销极低,适合长期存储大盘数据;
- 回答量化问题:
QPS、延迟、错误率、资源占用、业务吞吐量。
例如,JVM 堆内存指标 是 Java 应用健康度的核心生命线指标 ,既能提前预警内存泄漏、OOM 宕机,又能指导 GC 调优、容量规划,故障时快速缩小排查范围,是线上服务稳定运行必不可少的监控依据。
系统每秒定时采集 JVM 堆内存,每一条采集数据都会附带时间戳,时序库按时间串联成折线图,直观看到内存变化趋势。
折线图示例:

1.3 数据结构
一条 Metrics 时序样本由 5 部分核心字段 组成:
text
<指标名称> {<标签Key=Value列表>} <指标数值> <时间戳> [元数据类型]
字段说明:
name:指标名称,标识指标语义,区分指标大类,遵循命名规范;labels/tag:标签,用于维度细分的键值对结构;value:指标数值,表示当前指标的具体数值;timestamp:时间戳,标记该数值采集的精确时刻,构成时序数据核心;metric type:指标类型元数据,属于指标全局元数据,定义数值业务逻辑。
Prometheus 原生格式示例:
java
# HELP http_server_requests_seconds HTTP请求耗时
# TYPE http_server_requests_seconds histogram
http_server_requests_seconds_bucket{service="pay-service",status="200",endpoint="/pay",le="0.1"} 1245 1786923100000
http_server_requests_seconds_bucket{service="pay-service",status="500",endpoint="/pay",le="1"} 32 1786923100000
http_server_requests_seconds_sum{service="pay-service",status="200",endpoint="/pay"} 86.42 1786923100000
http_server_requests_seconds_count{service="pay-service",status="200",endpoint="/pay"} 1245 1786923100000
拆解对应结构:
name:http_server_requests_seconds_bucketlabels:service="pay-service",status="200",endpoint="/pay",le="0.1"value:1245timestamp:1786923100000type:histogram(顶部注释元数据)
在 Micrometer 、OpenTelemetry 等开发/埋点 SDK 中,内部统一抽象指标对象数据结构,用于采集、计算、聚合,再转换成各种导出格式(Prometheus、Influx、Jaeger 等)。
指标对象 JSON 示例:
json
{
"name": "jvm_memory_used_bytes",
"type": "gauge",
"tags": [
{"key": "area", "value": "heap"},
{"key": "instance", "value": "127.0.0.1:8080"}
],
"samples": [
{
"timestamp": 1786923100000,
"value": 268435456
}
]
}
内存结构化指标对象转换成 Prometheus 文本格式流程:

2. 指标名称(Metric Name)
2.1 核心概念
指标名称是一条监控时序数据唯一业务大类标识,用来描述「这是哪一类监控行为」,是区分不同业务监控数据的核心文本。
遵循 Micrometer 标准:全小写、小数点分层分隔。
核心特点:
- 代表一类统一行为,粒度粗、语义固定;
- 不携带动态、可变信息;
- 跨监控后端自动转换格式(
Prometheus/Graphite/Atlas); - 用来做大盘大类聚合、告警分组。
指标名示例:
http.server.requests:服务端HTTP请求db.mysql.query:MySQL数据库查询jvm.memory.used:JVM内存占用kafka.producer.send:Kafka生产者发送消息
2.2 指标命名规范
Micrometer 强制统一指标命名格式:
- 全小写英文:指标名称全部由小写英文字母构成,不允许出现大写字母。
- 使用小数点
.分层分隔语义 :按照【领域.资源.动作】三层语义结构拆分指标含义,层级清晰、可读性强。 - 不使用下划线、驼峰、横线 :严格禁止使用下划线
_、中横线-、驼峰大小写作为分隔,仅能依靠小数点做分层。
✅ 规范标准指标名:
db.mysql.queryhttp.client.durationjvm.memory.used
❌ 不符合规范写法:
db_mysql_query(下划线分隔)DbMysqlQuery(驼峰大写)db-mysql-query(横线分隔)
2.3 跨平台兼容
底层通过 NamingConvention 自动适配不同监控存储的命名语法,实现跨平台兼容。
标准指标名 http.server.requests 多平台自动转换示例:
Prometheus:不支持小数点,自动把.转为下划线,同时自动追加单位后缀_seconds,示例:http_server_requests_duration_seconds;Atlas:httpServerRequests驼峰命名风格,自动去除小数点并转为大驼峰,示例:httpServerRequests;Graphite:原生支持小数点分隔,直接复用原名称无转换,示例:http.server.requests;InfluxDB:原生兼容点分隔,原样输出,示例:http.server.requests。
如果默认转换规则不满足业务需求,可自定义 NamingConvention 全局替换,所有 Meter 统一生效:
java
// 全局自定义命名转换器
registry.config().namingConvention(new MyCustomNamingConvention());
3. 标签(Tag)
3.1 核心概念
标签 (Tag)是 Micrometer 指标体系中用于维度细分的键值对结构。
指标名用于定义「这是哪一类指标」,标签用于进一步拆分「该指标下不同场景、不同分支、不同资源的细分数据」。通过标签可以对同一指标做分组、筛选、聚合、告警拆分,是监控精细化、多维度统计的核心能力。
示例,定义统一指标名:http.server.requests(代表所有 HTTP 请求指标),搭配不同标签实现维度拆分:
- 标签
method=GET:单独统计GET请求的请求量、耗时、错误率; - 标签
status=500:单独统计服务端异常请求数据; - 标签
uri=/api/user/list:单独统计用户列表接口的监控数据。
如果没有标签,只能看到所有 HTTP 请求的笼统汇总数据,无法精准定位某个接口、某种请求方式的异常情况。
示例,通过不同标签拆分出多条独立时序数据:
java
http.server.requests{method="GET",uri="/api/user/list",status="200"} 2560
http.server.requests{method="POST",uri="/api/order/create",status="200"} 1350
http.server.requests{method="POST",uri="/api/order/create",status="500"} 28
可以精准区分:哪个接口、什么请求方式、成功/失败的请求量,是监控告警、问题排查的核心依据。
3.2 标签编写规范
标签的使用有严格的业务分层规范,核心原则:指标名承载大类业务语义,标签仅用于细分维度,严禁本末倒置。
3.2.1 ✅ 推荐规范写法
指标名语义清晰、归属明确,代表一类统一行为;标签作为细分维度,用来区分不同资源、不同接口、不同场景,聚合结果具备业务意义。
java
// 指标名:数据库调用(大类语义),标签细分具体数据库
registry.counter("database.calls", "db", "users");
// 指标名:HTTP请求(大类语义),标签细分具体接口路径
registry.counter("http.requests", "uri", "/api/users");
最终时序输出示例:
java
# 数据库调用指标,维度清晰
database_calls_total{db="users"} 8920
# HTTP 请求指标,维度清晰
http_requests_total{uri="/api/users"} 12680
优势:全局聚合精准、维度清晰、大盘统计和告警规则简洁稳定。
3.2.2 ❌ 禁止反模式
禁止使用极度通用、无业务区分度的指标名,完全依靠标签区分业务场景。该写法会导致指标聚合混乱、数据混杂,完全失去统计价值。
java
// 严重禁止!指标名过于笼统,数据库、HTTP、消息调用全部混杂在一起
// 聚合后的 calls 总量无任何业务意义,无法用于统计、告警、大盘展示
registry.counter("calls", "class", "database", "db", "users");
最终时序输出示例:
java
calls_total{class="database",db="users"} 8920
calls_total{class="http",uri="/api/users"} 12680
calls_total{class="mq",topic="order"} 5600
问题根源:指标名 calls 没有业务归属,所有类型调用都会聚合到同一个指标下,数据污染严重,无法区分各类业务的真实吞吐量与错误率。
3.3 全局公共标签
3.3.1 核心概念
全局公共标签(Common Tags)是 MeterRegistry 注册表级别的统一标签,项目中所有指标会自动携带该批标签,无需每个埋点重复添加。
核心用途:统一区分环境、机房、集群、服务实例,实现多环境、多实例监控数据隔离,适配统一监控平台。
3.3.2 两种配置方式
方式一:可变参数快速配置
java
registry.config().commonTags("stack", "prod", "region", "us-east-1");
方式二 :Tag 集合批量配置(可读性更强,适合多标签场景)
java
registry.config().commonTags(Arrays.asList(
Tag.of("stack", "prod"),
Tag.of("region", "us-east-1")
));
3.3.3 最佳实践
Spring Boot 最佳实践:
-
固定静态公共标签(环境、服务名):优先使用
application.yml配置文件统一声明,零代码侵入; -
动态运行标签(实例IP、端口、集群节点):通过
MeterRegistryCustomizer自定义Bean动态注入,适配容器化、云原生动态场景。
项目配置全局公共标签 stack=prod、region=us-east-1 后,所有指标会自动携带这两个维度,无需手动埋点添加,实现多环境数据隔离:
-
http.server.requests{method="GET",uri="/api/user/list",status="200",stack="prod",region="us-east-1"} 2560 -
database.calls{db="users",stack="prod",region="us-east-1"} 8960 -
http.requests{uri="/api/users",stack="prod",region="us-east-1"} 3210
优势:全量指标统一带上环境、机房标识,可快速筛选「生产环境」「指定机房」的全局监控数据,适配多集群统一监控大盘。
3.4 低基数标签
定义 :标签取值有限、固定、可枚举,不会无限新增,时序数量可控。
常见示例 :请求方式 GET/POST、响应状态码 200/400/500、环境 prod/test、接口模板路径、错误类型等。
核心价值:不会引发指标基数爆炸,监控时序数量稳定,适合聚合统计、可视化展示、阈值告警。
指标名 http.server.requests生成的时序为固定有限条数:
java
http.server.requests{method="GET",status="200"} 1280
http.server.requests{method="POST",status="200"} 960
http.server.requests{method="GET",status="500"} 6
无论请求多少次,标签组合永远只有几十种,时序数量可控、稳定。
3.5 高基数标签
定义:标签取值无限增长、动态不重复、持续新增,无固定枚举范围。每产生一条新值,就会生成一条全新时序数据。
高基数标签会瞬间生成海量独立时序,引发指标基数爆炸 ,直接导致时序库内存溢出、磁盘爆满、查询超时、监控平台瘫痪。高基数唯一标识数据,统一存放于链路追踪Trace 中,严禁写入Metrics 指标标签。
强制避坑规范:
- 标签值禁止为
null,空值统一收敛为固定枚举值; - 禁止使用用户输入参数、动态
URI、用户ID、订单ID、流水号、TraceId等高动态字段作为标签; - 动态异常路径、未知接口,统一归类为
NOT_FOUND、UNKNOWN等固定值,杜绝无限新增标签。
错误使用 userId 动态字段打标签示例:
java
http.server.requests{userId="10001"} 1
http.server.requests{userId="10002"} 1
http.server.requests{userId="10003"} 1
每来一个新用户,就新增一条全新时序。在线用户 10 万 = 瞬间新增 10 万条时序,直接压垮 Prometheus 监控服务。
高基数标签是指标埋点的高危禁区,必须严格规避,是线上监控雪崩的主要诱因之一。
4. 指标数值(Value)
定义:描述某一时刻监控对象业务状态的量化浮点数值,是 Metrics 承载业务信息的核心载体。
通用特性:
- 数据类型:标准为
double64位浮点数,支持整数、小数、NaN、+Inf、-Inf; - 语义绑定:数值含义由指标类型决定:
Gauge:瞬时快照值(内存、线程、CPU占用,可升可降);Counter:单调累计总量(请求数、异常数,只会递增);Histogram:区分bucket区间计数、sum总和、count总次数三类数值;
- 两种存在形态:
- 内存形态(
Micrometer/OTel):动态计算函数,不缓存固定数值; - 传输文本形态(
Prometheus格式):静态固化数字,写入报文后不再变更。
- 内存形态(
5. 时间戳(Timestamp)
定义:标记指标数值采集瞬间的毫秒级 Unix 时间戳 (UTC 1970-01-01起算 13 位整数),是构建时序曲线的唯一核心维度。
通用特性:
- 时序主键规则:
指标名称 + 标签集合 + timestamp三者唯一确定一条时序数据点; - 两大来源:应用端本地时钟生成、采集服务端拉取时刻时钟生成;
- 精度影响:时间戳粒度决定监控曲线的分辨能力,默认拉取模式下精度等于采集间隔。