PHP创建的RRD数据库3天后数据截断、生成图表为空问题
问题根因
- RRD归档(RRA)定义存在核心缺陷:
- MIN类型归档缺失1小时粒度(60步)的1年存储项,更关键的是温度数据源
grad8查询时使用了LAST合并函数,但创建的所有RRA都只定义了AVERAGE、MIN、MAX三种合并类型,没有任何LAST类型的归档。RRD在查询时间范围小于最高精度归档(1分钟粒度,理论存储时长36小时/1.5天)的覆盖范围时,可以直接用原始采集点动态计算LAST值;当查询范围超出这个阈值,需要读取粗粒度归档数据计算时,找不到匹配的LAST类型归档就会返回空值。你遇到的3天截断是因为采集存在偶发延迟,最高精度的1分钟归档实际能覆盖的有效数据时长略长于理论值,到3天左右就完全没有可用的原始点支撑查询了。 - RRA定义顺序混乱:把MAX类型的1小时粗粒度归档插在了MIN类型的15分钟细粒度归档中间,部分版本的PHP RRD扩展会按定义顺序匹配归档写入,会导致粗粒度归档提前覆盖细粒度数据,加剧数据丢失。
- MIN类型归档缺失1小时粒度(60步)的1年存储项,更关键的是温度数据源
- 绘图代码存在笔误和参数缺失:
- 功率数据源定义的DEF变量名为
inoctets,但GPRINT统计值时错误引用了不存在的inbits变量,会导致功率的Last/Avg/Max统计值显示为NaN。 - 定义了不同时间跨度的
$graphs数组,但绘图参数里没有传入--start指定查询起始时间,仅指定结束时间为now,RRD默认查询范围是最近24小时,时间跨度大时会自动裁剪数据。
- 功率数据源定义的DEF变量名为
- 参数阈值设置不合理:DS心跳设置为300秒(5分钟),RRA的xff阈值设为0.5,只要采集延迟超过5分钟就会把原始点标记为unknown,且一个归档窗口内只要有一半数据是unknown,整个归档点就会被标记为unknown,很容易因为偶发的采集延迟导致粗粒度归档出现大量空洞,查询时无有效数据返回。
修复方案
- 重建RRD数据库,修正RRA定义,参考如下配置:
$opts = array( "--step", "60", "--start", "now-1d", // 允许导入过去1天的历史数据 "DS:wattmin:GAUGE:600:0:8000", // 心跳调整为600秒适配偶发延迟 // AVERAGE归档,xff调整为0.7降低空洞概率,按粒度从细到粗排序 "RRA:AVERAGE:0.7:1:2160", // 1分钟粒度存1.5天 "RRA:AVERAGE:0.7:5:2016", // 5分钟粒度存7天 "RRA:AVERAGE:0.7:15:2880",// 15分钟粒度存30天 "RRA:AVERAGE:0.7:60:8760",// 1小时粒度存1年 // MIN归档,补全1小时粒度项 "RRA:MIN:0.7:1:2160", "RRA:MIN:0.7:5:2016", "RRA:MIN:0.7:15:2880", "RRA:MIN:0.7:60:8760", // MAX归档,按粒度从细到粗排序 "RRA:MAX:0.7:1:2160", "RRA:MAX:0.7:5:2016", "RRA:MAX:0.7:15:2880", "RRA:MAX:0.7:60:8760", // 新增LAST归档,适配温度数据的LAST查询需求 "RRA:LAST:0.7:1:2160", "RRA:LAST:0.7:5:2016", "RRA:LAST:0.7:15:2880", "RRA:LAST:0.7:60:8760" ); $ret = rrd_create(RRD_DB_WP, $opts);
注意:存储温度的
RRD_DB_TEMPS库也要按照相同的RRA规则重建,否则温度曲线依然会出现3天空白的问题。如果需要保留上线至今的历史数据,可以用rrd_dump导出旧库的XML数据,修改RRA定义后再导入新库;上线时间较短的话直接重建即可。
- 修正绘图代码的错误,参考如下配置:
$graphs=array("-6h","-12h","-1d","-1w","-1m","-1y"); foreach($graphs as $graph){ $opts = array( "--start", $graph, // 显式传入查询起始时间 "-e now", "--vertical-label=°C", "-h 250", "DEF:inoctets=".RRD_DB_WP.":wattmin:AVERAGE", "AREA:inoctets#60B5E8:Watt/min", // 修正变量名为已定义的inoctets "GPRINT:inoctets:LAST:Las\: %4.0lfW", "GPRINT:inoctets:AVERAGE:Avg\: %4.0lfW", "GPRINT:inoctets:MAX:Max\: %4.0lfW\\n", "DEF:grad8=".RRD_DB_TEMPS.":grad8:LAST", "LINE2:grad8#F5A9A9:Wasser ", "GPRINT:grad8:LAST:Las\: %2.1lf°C", "GPRINT:grad8:AVERAGE:Avg\: %2.1lf°C", "GPRINT:grad8:MIN:Min\: %2.1lf°C", "GPRINT:grad8:MAX:Max\: %1.1lf°C\\n" ); $ret = rrd_graph(RRD_OUT_PATH. "/waermepumpe".ltrim($graph,'-').".gif", $opts); }
内容的提问来源于stack exchange,提问作者user1912399
相关产品推荐
相关产品推荐

