Prometheus指标长期归档系统设计及Cortex/Thanos/Mimir替代方案咨询
问题解答
1. 是否需要为200种指标分别创建规则?
不需要逐个指标创建规则,利用标签匹配或命名规范就能批量处理所有同类型指标。
核心思路是给指标打上统一的类型标识:
- 要么在采集阶段(比如Telegraf配置里)给counter类指标添加
metric_type="counter"标签,gauge类添加metric_type="gauge"标签; - 要么遵循Prometheus风格的命名规则:counter指标以
_total/_count结尾,gauge指标无特殊后缀。
之后在汇总规则中通过标签或名称过滤,一次性匹配所有同类型指标,无需逐个编写规则。
2. 系统设计方案
核心架构:分层存储+定时汇总
把数据分成短期原始数据和长期汇总数据两层,分别存储并设置不同的保留策略:
步骤1:规范指标标识
在Telegraf采集时统一处理:
- 对于node exporter的指标,自带类型标识(比如
cpu_load_1m是gauge,node_network_receive_bytes_total是counter),直接复用; - 对于应用自有端点的指标,在Telegraf的
inputs.http配置中添加标签,比如:
[[inputs.http]] urls = ["http://app:8080/metrics"] tagexclude = ["url"] [inputs.http.tags] metric_type = "counter" # 针对销量类指标的采集实例
步骤2:InfluxDB侧设置保留策略
- 原始数据桶(bucket)设置保留策略为30天(足够排查短期问题即可);
- 汇总数据桶设置保留策略为3年(满足2年后查看需求)。
步骤3:编写定时汇总任务(InfluxDB Task)
利用InfluxDB的Task功能,每6小时执行一次汇总:
- Counter类指标:取6小时窗口内的最后一个样本值(即该时段结束时的累计值)
option task = {name: "6h-counter-summary", every: 6h} from(bucket: "raw_metrics") |> range(start: -6h) |> filter(fn: (r) => r._measurement == "app_metrics" and r.metric_type == "counter") |> last() |> set(key: "summary_window", value: "6h") |> to(bucket: "long_term_summary")
- Gauge类指标:取6小时窗口内的平均值
option task = {name: "6h-gauge-summary", every: 6h} from(bucket: "raw_metrics") |> range(start: -6h) |> filter(fn: (r) => r._measurement == "node_metrics" or r.metric_type == "gauge") |> mean() |> set(key: "summary_window", value: "6h") |> to(bucket: "long_term_summary")
步骤4:查询长期数据
直接从long_term_summary桶查询,比如查看某指标的每日汇总,可以将6小时的汇总数据再聚合:
from(bucket: "long_term_summary") |> range(start: -2y) |> filter(fn: (r) => r._field == "sales_total") |> aggregateWindow(every: 1d, fn: last) # counter的每日最终值
3. 改用Cortex/Thanos/Mimir是否会有同样难题?
不会,这些Prometheus生态的长期存储系统天生支持记录规则(Recording Rules),可以批量预计算汇总指标,反而更适合这类场景:
- 它们支持通过标签匹配批量生成汇总,比如一条规则匹配所有
job="vm"且__name__=~".*_total"的counter指标,计算其窗口最后值; - 可以通过**降采样(Downsampling)**功能自动生成不同粒度的汇总数据,同时支持设置原始数据的保留时间(比如原始数据存1个月,汇总数据存3年);
- 核心逻辑和InfluxDB一致:预计算汇总并长期存储,删除过期原始数据,避免不必要的负载。
关于rate函数的说明
你提到用rate函数汇总不正确是对的:rate是计算counter的速率(单位时间增量),而你需要的是counter的累计最终值,所以应该用last()(InfluxDB)或last_over_time()(PromQL)来获取时段结束时的累计值。如果后续需要计算某时段内的销量增量,只需用当前时段的last值减去上一时段的last值即可。
内容的提问来源于stack exchange,提问作者OmerFaruk
相关产品推荐
相关产品推荐

