2. 监控体系架构:Pull vs Push模型、时间序列数据库原理、多维数据模型与标签设计
2.1 Pull vs Push 模型:架构选择与适用场景
Prometheus 采用 Pull(拉取) 模型作为核心数据采集方式,这与传统的 Push(推送)模型在架构设计、运维复杂度和故障隔离能力上存在本质差异。理解两者的区别是设计可靠监控体系的基础。
| 对比维度 | Pull 模型(Prometheus 默认) | Push 模型(传统方案) |
|---|---|---|
| 数据流向 | 监控系统主动连接目标端点拉取指标 | 被监控对象主动向中央收集器发送数据 |
| 故障检测 | 拉取超时或失败可立即判定目标不可达 | 数据缺失难以区分是故障还是延迟推送 |
| 配置复杂度 | 中心化配置,只需维护 targets 列表 | 每个被监控端需配置接收端地址和认证 |
| 网络要求 | 监控端需路由可达所有目标 | 被监控端需路由可达收集器 |
| 扩展性 | 通过服务发现自动扩缩,适合动态环境 | 需手动管理推送端,扩容时易遗漏 |
| 数据一致性 | 拉取时间由监控端控制,采样间隔稳定 | 推送时间由被监控端控制,可能突发拥塞 |
控制面场景建议: 控制面组件(如 kube-apiserver、etcd、kube-scheduler)均暴露 /metrics 端点,天然适配 Pull 模型。使用 Prometheus 的 kubernetes_sd_configs 自动发现所有控制面 Pod,无需在组件侧做任何推送配置。
Pull 模型并非万能。对于短生命周期任务(如 Job、CronJob)或位于防火墙后的遗留系统,Prometheus 提供了 Pushgateway 作为补充。Pushgateway 作为中间代理接收临时任务的推送数据,再由 Prometheus 从 Pushgateway 拉取。
Pushgateway 使用限制: Pushgateway 不是聚合器,也不是高可用存储。它仅用于无法直接 Pull 的场景。滥用 Pushgateway 会导致单点故障和指标延迟,控制面监控中应优先使用原生 Pull。
2.2 时间序列数据库原理:存储结构与写入路径
Prometheus 内置的 TSDB(时间序列数据库)是其高性能查询的核心。理解 TSDB 的存储原理,有助于在控制面高基数场景下进行调优。
2.2.1 核心概念
- Sample(样本): 时间序列中的单个数据点,由
timestamp(毫秒精度)和value(float64)组成。 - Series(序列): 由 Metric Name + Labels 唯一标识的一组有序样本。例如
http_requests_total{method="GET", endpoint="/api/v1"}是一个序列。 - Block(数据块): TSDB 将数据按时间窗口切分为不可变的 block,每个 block 包含该时间窗口内的所有样本数据。
2.2.2 写入路径与压缩机制
- WAL(Write-Ahead Log): 所有写入先追加到 WAL,保证崩溃恢复不丢数据。
- Head Block(内存块): 最近的数据暂存在内存中的 Head Block,支持快速查询最新数据。
- 压缩与持久化: 当 Head Block 达到阈值(默认 2 小时),TSDB 将其压缩为不可变的持久化 block,并写入磁盘。
- 合并(Compaction): 后台定期合并较小的 block 为更大的 block,减少文件数量,提升查询效率。
控制面调优要点: 控制面组件(特别是 kube-apiserver 和 etcd)会产生大量高基数序列(如每个 Pod 的请求指标)。建议监控
prometheus_tsdb_head_series 指标,若超过 1000 万,需考虑调整 --storage.tsdb.retention.time 或启用 --storage.tsdb.retention.size 限制。
2.3 多维数据模型与标签设计:从指标到黄金信号
Prometheus 的数据模型是 多维的。每个指标(Metric)可以附加任意数量的标签(Label),标签的键值对组合构成了不同的时间序列。这种设计使得查询可以沿任意维度进行聚合、过滤和分组。
2.3.1 指标命名规范
- 基础格式:
<namespace>_<subsystem>_<unit>[_<suffix>] - 示例:
kubelet_node_config_error、etcd_server_leader_changes_seen_total - 控制面常用命名空间:
kube_(Kubernetes 组件)、etcd_、apiserver_、scheduler_、controller_manager_
2.3.2 标签设计原则
| 原则 | 说明 | 控制面示例 |
|---|---|---|
| 可区分性 | 标签应能唯一标识一个监控对象 | instance="10.0.1.5:10250" |
| 可聚合性 | 标签值应支持按业务维度分组 | node="node-01"、zone="us-east-1" |
| 基数控制 | 避免标签值无限增长(如 Pod Name、User ID) | 使用 namespace 而非 pod 作为聚合标签 |
| 一致性 | 同一类资源使用相同的标签键 | 所有控制面组件统一使用 component 标签 |
高基数陷阱: 控制面中
kube_pod_info 或 kube_deployment_status_replicas 等指标如果附加了 uid 或 pod_ip 标签,会导致序列数量爆炸。在 Prometheus 配置中通过 metric_relabel_configs 丢弃不必要的标签,是控制面监控的必备操作。
2.3.3 标签在查询中的应用
多维模型使得 PromQL 可以灵活地沿标签进行切片和聚合:
# 查询所有控制面组件的内存使用量,按组件分组
sum(process_resident_memory_bytes{job=~"kube-.*"}) by (job)
# 查询 etcd 集群中每个节点的 leader 变更次数
etcd_server_leader_changes_seen_total{cluster="prod"}
# 计算 apiserver 请求错误率(按资源类型)
sum(rate(apiserver_request_total{code=~"5.."}[5m])) by (resource)
标签设计检查清单:
- 每个指标至少包含
job和instance标签。 - 控制面组件额外添加
component、cluster标签。 - 避免在标签值中使用随机字符串、UUID、Pod 全名。
- 使用
__meta_kubernetes_*标签进行服务发现时,只保留必要的标签。