4. 数据处理与存储:时序数据库选型与降采样策略

监控数据落地,是系统健康里最实在的一环。数据存不好,前面采集得再漂亮也是白搭。今天咱们聊聊时序数据库的选型、数据清洗和降采样策略。这些事我踩过不少坑,希望能帮你少走弯路。

4.1 时序数据库选型:Prometheus vs InfluxDB

选型这事儿,说白了就是看你的场景。我个人习惯把时序数据库分成两类:一类是 Prometheus 这种“推拉结合”的,另一类是 InfluxDB 这种“纯写入”的。它们各有千秋,别盲目跟风。

特性 Prometheus InfluxDB
数据模型 指标名 + 标签(Label) 测量(Measurement)+ 标签(Tag)+ 字段(Field)
存储引擎 自研 TSDB,基于内存 + 磁盘 TSM(Time-Structured Merge Tree)
查询语言 PromQL(功能强大,但学习曲线陡) InfluxQL / Flux(类 SQL,上手快)
高可用 原生不支持,需 Thanos / Cortex 企业版支持集群,开源版单机
适用场景 容器监控、微服务、Kubernetes IoT、应用性能监控、自定义指标

我在项目中遇到过这样一个情况:团队一开始选了 InfluxDB,因为大家都会写 SQL。但后来业务上容器化,指标量暴增,InfluxDB 单机扛不住,查询也慢。最后不得不迁移到 Prometheus + Thanos。嗯,这里要注意:如果未来有容器化趋势,直接上 Prometheus 生态会更省心。

核心建议:

  • Prometheus:适合指标量中等(百万级)、查询模式固定、需要告警的场景。
  • InfluxDB:适合写入量大、查询灵活、需要长时间窗口聚合的场景。

4.2 数据清洗:别让脏数据毁了你的监控

数据清洗听起来简单,做起来全是坑。你想想看,采集端可能因为网络抖动、机器负载高、甚至代码 bug,吐出一些异常值。如果不处理,这些脏数据会污染你的聚合结果,甚至触发误告警。

我一般会在写入时序数据库之前,加一个清洗层。这个层可以是独立的服务,也可以是采集器自带的过滤逻辑。常见的清洗手段包括:

  • 去重:同一时间戳的重复数据,只保留最后一条。
  • 范围过滤:比如 CPU 使用率超过 100% 或小于 0,直接丢弃。
  • 空值填充:缺失的指标用前值填充或插值。
  • 格式标准化:统一时间戳格式、标签命名规范。

我曾经因为没做范围过滤,导致一个 CPU 指标偶尔出现 999% 的异常值,结果告警系统疯狂报警,运维同事半夜爬起来查问题,最后发现是采集器的一个整数溢出 bug。从那以后,我坚持在写入前做一次数据校验。

小技巧:在 Prometheus 中,可以用 relabel_configs 和 metric_relabel_configs 做简单的清洗。比如丢弃某些标签、重命名指标。但复杂的逻辑还是建议在采集端处理。

4.3 降采样策略:从海量数据中提炼价值

时序数据最大的特点就是“多”。一秒一个点,一天就是 86400 个点。存原始数据成本太高,查询也慢。降采样就是把这些数据“浓缩”一下,保留趋势,丢掉细节。

降采样不是简单粗暴地取平均值。我习惯按时间窗口分层:

  • 短窗口(1 分钟 ~ 1 小时):保留原始精度,用于实时监控。
  • 中窗口(1 小时 ~ 1 天):用平均值 + 最大值 + 最小值,保留波动范围。
  • 长窗口(1 天以上):用百分位数(P50、P95、P99)或聚合值,用于容量规划。

举个例子,假设你有一个 CPU 使用率指标,每秒采集一次。你可以这样设计降采样规则:

# 原始数据:1 秒一个点,保留 7 天
# 降采样到 5 分钟粒度:取平均值 + 最大值,保留 30 天
# 降采样到 1 小时粒度:取 P95 + P99,保留 1 年

# InfluxDB 的连续查询示例
CREATE CONTINUOUS QUERY "cq_cpu_5m" ON "mydb"
BEGIN
  SELECT mean("usage") AS "avg_usage", max("usage") AS "max_usage"
  INTO "cpu_5m"
  FROM "cpu"
  GROUP BY time(5m), *
END

在 Prometheus 生态里,降采样通常由 Thanos 或 VictoriaMetrics 的 downsampling 功能实现。我个人更推荐 VictoriaMetrics,它的降采样策略更灵活,而且支持自动调整。

注意:降采样会丢失细节。如果你需要回溯某个历史时刻的精确值,建议保留原始数据至少 7 天。另外,降采样后的数据不要覆盖原始数据,最好存到不同的 retention policy 或表中。

4.4 整体架构图

下面这张图展示了从数据采集到存储的完整流程,以及降采样在其中的位置。你可以看到,数据清洗在写入前完成,降采样则在写入后定期执行。

时序数据处理与存储架构 时序数据处理与存储架构 数据采集器 数据清洗层 时序数据库 降采样任务 回写聚合数据 存储分层策略 热数据(7天) 温数据(30天) 冷数据(1年) 原始精度 1s 降采样 5m avg+max 降采样 1h P95+P99

4.5 避坑指南

最后,分享几个我踩过的坑,希望能帮你省点时间:

  • 不要把所有指标都存原始精度:成本太高。按业务重要性分层,核心指标保留高精度,非核心指标直接降采样。
  • 降采样周期别太短:比如每 5 分钟降采样一次,会导致频繁的 I/O 和计算开销。我一般设置 1 小时或 1 天执行一次。
  • 注意时间戳对齐:降采样时,时间戳要对齐到窗口边界,否则查询时会出现“锯齿”效应。
  • 测试你的查询模式:选型前,先用真实数据跑一下查询性能。我曾经见过一个团队选了 InfluxDB,结果查询 P99 延迟超过 10 秒,最后不得不换方案。

一句话总结:时序数据库选型看场景,数据清洗要前置,降采样策略要分层。别贪心,也别偷懒,找到适合你业务的平衡点。