InfluxDB作为一款面向时间序列数据的数据库,最常见的使用场景是监控指标的采集与存储。假设有100台服务器,每台每秒上报一次CPU使用率,一天就会产生超过800万个数据点,一个月下来原始数据轻松突破两亿。这些数据在最初几天价值最高,越往后价值越低,但占用的磁盘却一点不少。InfluxDB针对这个矛盾提供了两个原生机制:保留策略(Retention Policy,简称RP)负责自动删除过期数据,连续查询(Continuous Query,简称CQ)负责把原始数据聚合成低精度数据。两者配合起来,就能实现一套自动化的数据降采样与生命周期管理,无需外部定时任务介入。

保留策略的作用与配置方法
保留策略定义了数据在数据库中存活多久以及副本份数。每个数据库创建时会自带一个名为autogen的默认策略,它是无限期保留的。你可以为同一个库创建多个策略,数据写入时指定策略名,InfluxDB会独立管理每个策略下的数据,过期后由后台服务自动清理,完全不需要手动删除。
创建一个保留7天原始数据的策略,语法非常直观:
-- 创建保留策略,duration为保留时长,replication为副本数(单机版固定为1) CREATE RETENTION POLICY "rp_7d" ON "monitor" DURATION 7d REPLICATION 1 DEFAULT -- 查看库下已有的策略 SHOW RETENTION POLICIES ON "monitor"
注意最后的DEFAULT关键字,加上它之后,未显式指定策略的写入和查询都会落到rp_7d上。如果不想改动默认策略,去掉这个关键字即可。保留时长的最小值是1小时,如果填的duration低于1h会直接报错。另外,策略的duration一旦创建就不支持缩短(部分旧版本中修改受限),建议在建表初期就规划好,或者新建策略再用ALTER RETENTION POLICY调整。
查询特定策略下的数据时,需要用 Fully Qualified 语法,也就是在measurement前面带上策略名:
SELECT MEAN("value") FROM "monitor"."rp_7d"."cpu_usage" WHERE time > now() - 1h GROUP BY time(5m)
这个语法在后面配置连续查询时会大量出现,因为降采样数据的写入目标往往在另一个策略下,务必掌握。
连续查询的原理与创建语法
连续查询本质上是InfluxDB内置的定时聚合任务。它会按照设定的执行间隔,周期性地对原始数据执行SELECT ... GROUP BY time()聚合,并把结果写入指定的measurement。这样即使原始数据被保留策略删掉,聚合后的低精度数据依然存在,长期趋势图依然可以绘制。它的执行由服务端调度,不需要Crontab、不需要客户端常驻进程,这是它相比外部定时聚合脚本最大的优势。
下面是一个完整的降采样连续查询示例,把每秒采集的CPU数据聚合成5分钟均值,写入另一个策略下的新measurement:
CREATE CONTINUOUS QUERY "cq_cpu_5m" ON "monitor"
BEGIN
SELECT MEAN("value") AS "mean", MAX("value") AS "max", MIN("value") AS "min"
INTO "rp_30d"."cpu_usage_5m"
FROM "rp_7d"."cpu_usage"
GROUP BY time(5m), "host"
END
几个关键点需要理解。第一,INTO子句指定了目标为策略rp_30d下的cpu_usage_5m,实现了跨策略的数据流转。第二,GROUP BY time(5m)之后还跟了"host"标签,这保证了聚合结果按主机维度分开存储,如果漏掉tag,所有主机的数据会被混在一起算均值,结果完全失真,这是新手最容易犯的错误。第三,连续查询默认只处理最近一个执行周期内的数据,处理的是增量而非全量。
连续查询的执行频率由InfluxDB配置文件中的query-stats-enabled与CQ调度间隔共同决定,默认情况下对于GROUP BY time(5m)这类窗口,CQ每过一个窗口期执行一次。如果需要控制调度粒度,可以在配置文件的continuous_queries段设置run-interval。查看已创建的连续查询可以用SHOW CONTINUOUS QUERIES语句,删除则用DROP CONTINUOUS QUERY "cq_cpu_5m" ON "monitor"。
生产环境的多层降采样方案
一个经过实践检验的典型方案是三层结构:原始数据保留7天供排查近期问题,5分钟聚合数据保留30天供日常巡检,1小时聚合数据保留一年供年度容量规划。对应的策略与连续查询配置如下:
-- 第一步:创建三个保留策略
CREATE RETENTION POLICY "rp_7d" ON "monitor" DURATION 7d REPLICATION 1 DEFAULT
CREATE RETENTION POLICY "rp_30d" ON "monitor" DURATION 30d REPLICATION 1
CREATE RETENTION POLICY "rp_1y" ON "monitor" DURATION 365d REPLICATION 1
-- 第二步:5分钟降采样(7天原始 -> 30天)
CREATE CONTINUOUS QUERY "cq_cpu_5m" ON "monitor"
BEGIN
SELECT MEAN("value") AS "mean", MAX("value") AS "max"
INTO "rp_30d"."cpu_usage_5m"
FROM "rp_7d"."cpu_usage"
GROUP BY time(5m), "host"
END
-- 第三步:1小时降采样(5分钟聚合 -> 1年)
CREATE CONTINUOUS QUERY "cq_cpu_1h" ON "monitor"
BEGIN
SELECT MEAN("mean") AS "mean", MAX("max") AS "max"
INTO "rp_1y"."cpu_usage_1h"
FROM "rp_30d"."cpu_usage_5m"
GROUP BY time(1h), "host"
END
这个方案有个值得注意的细节:第三层聚合的输入是第二层的输出,即从rp_30d的聚合表继续汇总,而不是直接对原始数据做1小时聚合。这样做的好处是避免了两个连续查询同时扫描原始数据带来的重复IO开销。但要小心时间链路问题——第二层CQ还没跑完时第三层就去读,会漏数据,所以窗口粒度要拉开足够差距,一般相邻层级至少10倍以上比较安全。
应用查询时也要做相应适配:前端查最近几小时的图走原始精度,查一个月的图切到5分钟表,查一年的图切到1小时表。可以在应用层按时间范围自动路由,也可以借助Grafana的数据源变量来切换,具体取决于你的展示架构。
常见踩坑点与排查思路
第一类坑是聚合结果里出现大量空值。原因是连续查询的GROUP BY time()窗口内没有数据时不会产出点,配合fill()可以改变这个行为,例如GROUP BY time(5m) fill(0),但要注意fill(previous)在某些场景下会掩盖真实的数据断点,监控场景慎用。
第二类坑是写入时区偏差。CQ的调度基于UTC时间,如果你的业务窗口按本地时间对齐(比如按北京时间0点出日报),聚合窗口会出现错位。可以在连续查询中配合tz()子句处理,或者在应用层自行换算。
第三类坑是忘记在INTO子句中带上目标策略,导致聚合结果落到了默认策略下,很快就被默认策略的duration清理掉,表现为降采样表数据莫名消失。遇到降采样数据缺失时,优先用SHOW CONTINUOUS QUERIES确认查询定义,再检查目标策略的保留时长,最后看服务端日志中CQ的执行记录,基本都能定位到原因。
把保留策略理解为数据生命周期的终点管理,把连续查询理解为数据流转的搬运工,两者组合起来就是一套零依赖的自动降采样体系。对于中小规模监控场景,这套方案足够稳定可靠;当数据规模大到单机扛不住时,再考虑升级到集群方案或更换其他架构即可。