土法炼钢兴趣小组的算法知识备份

【可观测性工程】Metrics:Prometheus、VictoriaMetrics、Thanos、Mimir、M3

文章导航

分类入口
architectureobservability
标签入口
#prometheus#victoriametrics#thanos#mimir#m3db#promql#remote-write#tsdb#metrics#observability

目录

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    │  │                                    │
  └──────────┘  └──────────────────────────────────┘

关键组件:

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)

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(实验性),改进:

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 年创建,目标:

  1. 无限时间范围存储(对象存储)。
  2. 跨集群全局查询(多个 Prometheus 实例视为一体)。
  3. 高可用(多副本去重)。

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: true

4.5 Thanos 高可用拓扑

参见本文顶部 SVG 图(左侧)。关键点:


五、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: 200

HTTP Header 多租户路由:

# 发送指标时带上租户 ID
curl -H "X-Scope-OrgID: acme" \
  -X POST http://mimir:3100/api/v1/push \
  --data-binary @payload.snappy

5.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 年创建,核心卖点:

6.2 单体模式

# 启动单机 VictoriaMetrics
./victoria-metrics-prod \
  -storageDataPath=/var/lib/victoria-metrics \
  -retentionPeriod=12   \   # 12 个月
  -httpListenAddr=:8428 \
  -maxConcurrentInserts=16 \
  -insert.maxQueueDuration=1m

6.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: 100000

6.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 亿活跃时间序列。由三个子项目组成:

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: 3

M3DB 使用自研的 TSDB 引擎(m3tsz),支持 Gorilla 压缩(详见第七篇)。集群拓扑基于一致性哈希,支持在线扩容。


八、五者对比矩阵

8.1 技术特性对比

维度 Prometheus Thanos Mimir VictoriaMetrics M3DB
部署复杂度 ★(单进程) ★★★★(6+ 组件) ★★★★★(10+ 组件) ★(单进程)/ ★★★(集群) ★★★★★
水平扩展 Sidecar + 对象存储 ✓(原生集群) ✓(集群模式) ✓(分片)
多租户 ✗(无 HTTP 隔离) ✓(原生) ✓(前缀隔离)
长期存储 ✗(本地) ✓(对象存储) ✓(对象存储) ✓(本地/远端) ✓(本地分片)
写入延迟 最低 最低
查询延迟 最低(本地) 中(跨网络)
磁盘占用 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 期间遇到如下问题(基于公开技术博客整理):

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 工程落地清单


参考资料

  1. Prometheus 官方文档 — https://prometheus.io/docs/
  2. Thanos 官方文档 — https://thanos.io/tip/thanos/
  3. VictoriaMetrics 文档 — https://docs.victoriametrics.com/
  4. Grafana Mimir 文档 — https://grafana.com/docs/mimir/
  5. M3DB 文档 — https://m3db.io/docs/
  6. Björn Rabenstein, “Prometheus Storage” (PromCon 2017)
  7. Bartłomiej Płotka, “Thanos: Prometheus at Scale” (KubeCon EU 2019)
  8. 阿里云 PolarDB 团队, “从 Thanos 迁移到 VictoriaMetrics 的实践” (InfoQ 2023) — https://www.infoq.cn/
  9. Aliaksandr Valialkin, “How VictoriaMetrics makes writes faster” (VictoriaMetrics blog, 2022)
  10. Uber Engineering, “M3: Uber’s Open Source, Large-scale Metrics Platform for Prometheus” (2018) — https://www.uber.com/blog/
  11. Grafana Labs, “Cortex and Thanos: A technical comparison” (Grafana blog)
  12. Rob Skillington, “Introducing M3” (KubeCon NA 2018)

上一篇数据模型:时间序列、日志、Span、Profile 的内部表达

下一篇时序数据库内核:TSM、TSI、倒排索引与 Gorilla 压缩

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-04-22 · architecture / observability

【可观测性工程】时序数据库内核:TSM、TSI、倒排索引与 Gorilla 压缩

深入时序数据库的存储内核:Prometheus TSDB 的 WAL 与块管理、InfluxDB 的 TSM 引擎与 TSI 倒排索引、Gorilla 压缩算法的数学原理、VictoriaMetrics mergeset 架构、ClickHouse MergeTree 作为 metrics 后端,以及国内大厂在 series churn 和 compaction 风暴上踩过的坑。

2026-04-22 · architecture / observability

可观测性工程

从 Metrics、Logs、Traces 到 Profiling、eBPF、OpenTelemetry 与 SLO 治理,面向中国工程团队的可观测性系统化手册。


By .