# 面试题:Metrics 的数据模型有了解吗? Metrics 是可观测性的三大支柱之一,它的核心是: > **用结构化的数值型数据,持续记录系统状态,用于告警、趋势分析、容量预测。** 业内的数据模型几乎都对齐 **OpenTelemetry(OTel)与 Prometheus** 标准。 面试官一般期待你回答: 1. Metrics 的三类模型是什么? 2. 为什么要这样设计? 3. Label、时间序列、Sample 是怎么构造的? 4. Counter / Gauge / Histogram / Summary 区别? 5. Push、Pull 模型以及存储结构? 下面完整拆解。 --- ## 一、Metrics 的数据模型是什么?(核心定义) OpenTelemetry + Prometheus 的 Metrics 数据模型由 3 个核心组成: 1. **Metric(指标)**:一类业务指标,例如 http_request_total 2. **Time Series(时间序列)**:一个 Metric + 一组标签 3. **Sample(样本点)**:某个时间点的数值 一句话: > **Metric + Labels → 一个 Time Series → 存储若干 Samples,他们一起构成完整的 Metrics 数据模型。** 示例: ``` Metric: http_requests_total Labels: method="GET", handler="/api/v1/order" 一个唯一时间序列: http_requests_total{method="GET", handler="/api/v1/order"} Sample: ( timestamp=1712148091000, value=342 ) ``` --- ## 二、Metrics 的三类基本类型(数据模型基础) 在 Prometheus / OpenTelemetry 中,所有 Metrics 可以归为四大类: ## 1)Counter(计数器) * 单调递增 * 只能增加不能减少 * 常用于统计次数、累计量 例子: * 总请求数 * 总错误数 * 总用户注册数 数据模型: ``` counter: name: http_requests_total value: 120392 ``` --- ## 2)Gauge(仪表盘) * 可增可减 * 表示某一时刻的状态 例子: * 当前 goroutine 数量 * 当前内存使用量 * Redis 连接数 数据模型: ``` gauge: name: cpu_usage value: 72.5 ``` --- ## 3)Histogram(直方图) 用于测分布的指标,如延迟、包大小等。 结构: * buckets(多个桶) * count(总数量) * sum(总和) 示例: ``` http_request_duration_seconds_bucket{le="0.1"} 1390 http_request_duration_seconds_bucket{le="0.3"} 2345 http_request_duration_seconds_sum 532.1 http_request_duration_seconds_count 2895 ``` Histogram 是最常用的延迟指标模型。 --- ## 4)Summary(分位数直方图) 用于客户端直接计算 p99/p95 的分布。 但: * 不可聚合(分布不能 merge) * 大规模生产推荐 Histogram + server-side quantile 数据模型: ``` summary: quantile=0.9 value=33ms quantile=0.99 value=70ms ``` --- ## 三、Metric → TimeSeries → Sample 的完整数据结构(深度) 下面是 Prometheus 的完整模型: --- ### 1. Metric 名称(Name) 表示指标类型: ``` http_requests_total go_goroutines process_cpu_seconds_total ``` 有命名规范(如 `_total`, `_count`, `_bucket` 等)。 --- ### 2. Labels(维度) Labels 是 Metrics 的“维度”,扩展时间序列。 例如: ``` method="GET" status="200" region="us-east-1" ``` 每一种 Label 组合会产生 **一个新的时间序列**。 例如: ``` http_requests_total{method="GET", status="200"} → 一条 TimeSeries http_requests_total{method="POST", status="500"} → 另一条 TimeSeries ``` **标签爆炸问题(cardinality explosion)**是 Metrics 最大的陷阱。 --- ### 3. Time Series(时间序列) 定义为: ``` MetricName + LabelSet ``` 例如: ``` http_requests_total{method="GET", status="200"} ``` 这是一条“唯一的时间序列”。 --- ### 4. Sample(样本点) 一个时间点的测量数据。 结构: ``` timestamp(int64) value(float64) ``` Prometheus 存储的就是所有 TimeSeries 的 Sample。 --- ## 四、为什么 Metrics 要设计成这种模型? 面试加分点:设计哲学。 ### 1)高压缩比、高性能存储 Time Series 数据可高度压缩: * 单条 Series 只有两列(timestamp, value) * 存储引擎(TSDB)压缩率极高 ### 2)天然聚合能力(PromQL) 聚合维度可自由组合: ``` sum by (method) (http_requests_total) avg(rate(http_request_duration_seconds[5m])) ``` ### 3)分布式不可变性 Sample 是不可变的 append-only data: 不需要更新,只需要 append。 --- ## 五、Push vs Pull 数据模型(架构差异) ### Prometheus = Pull 模型 Prometheus 主动拉取: ``` /metrics ``` 优点:统一发现、自动采集、减少压力。 ### OpenTelemetry = Push 模型(OTLP) Agent/SDK 将 Metrics 主动 push 到 Collector。 云原生下常用架构: ``` App → OTEL SDK → Collector → Prometheus/Tempo/Grafana Cloud ``` --- ## 六、Metrics 的落地标准(OpenMetrics) 未来标准: **OpenMetrics(基于 Prometheus,但更通用)** 被 CNCF 广泛支持。 数据模型: ``` ## TYPE http_requests_total counter http_requests_total{method="GET"} 1234 1712148091000 ``` --- ## 七、面试可背总结 > “Metrics 的数据模型由三个核心概念组成: > **Metric(指标定义)、TimeSeries(指标+标签的唯一组合)、Sample(某个时间点的值)。** > > 常用类型有四种: > > * Counter:递增,用于累计值。 > * Gauge:可增可减,用于当前状态。 > * Histogram:用于延迟、大小等的分布统计,包含 buckets、count、sum。 > * Summary:客户端计算分位数,但不便聚合。 > > Metrics 使用标签(Label)扩展时间序列,使得 promQL 可以从多维度聚合。 > 数据通常以 append-only 的方式写入 TSDB,具有高压缩、高性能和强聚合能力。 > 采集模型有 Pull(Prometheus)和 Push(OpenTelemetry)。 > 这是现代可观测性体系的基础。”