Metrics:Prometheus、VictoriaMetrics、Thanos、Mimir、M3
度量指标(Metrics)是可观测性三大支柱里最”省钱”也最成熟的一支。一条时间序列每秒写入一个浮点数,存储成本远低于日志,查询聚合也比分布式追踪简单得多。但当你的业务从几十台服务器扩张到几千个微服务,Prometheus 单实例的瓶颈就开始暴露:两周数据留存上限、单机内存压力、跨集群查询不通。本文从 Prometheus 的内部架构讲起,逐层拆解各主流扩展方案的工程取舍。
一、Prometheus 架构与数据模型
1.1 整体架构
普罗米修斯(Prometheus)由 SoundCloud 工程师 Matt T. Proud 和 Julius Volz 于 2012 年开始设计,2016 年成为云原生计算基金会(CNCF)第二个孵化项目。其核心架构遵循”拉取(Pull)优于推送(Push)“的设计哲学。
┌──────────────────────────────────┐
│ Prometheus Server │
┌──────────┐ │ ┌──────────┐ ┌──────────────┐ │ ┌─────────────────┐
│ Target │◄─┼──│ Scrape │ │ TSDB │ │ │ Alertmanager │
│ /metrics │ │ │ Engine │─►│ WAL+Blocks │ │ │ (Alert Route) │
└──────────┘ │ └──────────┘ └──────┬───────┘ │ └─────────────────┘
┌──────────┐ │ ┌──────────┐ │ │
│ Target │◄─┼──│ SD │ │ │ ┌─────────────────┐
│ /metrics │ │ │ (K8s/ │ ┌──────▼───────┐ │ │ Grafana / │
└──────────┘ │ │ Consul) │ │ PromQL │◄─┼──│ HTTP API │
┌──────────┐ │ └──────────┘ │ Query Layer │ │ └─────────────────┘
│ Pushgate │──┼────────────────►└──────────────┘ │
│ way │ │ │
└──────────┘ └──────────────────────────────────┘
关键组件:
- Scrape Engine:按
scrape_interval(默认 15s)主动拉取目标的/metrics端点,解析 Exposition 格式文本或 OpenMetrics Protobuf。 - 服务发现(Service Discovery,SD):通过
kubernetes_sd_configs、consul_sd_configs等动态发现抓取目标,避免手工维护 IP 列表。 - TSDB:基于 WAL + 两小时内存块 + 本地磁盘块的混合存储,详见第七篇。
- Pushgateway:为短生命周期 Job(如 Cron 任务)提供临时推送端点;不适用于持久指标。
- Alertmanager:独立进程,接收 Prometheus 推送的告警,执行分组、抑制、路由、静默,再分发到 PagerDuty / 钉钉 / 飞书等渠道。
1.2 数据模型
普罗米修斯采用多维度时间序列(Multi-dimensional Time Series)模型。每条序列由指标名(metric name)与标签集(label set)唯一标识:
http_requests_total{method="GET", status="200", handler="/api/v1/user"}
四种指标类型:
| 类型 | 语义 | 场景 |
|---|---|---|
| Counter(计数器) | 单调递增,仅在重启时重置 | 请求总数、错误总数 |
| Gauge(仪表盘) | 可任意升降 | 内存使用量、队列长度 |
| Histogram(直方图) | 观测值分桶计数,附
_sum/_count |
请求延迟分布、请求大小 |
| Summary(摘要) | 客户端计算分位数(φ-quantile) | 与 Histogram 类似,但分位数在客户端固定 |
Exposition 格式示例:
# HELP http_request_duration_seconds HTTP request latency histogram
# TYPE http_request_duration_seconds histogram
http_request_duration_seconds_bucket{le="0.05"} 24054
http_request_duration_seconds_bucket{le="0.1"} 33444
http_request_duration_seconds_bucket{le="0.2"} 100392
http_request_duration_seconds_bucket{le="0.5"} 129389
http_request_duration_seconds_bucket{le="1.0"} 133988
http_request_duration_seconds_bucket{le="+Inf"} 144320
http_request_duration_seconds_sum 53423
http_request_duration_seconds_count 144320
1.3 WAL 与 TSDB 写入路径
数据写入流程:
Scrape → 内存追加器(Append)→ WAL(Write-Ahead Log)→ 内存 Head Block(~2h)
↓ flush
磁盘只读 Block(2h 窗口)
↓ compaction
合并 Block(6h / 24h / 1w)
- WAL:每次追加先写日志(mmap 文件),防止进程崩溃丢数据。WAL 段文件默认 128 MiB,超过则滚动。
- Head
Block:当前两小时的数据保存在内存,超过后刷为只读磁盘块(
chunks_head→block)。 - 压缩(Compaction):后台将小块合并为更大时间窗口的块,同时删除过期数据(
--storage.tsdb.retention.time)。
1.4 服务发现配置示例
Kubernetes Pod 服务发现:
scrape_configs:
- job_name: "kubernetes-pods"
kubernetes_sd_configs:
- role: pod
namespaces:
names: ["default", "production"]
relabel_configs:
# 只抓有注解 prometheus.io/scrape: "true" 的 Pod
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: "true"
# 动态 port
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_port]
action: replace
target_label: __address__
regex: (.+)
replacement: ${1}
# 保留 namespace、pod 名为标签
- source_labels: [__meta_kubernetes_namespace]
target_label: namespace
- source_labels: [__meta_kubernetes_pod_name]
target_label: pod国内 Nacos 服务发现(通过 Prometheus 社区扩展):
# 使用 prometheus-nacos-sd(第三方 sidecar)将 Nacos 实例列表转为 file_sd JSON
scrape_configs:
- job_name: "nacos-services"
file_sd_configs:
- files:
- /etc/prometheus/sd/nacos/*.json
refresh_interval: 30s
relabel_configs:
- source_labels: [__meta_nacos_service]
target_label: service
- source_labels: [__meta_nacos_cluster]
target_label: cluster二、Remote Write 协议
2.1 协议概述
远程写(Remote Write)是 Prometheus 将样本实时复制到外部存储的标准接口。协议使用 Protobuf + Snappy 压缩,经 HTTP POST 发送到远端接收器。
Prometheus --[remote_write]--> VictoriaMetrics / Thanos Receive / Mimir / M3
配置示例:
remote_write:
- url: "http://victoriametrics:8428/api/v1/write"
remote_timeout: 30s
queue_config:
capacity: 10000
max_shards: 50
min_shards: 1
max_samples_per_send: 5000
batch_send_deadline: 5s
min_backoff: 30ms
max_backoff: 5s
write_relabel_configs:
# 只转发生产命名空间的指标
- source_labels: [namespace]
action: keep
regex: "production|staging"2.2 Remote Write 2.0
Prometheus 2.54 引入 Remote Write 2.0(实验性),改进:
- 使用新 Protobuf 格式减少序列化开销。
- 支持元数据(
metadata)内联传输。 - 引入
created_timestamp字段,精准标记计数器重置。
2.3 背压(Back Pressure)机制
Remote Write 使用分片队列(sharded queue)缓冲待发送样本。当远端慢或宕机时:
样本写入内存队列
↓
队列满 → 丢样本(失败计数 prometheus_remote_storage_samples_failed_total++)
↓
监控队列深度:prometheus_remote_storage_queue_highest_sent_timestamp_seconds
关键监控指标:
# 检查队列积压(正常应 ≈ 0)
prometheus_remote_storage_pending_samples{job="prometheus"}
# 丢样本率(应为 0)
rate(prometheus_remote_storage_samples_failed_total[5m])
# 发送延迟
prometheus_remote_storage_highest_timestamp_in_seconds
- prometheus_remote_storage_queue_highest_sent_timestamp_seconds
三、PromQL 入门与进阶
3.1 基础查询
即时向量(Instant Vector)返回当前值:
# 所有 HTTP 请求的计数
http_requests_total
# 标签过滤
http_requests_total{status=~"5.."}
# 否定过滤
http_requests_total{environment!="dev"}
区间向量(Range Vector)返回时间窗口内的样本:
# 过去 5 分钟的样本
http_requests_total[5m]
3.2 速率函数
# 每秒请求速率(Counter 专用,处理 Reset)
rate(http_requests_total[5m])
# 瞬时变化(适合短窗口,但对 Counter Reset 不友好)
irate(http_requests_total[5m])
# increase:区间内增量(rate × interval 的近似)
increase(http_requests_total[1h])
rate vs irate
的选择:rate
对长窗口更平滑,适合告警;irate
对短尖刺更敏感,适合仪表盘。
3.3 Histogram 分位数
# p99 请求延迟(Histogram 要求 le 桶存在)
histogram_quantile(0.99,
sum by (le, service) (
rate(http_request_duration_seconds_bucket[5m])
)
)
# p50 / p95 / p99 并列
histogram_quantile(0.50, sum by (le) (rate(http_request_duration_seconds_bucket[5m])))
histogram_quantile(0.95, sum by (le) (rate(http_request_duration_seconds_bucket[5m])))
histogram_quantile(0.99, sum by (le) (rate(http_request_duration_seconds_bucket[5m])))
注意:跨序列 Histogram 相加后再调用
histogram_quantile
才有意义,不能先算分位数再相加。
3.4 Recording Rules
记录规则(Recording Rules)把开销大的查询预计算为新的指标序列,提升仪表盘性能:
groups:
- name: http_metrics
interval: 60s
rules:
# 每分钟预计算 p99 延迟,按 service 聚合
- record: job:http_request_duration_p99:rate5m
expr: |
histogram_quantile(0.99,
sum by (le, job) (
rate(http_request_duration_seconds_bucket[5m])
)
)
# 预计算 QPS
- record: job:http_requests:rate5m
expr: |
sum by (job, status) (
rate(http_requests_total[5m])
)
# 错误率(用于 SLO 计算)
- record: job:http_errors:ratio5m
expr: |
sum by (job) (rate(http_requests_total{status=~"5.."}[5m]))
/
sum by (job) (rate(http_requests_total[5m]))3.5 进阶:子查询与
label_replace
子查询(Subquery)对历史区间重算函数:
# 过去 1 小时内每分钟的 p99(用于趋势图)
histogram_quantile(0.99,
sum by (le) (
rate(http_request_duration_seconds_bucket[5m:1m])
)
)
label_replace 修改标签:
# 从 instance="10.0.1.5:8080" 提取 IP 部分
label_replace(
up,
"ip",
"$1",
"instance",
"([^:]+):.*"
)
3.6 告警规则示例
groups:
- name: slo_alerts
rules:
- alert: HighErrorRate
expr: |
job:http_errors:ratio5m > 0.01
for: 5m
labels:
severity: critical
team: backend
annotations:
summary: "服务 {{ $labels.job }} 错误率 {{ $value | humanizePercentage }}"
runbook: "https://wiki.example.com/runbooks/high-error-rate"
- alert: HighP99Latency
expr: |
job:http_request_duration_p99:rate5m > 0.5
for: 10m
labels:
severity: warning
annotations:
summary: "服务 {{ $labels.job }} P99 延迟超过 500ms"四、Thanos:Prometheus 的全球视图
4.1 设计目标
Thanos 由 Bartłomiej Płotka(Improbable,后来 Red Hat)等人于 2017 年创建,目标:
- 无限时间范围存储(对象存储)。
- 跨集群全局查询(多个 Prometheus 实例视为一体)。
- 高可用(多副本去重)。
4.2 核心组件
┌──────────────────────────────────────────────────────────────┐
│ Thanos 组件图 │
│ │
│ Prometheus──Sidecar──┐ │
│ Prometheus──Sidecar──┼──► Store Gateway ◄──► Object Store │
│ Prometheus──Sidecar──┘ │ │
│ │ │
│ Thanos Ruler ──────────────────┤ │
│ │ │
│ Thanos Receive ────────────────┤ │
│ (push 路径,支持 remote_write) │ │
│ ▼ │
│ Thanos Query ──── 全局 PromQL │
│ │ │
│ Query Frontend │
│ (缓存 + 分片查询) │
│ │ │
│ Grafana / API │
└──────────────────────────────────────────────────────────────┘
Sidecar(边车):与 Prometheus 同 Pod 运行,功能: - 将完成写入的 2h 块上传至对象存储(S3/GCS/阿里云 OSS)。 - 暴露 Store API,供 Thanos Query 访问当前未上传的新鲜数据。
Store Gateway(存储网关):从对象存储按需加载块索引,响应 Thanos Query 的查询请求。支持块缓存(In-memory / Redis)。
Compactor(合并器):对对象存储中的块执行合并与下采样(5m/1h 分辨率),节省长期存储。全局唯一,同时只能有一个实例运行。
Ruler(规则引擎):在全局视图上执行告警规则和记录规则,结果写回对象存储或 Alertmanager。
Thanos Receive:接受 Remote Write,充当 Prometheus 的替代采集入口(不需要 Sidecar)。
4.3 Sidecar 配置
# thanos-sidecar Deployment
args:
- sidecar
- --prometheus.url=http://localhost:9090
- --tsdb.path=/data/prometheus
- --objstore.config-file=/etc/thanos/objstore.yaml
- --shipper.upload-compacted
- --min-time=-3h # 不缓存超过 3h 的块(由 Store 负责)对象存储配置(阿里云 OSS):
type: OSS
config:
endpoint: "oss-cn-hangzhou.aliyuncs.com"
bucket: "company-thanos-metrics"
access_key_id: "${OSS_ACCESS_KEY}"
access_key_secret: "${OSS_SECRET}"4.4 Query Frontend 缓存
# query-frontend 配置 Redis 缓存
query_range:
results_cache:
cache:
redis:
addr: "redis:6379"
split_queries_by_interval: 24h # 将大查询切分为 24h 分片并行执行
max_retries: 5
align_queries_with_step: true4.5 Thanos 高可用拓扑
参见本文顶部 SVG 图(左侧)。关键点:
- Prometheus 双副本:每个集群部署两个
Prometheus,配置完全相同,抓取同一批目标。Thanos Query 通过
--store指向两个 Sidecar,自动在返回结果时去重(基于时间戳,不基于值)。 - 对象存储单一来源:两个 Sidecar
上传相同的块后,Compactor
合并时按副本标签(
replicalabel)去重。
五、Mimir:云原生多租户 Prometheus
5.1 Cortex → Mimir
Mimir 是 Grafana Labs 于 2022 年 3 月从 Cortex fork 并彻底重构的项目,宣称相比 Cortex “40× 内存,更简单的部署”。Cortex 是最早的多租户 Prometheus 扩展方案,也是 Thanos 的竞品,由 Weaveworks 发起。
5.2 架构
写路径:
Prometheus/Agent ──remote_write──► Distributor ──► Ingester (WAL) ──► Store Gateway
│ ↑ flush
└──────────────────────────► Object Store
查询路径:
Grafana ──► Query Frontend ──► Query Scheduler ──► Querier ──► Store Gateway
│ │
缓存(Memcached/Redis) Object Store
核心微服务:
| 组件 | 职责 |
|---|---|
| Distributor(分发器) | 接收 Remote Write,哈希路由至 Ingester,写三副本 |
| Ingester(摄取器) | 内存 WAL + 持久化,持有最近 ~2h 数据 |
| Store Gateway | 从对象存储读取历史块,带 chunk 缓存 |
| Querier | 合并 Ingester 和 Store Gateway 的结果 |
| Query Frontend | 查询缓存、分片、重试 |
| Compactor | 后台合并 + 下采样 |
| Alertmanager(内置) | 多租户告警路由 |
5.3 多租户隔离
# mimir.yaml 多租户配置
multitenancy_enabled: true
# 每个租户限制
limits:
# 租户 acme 的限制
acme:
ingestion_rate: 150000 # 每秒最大样本数
ingestion_burst_size: 300000
max_global_series_per_user: 5000000
max_fetched_chunks_per_query: 2000000
ruler_max_rules_per_rule_group: 200HTTP Header 多租户路由:
# 发送指标时带上租户 ID
curl -H "X-Scope-OrgID: acme" \
-X POST http://mimir:3100/api/v1/push \
--data-binary @payload.snappy5.4 Helm 部署(单体模式)
# values.yaml — mimir-distributed chart
mimir:
structuredConfig:
common:
storage:
backend: s3
s3:
bucket_name: mimir-metrics
endpoint: s3.cn-northwest-1.amazonaws.com.cn
access_key_id: ${AWS_ACCESS_KEY_ID}
secret_access_key: ${AWS_SECRET_ACCESS_KEY}
ingester:
ring:
replication_factor: 3
compactor:
data_dir: /data/compactor
store_gateway:
sharding_ring:
replication_factor: 3六、VictoriaMetrics:高性能替代方案
6.1 设计理念
VictoriaMetrics 由 Aliaksandr Valialkin 等人于 2018 年创建,核心卖点:
- 存储效率:比 Prometheus TSDB 节省 7× 磁盘空间。
- 写入性能:单机 100 万 samples/s 写入不成问题。
- 兼容性:完整支持 Prometheus Remote Write 协议和 MetricsQL(PromQL 超集)。
- 运维简单:单体模式只有一个二进制文件。
6.2 单体模式
# 启动单机 VictoriaMetrics
./victoria-metrics-prod \
-storageDataPath=/var/lib/victoria-metrics \
-retentionPeriod=12 \ # 12 个月
-httpListenAddr=:8428 \
-maxConcurrentInserts=16 \
-insert.maxQueueDuration=1m6.3 集群模式
集群由三个组件组成:
vminsert (写入层, 无状态)
↓ consistent hash
vmstorage (存储层, 有状态, 分片)
↑
vmselect (查询层, 无状态)
集群 Helm values:
# victoria-metrics-cluster values.yaml
vminsert:
replicaCount: 3
resources:
requests:
cpu: "2"
memory: "2Gi"
extraArgs:
maxLabelsPerTimeseries: "50"
replicationFactor: "2"
vmstorage:
replicaCount: 6
persistentVolume:
storageClass: "ssd"
size: 1Ti
resources:
requests:
cpu: "4"
memory: "16Gi"
vmselect:
replicaCount: 3
resources:
requests:
cpu: "2"
memory: "4Gi"
extraArgs:
dedup.minScrapeInterval: "15s" # 去重(当 replicationFactor > 1 时)6.4 VMAgent
VMAgent 是 VictoriaMetrics 的专用采集器,比 Prometheus 采集效率高 2-4×:
# vmagent ConfigMap
scrape_configs:
- job_name: "kubernetes-pods"
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: "true"
# 推送到集群 vminsert
remote_write:
- url: "http://vminsert:8480/insert/0/prometheus"
queue_config:
max_samples_per_send: 10000
capacity: 1000006.5 VMAlert(告警)
# vmalert 规则
groups:
- name: vm_alerts
rules:
- alert: VMStorageDiskUsageHigh
expr: |
vm_data_size_bytes{job="vmstorage"} /
vm_free_disk_space_bytes{job="vmstorage"} > 0.8
for: 10m
labels:
severity: warning
annotations:
summary: "vmstorage 磁盘使用率超过 80%"6.6 MetricsQL 特色函数
# 插值(VictoriaMetrics 独有,填补空洞)
interpolate(
rate(http_requests_total[5m])
)
# 滚动聚合(Rollup)
rollup(http_requests_total, "1h")
# 异常检测(实验性)
outliers_mad(
sum by (pod) (rate(container_cpu_usage_seconds_total[5m])),
4.0 # MAD 倍数
)
七、M3DB 简介
7.1 背景
M3 是 Uber 开源的分布式时序数据库,2018 年捐赠给 CNCF。在 Uber 峰值处理超过 500 亿活跃时间序列。由三个子项目组成:
- M3DB:存储层,支持多副本、分片、时间范围查询。
- M3Coordinator:Prometheus Remote Write 接收器,将数据路由至 M3DB。
- M3Query:PromQL 查询引擎。
- M3Aggregator:可选聚合层,实现实时下采样。
7.2 M3DB 架构特点
# m3dbnode 配置示意
db:
hostID:
resolver: "hostname"
namespace:
- name: metrics_0s_10s # 原始分辨率,保留 10 秒粒度,保留 2 天
resolution: 0
retention: 48h
- name: metrics_10s_2d # 10 秒分辨率,保留 2 天
resolution: 10s
retention: 48h
- name: metrics_1m_30d # 1 分钟分辨率,保留 30 天
resolution: 1m
retention: 720h
- name: metrics_10m_1y # 10 分钟分辨率,保留 1 年
resolution: 10m
retention: 8760h
replication:
factor: 3M3DB 使用自研的 TSDB 引擎(m3tsz),支持 Gorilla 压缩(详见第七篇)。集群拓扑基于一致性哈希,支持在线扩容。
八、五者对比矩阵
8.1 技术特性对比
| 维度 | Prometheus | Thanos | Mimir | VictoriaMetrics | M3DB |
|---|---|---|---|---|---|
| 部署复杂度 | ★(单进程) | ★★★★(6+ 组件) | ★★★★★(10+ 组件) | ★(单进程)/ ★★★(集群) | ★★★★★ |
| 水平扩展 | ✗ | Sidecar + 对象存储 | ✓(原生集群) | ✓(集群模式) | ✓(分片) |
| 多租户 | ✗ | ✗(无 HTTP 隔离) | ✓(原生) | ✓(前缀隔离) | ✓ |
| 长期存储 | ✗(本地) | ✓(对象存储) | ✓(对象存储) | ✓(本地/远端) | ✓(本地分片) |
| 写入延迟 | 最低 | 低 | 中 | 最低 | 中 |
| 查询延迟 | 最低(本地) | 中(跨网络) | 中 | 低 | 中 |
| 磁盘占用 | 1× | 1× + 对象存储 | 1× + 对象存储 | 0.1-0.2× | 0.3-0.5× |
| PromQL 兼容 | 原生 | 原生 | 原生 | MetricsQL(超集) | M3Query(近似) |
| 社区活跃度 | CNCF 毕业 | CNCF 孵化 | Grafana Labs | 独立 | CNCF 孵化 |
| 国内应用 | 极广 | 广 | 增长中 | 快速增长 | 较少 |
8.2 成本与规模适配
序列数量(活跃) 推荐方案
───────────────────────────────────────────────────────────
< 100 万 Prometheus 单机(默认选择)
100 万 - 500 万 Prometheus + Thanos(已有 K8s 集群)
或 VictoriaMetrics 单机
500 万 - 5000 万 VictoriaMetrics 集群
或 Thanos(已有团队经验)
> 5000 万 Mimir(需要多租户)
VictoriaMetrics 集群(高写入要求)
M3DB(Uber 量级,复杂度极高)
九、国内案例:VictoriaMetrics 替换 Prometheus 的迁移故事
9.1 背景
某互联网头部公司(云原生架构,多 K8s 集群,总活跃序列约 2 亿)在使用 Thanos 期间遇到如下问题(基于公开技术博客整理):
- Compactor 单点瓶颈:全局唯一 Compactor 在处理大量历史块时频繁 OOM,需人工重启。
- Store Gateway 内存:索引缓存配置不当导致每个 Store Gateway 实例占用 50 GiB 内存。
- 查询延迟抖动:跨三个数据中心的 Query 延迟 P99 超过 8 秒,影响告警响应速度。
9.2 迁移方案
阶段 0(并行写入):
Prometheus ──remote_write──► Thanos Receive(现有)
└──remote_write──► VictoriaMetrics 集群(新建,接受流量 10%)
阶段 1(灰度验证,2 周):
逐步将 remote_write 流量提升到 100%,用 vmselect 验证查询结果一致性
对比查询:
curl "http://vm:8481/select/0/prometheus/api/v1/query" \
--data 'query=job:http_requests:rate5m'
curl "http://thanos-query:9090/api/v1/query" \
--data 'query=job:http_requests:rate5m'
阶段 2(切流):
Grafana 数据源指向 vmselect
保留 Thanos 只读查询 30 天(历史数据迁移)
阶段 3(历史迁移):
使用 vmctl 工具从 Prometheus/Thanos 批量导入历史块:
vmctl prometheus --prom-snapshot /data/prometheus/snapshots/xxx \
--vm-addr http://vminsert:8480 \
--vm-concurrency 8 \
--concurrency 8
9.3 迁移效果
迁移后与 Thanos 期间相比(数据来自公开博客,非实测):
| 指标 | 迁移前(Thanos) | 迁移后(VictoriaMetrics) |
|---|---|---|
| 查询 P99 | 8s | 1.2s |
| 磁盘占用 | 42 TiB | 8 TiB |
| 运维组件数 | 7 个 | 3 个 |
| 月均告警人工干预 | 12 次 | 1 次 |
十、工程坑点
10.1 Remote Write 背压导致数据丢失
现象:监控图出现断点,prometheus_remote_storage_samples_failed_total
持续增加。
根因:远端接收器(VictoriaMetrics/Thanos
Receive)写入慢,Prometheus Remote Write
队列满后主动丢弃新样本(dropped 模式)。
解决方案:
remote_write:
- url: "http://vminsert:8480/insert/0/prometheus"
queue_config:
capacity: 50000 # 增大队列容量
max_shards: 100 # 增大并发分片
max_samples_per_send: 10000
batch_send_deadline: 10s
max_backoff: 30s # 放宽退避上限
# 启用 WAL 重放(Prometheus 2.42+ 默认开启)同时扩容接收端:vminsert 副本从 2 增至
6,vmstorage 磁盘 IOPS 升级。
10.2
label_replace 误用导致高基数爆炸
现象:某次上线后 Prometheus 内存从 8 GiB 暴涨至 32 GiB,active series 增加 1000 万。
根因:有人在
relabel_configs 中使用如下规则:
# 错误示例:把 URL path 完整写入标签
relabel_configs:
- source_labels: [__param_target]
target_label: url/param_target 包含完整 URL(含随机 query
string),导致每个唯一 URL 都成为新序列。
解决方案:
# 正确:只保留 path,截断 query string
relabel_configs:
- source_labels: [__param_target]
regex: "https?://[^/]+(/.*)\\?.*"
replacement: "$1"
target_label: url_path永远不要把高基数字段(用户 ID、trace ID、完整 URL)直接写入 Prometheus 标签。
10.3 Scrape Timeout 链式失败
现象:某个服务 500 台 Pod 的指标全部消失,但 Pod 本身正常运行。
根因:scrape_timeout 默认 10s,该服务
/metrics 端点需要遍历 Redis
统计数据,在业务高峰期响应时间超过 10s,触发 Prometheus 报错
context deadline exceeded,同时
up{job="xxx"} == 0
触发告警。但告警误导排查方向,以为是服务本身挂掉。
解决方案:
scrape_configs:
- job_name: "slow-service"
scrape_timeout: 30s # 针对慢 /metrics 单独调高
scrape_interval: 60s # 同时降低抓取频率
metrics_path: /metrics/fast # 提供精简版 metrics 端点(去掉慢查询)根本方案:优化 /metrics
端点,将耗时统计改为后台异步计算,暴露缓存值。
10.4 Thanos Compactor 单点 OOM
现象:Compactor 进程在合并大时间范围块时因内存不足被 OOM Killer 终止,导致历史块碎片化,查询变慢。
解决方案:
# 增大 Compactor 内存限制
# 同时开启分片(Thanos 0.29+)
thanos compact \
--objstore.config-file=/etc/thanos/objstore.yaml \
--data-dir=/data/compactor \
--consistency-delay=30m \
--compact.blocks-fetch-concurrency=1 \ # 限制并发取块
--wait \
--wait-interval=5m或切换到 VictoriaMetrics,其 compaction 在各 vmstorage 节点本地进行,无单点。
十一、选型建议与落地清单
11.1 选型决策树
Q1:你的活跃序列数量级?
< 100 万 → Prometheus 单机 + 本地磁盘(2 周)→ 结束
100 万 - 500 万 → Q2
> 500 万 → Q3
Q2:是否已有 Thanos 经验或团队熟悉 Go 生态?
是 → Prometheus + Thanos(对象存储打通)
否 → VictoriaMetrics 单机(最省运维)
Q3:是否有多租户需求(多业务线共享一套 Prometheus)?
是 → Mimir(原生多租户)或 VictoriaMetrics Cluster(前缀隔离)
否 → VictoriaMetrics Cluster
超大规模(> 10 亿序列 / Uber 量级)→ M3DB(慎重评估运维成本)
11.2 工程落地清单
参考资料
- Prometheus 官方文档 — https://prometheus.io/docs/
- Thanos 官方文档 — https://thanos.io/tip/thanos/
- VictoriaMetrics 文档 — https://docs.victoriametrics.com/
- Grafana Mimir 文档 — https://grafana.com/docs/mimir/
- M3DB 文档 — https://m3db.io/docs/
- Björn Rabenstein, “Prometheus Storage” (PromCon 2017)
- Bartłomiej Płotka, “Thanos: Prometheus at Scale” (KubeCon EU 2019)
- 阿里云 PolarDB 团队, “从 Thanos 迁移到 VictoriaMetrics 的实践” (InfoQ 2023) — https://www.infoq.cn/
- Aliaksandr Valialkin, “How VictoriaMetrics makes writes faster” (VictoriaMetrics blog, 2022)
- Uber Engineering, “M3: Uber’s Open Source, Large-scale Metrics Platform for Prometheus” (2018) — https://www.uber.com/blog/
- Grafana Labs, “Cortex and Thanos: A technical comparison” (Grafana blog)
- Rob Skillington, “Introducing M3” (KubeCon NA 2018)
上一篇:数据模型:时间序列、日志、Span、Profile 的内部表达
下一篇:时序数据库内核:TSM、TSI、倒排索引与 Gorilla 压缩
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【可观测性工程】时序数据库内核:TSM、TSI、倒排索引与 Gorilla 压缩
深入时序数据库的存储内核:Prometheus TSDB 的 WAL 与块管理、InfluxDB 的 TSM 引擎与 TSI 倒排索引、Gorilla 压缩算法的数学原理、VictoriaMetrics mergeset 架构、ClickHouse MergeTree 作为 metrics 后端,以及国内大厂在 series churn 和 compaction 风暴上踩过的坑。
【可观测性工程】可观测性全景:Metrics、Logs、Traces、Profiles、Events 五大支柱
从控制论到云原生:拆解可观测性的五大信号支柱,对比监控与可观测性的本质区别,梳理开源/商业/SaaS 分类,以及国内互联网公司三大支柱落地现状与典型工程坑点。
可观测性工程
从 Metrics、Logs、Traces 到 Profiling、eBPF、OpenTelemetry 与 SLO 治理,面向中国工程团队的可观测性系统化手册。
【可观测性工程】可观测性 vs 监控:从 Zabbix/Nagios 到 OpenTelemetry 的二十年
监控与可观测性不是新旧迭代,而是认知模型的根本转换。本文梳理从 1999 年 Nagios 到 2019 年 OpenTelemetry 的二十年演进时间线,对比 push/pull 模型、数据模型差异,以及国内从 Zabbix 到 Prometheus 再到 OTel 的典型迁移路径与工程坑点。