InfluxDB作为一款流行的时序数据库,被广泛用于存储监控指标、传感器数据、埋点日志等场景。这类数据有一个共同特点:写入量极大,单条数据的价值却随时间快速衰减。比如CPU使用率,实时看需要秒级精度,回看三天前的走势只需要分钟级,一个月前的数据甚至只需要小时级就够了。如果所有历史数据都以最高精度保留,磁盘成本会变得难以承受,查询历史区间时扫描的数据量也会拖慢响应速度。降采样就是为了解决这个问题:按时间粒度对原始数据做聚合压缩,并配合保留策略定期清理过期的明细数据。本文围绕InfluxDB的downsampling展开,重点讲清楚连续查询和Retention Policy两个核心组件的配合方式。

为什么时序数据必须做降采样
先算一笔账。假设有200台服务器,每台采集CPU、内存、磁盘等20项指标,每10秒上报一次,那么每天的写入点数是200乘以20再乘以8640,超过3400万个点。按每个点平均占用几十字节估算,一天就是GB级别的存储量,一个月下来单机磁盘基本告急。而这些数据中,超过一周的部分在绝大多数业务场景下根本不会被以原始精度访问,属于典型的冷数据。
降采样的本质是用精度换空间。例如把10秒精度的数据聚合成1分钟精度的均值,数据量直接缩减为原来的六分之一,聚合为1小时精度则缩减到三千六百分之一。聚合后的数据保留了趋势信息,对回看历史曲线来说完全够用。同时降采样还能显著提升大时间跨度的查询性能,因为查询引擎需要扫描的点数少了几个数量级,Grafana面板的响应速度会明显改善。
需要澄清一个容易混淆的概念:降采样不等于删除数据。完整的方案是分层的,高精度原始数据保留较短时间比如7天,中等精度数据保留几个月,低精度数据保留几年。InfluxDB通过Retention Policy实现分层保留,通过Continuous Query实现自动聚合,两者组合起来才是一套完整的降采样策略,缺一不可。
连续查询CQ的原理与编写方法
连续查询是InfluxDB预先定义好的聚合查询,它会在后台自动周期性执行,把当前数据库中的数据聚合后写入另一张measurement或者另一个RP中。可以把CQ理解为数据库内部定时触发的INSERT INTO加SELECT聚合语句,相比外部cron任务,它由InfluxDB内部调度,开销更小,且天然感知分片的时间边界,不会因为任务与数据时间窗口错位而漏算数据。
下面是一个典型的CQ定义,把telegraf库中10秒精度的CPU数据聚合成30分钟粒度的均值,写入中等精度measurement:
CREATE CONTINUOUS QUERY "cq_cpu_30m" ON "telegraf"
BEGIN
SELECT mean("usage_idle") AS "usage_idle",
mean("usage_user") AS "usage_user"
INTO "telegraf"."rp_30m"."cpu_load_mid"
FROM "telegraf"."autogen"."cpu"
GROUP BY time(30m), "host"
END
这里有几个关键点需要理解。第一,GROUP BY time(30m)定义了聚合粒度,同时必须配合host这样的tag做分组,否则所有主机的数据会被混合成一个值,维度信息直接丢失。第二,INTO子句明确指定了目标RP为rp_30m,这样中等精度数据可以设置与原始数据不同的保留时长。第三,CQ默认按与查询分组相同的间隔周期执行,每次只处理当前时间窗口,不会重复计算历史区间。
如果采集端存在延迟写入,可以加上RESAMPLE子句让CQ更频繁地运行并回看更长的时间窗口,这样迟到的数据点也能被补算进去:
CREATE CONTINUOUS QUERY "cq_cpu_30m_resample" ON "telegraf"
RESAMPLE EVERY 10m FOR 1h
BEGIN
SELECT mean("usage_idle") AS "usage_idle"
INTO "cpu_load_mid"
FROM "cpu"
GROUP BY time(30m), "host"
END
管理CQ可以使用SHOW CONTINUOUS QUERIES查看当前所有定义,用DROP CONTINUOUS QUERY删除。建议给CQ命名时带上粒度后缀,比如30m、1h、6h,在多级降采样体系里一眼就能分清各自职责,后期排查问题也方便。
Retention Policy与多精度分层存储实战
Retention Policy决定了数据在库内的保留时长和副本数。InfluxDB每个database默认有一个名为autogen的RP,表示永久保留,这显然不适合生产环境。搭建降采样体系的第一步就是为不同精度分别创建RP,并把控制原始数据的RP设为默认:
-- 原始数据保留7天,设为默认RP CREATE RETENTION POLICY "rp_raw" ON "telegraf" DURATION 7d REPLICATION 1 DEFAULT; -- 30分钟聚合数据保留90天 CREATE RETENTION POLICY "rp_30m" ON "telegraf" DURATION 90d REPLICATION 1; -- 6小时聚合数据保留3年 CREATE RETENTION POLICY "rp_6h" ON "telegraf" DURATION 1044w REPLICATION 1;
创建三级RP之后,完整的降采样链路是:应用写入rp_raw保存原始数据,第一个CQ把数据从rp_raw聚合写入rp_30m,第二个CQ再从rp_30m聚合写入rp_6h。注意第二级聚合的数据源应该写成低精度RP而不是原始数据,这样聚合计算量会大幅降低,服务器负载也更平稳:
CREATE CONTINUOUS QUERY "cq_cpu_6h" ON "telegraf"
BEGIN
SELECT mean("usage_idle") AS "usage_idle"
INTO "telegraf"."rp_6h"."cpu_load_low"
FROM "telegraf"."rp_30m"."cpu_load_mid"
GROUP BY time(6h), "host"
END
查询时需要按时间跨度选择合适的RP:查最近几小时走原始数据保证精度,查最近一个月走rp_30m,查一年的趋势走rp_6h。可以在查询语句里显式指定RP,也可以在应用层或Grafana数据源中根据时间范围自动路由。另外要留意,RP的过期清理是后台定期执行的,数据到期后不会精确到秒地消失,通常有一定延迟,属于正常现象,不要误以为是配置失效。
常见陷阱与验证方法
实际部署中有几个高频踩坑点。最常见的是聚合函数选择不当:均值会抹平毛刺,如果监控场景需要发现瞬时峰值,应该在CQ里同时写入max和mean两个聚合结果,例如SELECT mean("value") AS "value_avg", max("value") AS "value_max",否则降采样之后告警所需的峰值信息就永久丢失了,这是无法事后补救的。
第二个坑是聚合粒度与采集间隔不匹配。如果原始数据30秒一个点,而CQ按7分钟的窗口聚合,窗口内点数分布不均会导致聚合曲线出现锯齿。建议聚合粒度取采集间隔的整数倍,并且不低于采集间隔的十倍。第三个坑是忘记写GROUP BY中的tag,聚合结果会把所有维度混成一个序列,可以用SHOW TAG KEYS先确认维度字段再写CQ。
验证降采样是否生效,先执行SHOW CONTINUOUS QUERIES确认CQ已创建,等待一个聚合周期后检查目标measurement是否有数据写入:
SELECT * FROM "telegraf"."rp_30m"."cpu_load_mid" WHERE time > now() - 2h LIMIT 10;
如果目标measurement始终为空,优先检查CQ中FROM子句的measurement名称和RP是否写对,再确认源数据的时间戳是否落在CQ的处理窗口内。对于InfluxDB 2.x用户,CQ和RP已被Task与Bucket机制替代,配置方式变成了Flux脚本,但分层保留加逐级聚合的思路完全一致。无论哪个版本,一套设计合理的降采样体系都能让时序数据库的存储成本和查询性能长期保持在健康水平。
InfluxDBdownsampling连续查询修改时间:2026-09-17 00:46:07