简介:RRDTool 1.4.7 是一款开源的环形时序数据库工具,面向网络运维、系统监控与性能分析人员,用于采集、存储并可视化网络流量、CPU、内存等随时间变化的指标数据,是 Smokeping、Cacti、MRTG 等监控系统的底层组件。本资源为 1.4.7 稳定版源码包,共 314 个文件,约 1.29MB,以 C 源码与头文件为核心实现,辅以 pod、html、txt 等文档说明,以及 configure、Makefile.am、m4 等构建脚本和少量 Perl、Python、Lua 辅助文件,便于自行编译与二次开发。已有 264 人学习下载。包内包含 rrdcreate、rrdcached、rrdgraph 等命令手册与入门教程,读者可据此掌握环形数据库结构、Heartbeat 更新机制、数据压缩存储与折线图、饼图等图形化展示方法,并借助命令行接口与 API 将 RRDTool 集成到自有监控流程中,为运维决策与故障排查提供可靠的数据支撑。
1. rrdtool-1.4.7.tar.gz 到底解决什么问题:从监控曲线到时间序列归档
机房值班最怕什么?不是服务器宕机,而是宕机之后你翻遍监控系统,发现过去 24 小时的 CPU 曲线是断的。很多老运维都遇到过这种场景:一套跑了七八年的监控系统,底层用的还是 rrdtool-1.4.7.tar.gz 这个源码包编译出来的二进制,磁盘上的 .rrd 文件突然不更新了,前端页面一片空白。这时候你需要的不是重装系统,而是搞清楚这个归档工具到底怎么工作、怎么编译、怎么排错。
rrdtool 全称 Round Robin Database Tool,核心解决的是「固定大小存储 + 自动降采样」的时间序列归档问题。它不像 MySQL 那样无限增长,一个 .rrd 文件创建时就定死了大小,数据写满一圈就覆盖最老的记录。这个设计在 1.4.7 这个版本上已经非常成熟,很多工业监控、网络流量采集、温湿度记录场景至今还在用。适合谁读?如果你手头有老监控系统要维护、要迁移,或者想用最小依赖搭一套长期运行的曲线记录服务,这个源码包值得花时间吃透。接下来我会按「编译 → 建库 → 写数据 → 画图 → 排错」的顺序,把能复现的步骤和参数一次讲清。
2. 从源码包到可执行文件:rrdtool-1.4.7 的编译链路与依赖取舍
拿到 rrdtool-1.4.7.tar.gz 之后,第一件事不是急着 ./configure,而是先看清楚它依赖什么、哪些能省、哪些不能省。这个版本的编译系统还是经典的 autotools 流程,但依赖库的版本组合比较讲究,尤其是 cairo 和 libxml2 这两个,版本不对会直接导致 configure 报错或者编译到一半链接失败。
2.1 依赖库清单与最小化选择
rrdtool 1.4.7 的核心依赖分三档:必需、绘图可选、语言绑定可选。我一般会先装必需项,跑通基础功能后再按需补绘图库。
| 依赖库 | 作用 | 是否必需 | 常见版本要求 |
|---|---|---|---|
| zlib | 压缩 .rrd 文件内部数据块 | 必需 | 1.2.x 以上 |
| libpng | 输出 PNG 曲线图 | 绘图必需 | 1.2.x / 1.6.x |
| freetype | 图表字体渲染 | 绘图必需 | 2.x |
| cairo | 矢量绘图后端 | 1.4.7 绘图必需 | 1.8 以上,建议 1.10+ |
| libxml2 | 解析 XML 格式的配置和输出 | 可选 | 2.6 以上 |
| pango | 复杂文本布局 | 绘图可选 | 1.20 以上 |
| perl | 生成 Perl 绑定 | 可选 | 5.8 以上 |
| python | 生成 Python 绑定 | 可选 | 2.6 / 2.7 |
如果你的场景只是写数据和取数据,不画图,那 libpng、freetype、cairo、pango 全都可以不装,configure 时加--disable-png就能跳过。但实际运维里不可能不画图,所以我的建议是:cairo 至少 1.10,libpng 至少 1.6,freetype 至少 2.4,这三个版本组合在 1.4.7 上最稳。
2.2 编译参数逐项说明与实操命令
下面这套命令是我在 CentOS 7 和 Ubuntu 18.04 上都验证过的流程,依赖用系统包管理器装,rrdtool 自己编译。
# 安装基础编译工具和依赖库 # CentOS 系: yum install -y gcc make libpng-devel freetype-devel cairo-devel pango-devel libxml2-devel zlib-devel # Ubuntu/Debian 系: apt-get install -y build-essential libpng-dev libfreetype6-dev libcairo2-dev libpango1.0-dev libxml2-dev zlib1g-dev # 解压源码包 tar -zxvf rrdtool-1.4.7.tar.gz cd rrdtool-1.4.7 # 配置编译选项 ./configure \ --prefix=/usr/local/rrdtool \ --disable-tcl \ --disable-ruby \ --disable-lua \ --with-python=/usr/bin/python2.7 # 编译并安装 make -j4 make install逐项解释一下关键参数。--prefix=/usr/local/rrdtool把安装目录独立出来,避免和系统自带的旧版本冲突,后面配环境变量也干净。--disable-tcl、--disable-ruby、--disable-lua这三个绑定一般用不上,关掉能省不少编译时间,也避免因为缺少对应解释器头文件而报错。--with-python指定 Python 2.7 的路径,因为 1.4.7 的 Python 绑定还不支持 Python 3,如果系统默认 python 指向 python3,这里必须显式指定 python2.7 的绝对路径,否则 configure 会跳过绑定生成。
编译完成后,把/usr/local/rrdtool/bin加到 PATH 里,执行rrdtool --version应该能看到 1.4.7 的版本号。如果报error while loading shared libraries: librrd.so.4,说明动态库路径没配,在/etc/ld.so.conf.d/下新建一个rrdtool.conf,写入/usr/local/rrdtool/lib,然后跑ldconfig即可。
2.3 编译期常见报错的定位思路
configure 阶段最常见的报错是checking for cairo... no,这通常不是 cairo 没装,而是 pkg-config 找不到 cairo.pc 文件。解决方法是确认pkg-config --modversion cairo能输出版本号,如果不行就设置PKG_CONFIG_PATH=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig再重新 configure。
另一个高频问题是undefined reference to 'png_set_longjmp_fn',这是 libpng 1.6 和旧版 rrdtool 代码之间的兼容性问题。1.4.7 的源码里对 libpng 1.6 的支持不完整,解决办法是在 configure 时加CFLAGS="-DPNG_SKIP_SETJMP_CHECK",或者降级到 libpng 1.5。我一般选前者,因为降级 libpng 可能影响系统其他组件。
提示:编译前先跑一遍
./configure --help,确认当前源码包支持哪些开关,不同打包方式(比如某些发行版重新打包过的 tar.gz)可能裁剪了部分选项。
3. 建库与写数据:rrdtool create/update 的参数怎么定才不翻车
编译装好只是第一步,真正决定监控曲线能不能长期稳定运行的,是建库时那几个核心参数。很多「曲线断档」「数据点丢失」的玄学问题,根源都在 create 阶段没算清楚。
3.1 RRA 与 heartbeat:两个最容易设错的参数
rrdtool 的存储结构叫 RRA(Round Robin Archive),一个 .rrd 文件里可以定义多个 RRA,每个 RRA 有自己的精度和保留时长。建库命令里最关键的三个参数是--step、heartbeat和 RRA 行里的rows。
--step是基础采集间隔,单位秒。比如你每 5 分钟采集一次,就设--step 300。heartbeat是单个数据点允许的最大间隔,超过这个时间没收到新数据,该点就被标记为 Unknown。我一般把 heartbeat 设成 step 的 2 倍,比如 step=300 时 heartbeat=600,这样偶尔一次采集延迟不会导致断点。
RRA 行里的rows决定保留多少个数据点。比如RRA:AVERAGE:0.5:1:288表示:用 AVERAGE 聚合,0.5 是 xff(允许未知数据占比),1 表示每 1 个基础点存一个归档点,288 表示保留 288 个点。step=300 时,288 个点正好是 24 小时。
下面是一个典型的建库命令,采集间隔 5 分钟,保留 1 天原始精度、7 天 5 分钟精度、30 天小时精度、1 年天精度:
rrdtool create /data/rrd/server_cpu.rrd \ --step 300 \ DS:cpu_user:GAUGE:600:0:100 \ DS:cpu_sys:GAUGE:600:0:100 \ DS:cpu_idle:GAUGE:600:0:100 \ RRA:AVERAGE:0.5:1:288 \ RRA:AVERAGE:0.5:12:2016 \ RRA:AVERAGE:0.5:12:8760 \ RRA:AVERAGE:0.5:288:365DS 行定义数据源。GAUGE表示直接读取的数值,适合 CPU 百分比、温度、内存用量这类瞬时值;如果是网卡流量这种累计计数器,要用COUNTER或DERIVE,rrdtool 会自动算差值。600是 heartbeat,0:100是允许的最小值和最大值,超出范围的点会被丢弃并记为 Unknown。
RRA 的第二个字段0.5是 xff(xfiles factor),意思是聚合时如果超过 50% 的原始点是 Unknown,这个聚合点也记为 Unknown。这个值设太小会导致曲线频繁断点,设太大又会把异常掩盖掉,0.5 是通用场景下的平衡点。
3.2 update 写入与批量补数据的正确姿势
写数据用rrdtool update,格式是时间戳:值1:值2:值3。时间戳必须是 Unix 时间戳,不能用日期字符串。如果某个值暂时拿不到,用U占位。
# 单条写入,时间戳用 date +%s 生成 rrdtool update /data/rrd/server_cpu.rrd $(date +%s):23:15:62 # 批量补数据,从文本文件读取 # 文件格式每行:时间戳:值1:值2:值3 rrdtool update /data/rrd/server_cpu.rrd --template cpu_user:cpu_sys:cpu_idle \ $(cat /tmp/cpu_backfill.txt | tr '\n' ' ')批量补数据时有个坑:--template指定的 DS 顺序必须和 update 命令里值的顺序一致,否则会把值写到错误的 DS 上。另外,rrdtool 对时间戳有要求,不能写入比当前最新数据点更早的时间戳(除非用--skip-past-updates参数,但 1.4.7 对乱序写入的支持有限),所以补数据要从老到新按时间顺序写。
如果写入时报illegal attempt to update using time xxx when last update time is xxx,说明时间戳比库里最新记录还早,这时候要么调整数据顺序,要么接受这部分数据写不进去。我一般会在补数据前先rrdtool last看一下库里最新时间戳,确保补的数据都比它大。
3.3 用 fetch 验证数据是否真的写进去了
写完数据别急着画图,先用rrdtool fetch确认数据落盘了。fetch 的语法是rrdtool fetch 文件 CF 起始时间 结束时间,CF 可以是 AVERAGE、MAX、MIN、LAST。
# 查看最近 1 小时的平均值数据 rrdtool fetch /data/rrd/server_cpu.rrd AVERAGE -1h now # 输出示例: # cpu_user cpu_sys cpu_idle # 1700000000: 2.300000e+01 1.500000e+01 6.200000e+01 # 1700000300: 2.100000e+01 1.400000e+01 6.500000e+01如果输出全是nan,说明对应时间段没有有效数据,要么是没写入,要么是写入的值超出了 DS 定义的范围被丢弃了。这时候回头检查 DS 的 min/max 设置,以及写入的值是否在范围内。
4. 画图与导出:rrdtool graph 的常用参数和输出格式选择
数据写进去之后,最终要落到「能看」上。rrdtool graph 是这个工具最强大的部分,也是最容易因为参数顺序写错而翻车的地方。
4.1 graph 命令的最小可用模板
一个能跑的 graph 命令至少包含:输出文件、时间范围、至少一个 DEF 和一条 LINE/AREA。下面是最小模板:
rrdtool graph /data/www/cpu_1h.png \ --start -1h \ --end now \ --width 800 \ --height 300 \ --title "CPU Usage - Last 1 Hour" \ --vertical-label "Percent" \ DEF:user=/data/rrd/server_cpu.rrd:cpu_user:AVERAGE \ DEF:sys=/data/rrd/server_cpu.rrd:cpu_sys:AVERAGE \ AREA:user#00FF00:"User CPU" \ LINE1:sys#0000FF:"System CPU"DEF 行把 .rrd 文件里的 DS 映射成一个变量,格式是DEF:变量名=文件:DS名:CF。AREA 画填充区域,LINE1 画 1 像素宽的线。颜色用 #RRGGBB 格式。--start和--end支持相对时间(-1h、-1d、-1w)和绝对时间戳。
4.2 时间范围与数据聚合的对应关系
graph 的时间范围决定了 rrdtool 从哪个 RRA 取数据。如果你建库时只保留了 1 天原始精度和 7 天 5 分钟精度,那画 30 天的图时,rrdtool 会自动从 5 分钟精度的 RRA 里取数据再聚合。如果对应的 RRA 不存在,图就会断档或者报found no matching RRA。
我一般会按「画图范围不超过最长 RRA 覆盖时长」的原则来建库。比如要画 1 年图,就必须有一个覆盖 1 年以上的 RRA,否则画出来的图后半段全是空白。
4.3 导出 CSV 做二次分析
除了画 PNG,rrdtool 还能导出 XML 和 CSV。导出 CSV 用rrdtool xport,适合把数据喂给其他分析工具。
rrdtool xport \ --start -1d \ --end now \ --step 300 \ DEF:user=/data/rrd/server_cpu.rrd:cpu_user:AVERAGE \ XPORT:user:"User CPU" \ > /tmp/cpu_export.xmlxport 输出的是 XML 格式,里面包含时间戳和对应的值。如果要纯 CSV,可以用rrdtool fetch配合 awk 转换,或者用rrdtool dump导出整个库的 XML 再解析。rrdtool dump会把 .rrd 文件的所有 RRA 内容展开成 XML,文件会很大,但适合做完整备份或迁移。
5. 避坑与排查:rrdtool-1.4.7 运维中最容易踩的五个坑
这一章记录的是我在实际维护中反复遇到的五个问题,每个都按「现象 → 原因 → 解决」写清楚。
5.1 曲线突然断档,fetch 显示大量 nan
现象:监控页面过去几小时曲线空白,rrdtool fetch输出大量nan。
原因:最常见的是采集脚本挂了或者写入频率低于 heartbeat。比如 step=300、heartbeat=600,但采集脚本因为网络超时每 15 分钟才写一次,超过 600 秒的点全被标记为 Unknown。
解决:先检查采集脚本的日志和 crontab 执行记录,确认写入频率。如果确实是采集间隔不稳定,把 heartbeat 调大,比如设成 step 的 3 倍。但注意 heartbeat 太大会让异常检测变迟钝,一般不超过 step 的 4 倍。
5.2 update 报错 illegal attempt to update using time
现象:补数据时 rrdtool 报illegal attempt to update using time xxx when last update time is xxx (minimum one second step)。
原因:写入的时间戳比库里最新记录还早,rrdtool 默认不允许乱序写入。
解决:用rrdtool last 文件查看最新时间戳,确保补的数据时间戳都大于它。如果必须写入历史数据,可以考虑用rrdtool dump导出 XML,手动修改后rrdtool restore回去,但操作前务必备份原文件。
5.3 画图报错 found no matching RRA
现象:rrdtool graph报found no matching RRA,图出不来。
原因:请求的时间范围和 step 组合在现有 RRA 里找不到匹配项。比如建库时只有 step=300 的 RRA,但 graph 时指定了--step 60,就会找不到。
解决:去掉 graph 命令里的--step参数,让 rrdtool 自动选择最合适的 RRA。或者在建库时就规划好不同精度的 RRA,覆盖常用的画图范围。
5.4 编译时 cairo 版本不兼容导致链接失败
现象:make 阶段报undefined reference to 'cairo_xxx',但 cairo 明明已经装了。
原因:系统里存在多个 cairo 版本,configure 找到的头文件和链接时用的库版本不一致。
解决:用pkg-config --cflags --libs cairo确认实际使用的版本和路径,然后在 configure 时显式指定CAIRO_CFLAGS和CAIRO_LIBS。如果系统 cairo 太老,考虑从源码编译一个独立版本的 cairo 装到 /usr/local 下。
5.5 .rrd 文件体积异常增大
现象:单个 .rrd 文件从几百 KB 涨到几十 MB。
原因:建库时 RRA 的 rows 设得太大,或者 DS 数量过多。rrdtool 文件大小是固定的,但建库时如果 rows 乘积过大,文件初始就很大。
解决:用rrdtool info 文件查看当前 RRA 配置,重新评估保留时长和精度需求。如果确实需要长期存储,考虑用rrdtool resize缩小 RRA,或者迁移到其他时序数据库。resize 操作有风险,务必先备份。
6. 进阶技巧:用 rrdtool tune 和 resize 在线调整已有库
最后一个章节讲两个实际运维中很有用但文档里写得少的操作:tune 和 resize。这两个命令能在不重建库的前提下调整部分参数,省去数据迁移的麻烦。
6.1 rrdtool tune 修改 heartbeat 和 min/max
rrdtool tune可以修改 DS 的 heartbeat、min、max,但不能修改 DS 名称和类型。语法是:
# 把 cpu_user 的 heartbeat 从 600 改成 900 rrdtool tune /data/rrd/server_cpu.rrd --heartbeat cpu_user:900 # 修改 min/max 范围 rrdtool tune /data/rrd/server_cpu.rrd --minimum cpu_user:0 --maximum cpu_user:100tune 修改后立即生效,不需要重启任何服务。但要注意,修改 heartbeat 不会影响已经写入的历史数据,只影响后续写入的判断逻辑。
6.2 rrdtool resize 缩小或扩大 RRA
resize用于调整某个 RRA 的 rows 数量。比如发现 1 天精度的 RRA 太大想缩小:
# 先查看 RRA 编号 rrdtool info /data/rrd/server_cpu.rrd | grep -A2 "rra\[0\]" # 把第 0 个 RRA 的 rows 从 288 改成 144 rrdtool resize /data/rrd/server_cpu.rrd 0 GROW 144resize 的第二个参数是 RRA 编号,第三个参数是 GROW 或 SHRINK,第四个是增减的行数。操作完成后会生成一个resize.rrd文件,需要手动替换原文件。这个操作有数据丢失风险,执行前一定要cp一份备份。
6.3 用 rrdtool dump/restore 做跨版本迁移
如果要从 1.4.7 迁移到更新版本,或者换一台机器,最稳妥的方式是 dump 成 XML 再 restore:
# 导出为 XML rrdtool dump /data/rrd/server_cpu.rrd > /tmp/server_cpu.xml # 在目标机器上恢复 rrdtool restore /tmp/server_cpu.xml /data/rrd/server_cpu_new.rrddump 出来的 XML 包含所有 RRA 的完整数据,restore 时会按 XML 里的定义重建库。跨大版本迁移时,建议先在小规模测试库上验证 restore 后的数据完整性,确认 fetch 和 graph 都正常后再批量操作。
我自己的习惯是:任何对 .rrd 文件的写操作之前,先cp一份到备份目录,文件名带上日期。这个习惯帮我省过至少三次后悔药。rrdtool 本身很稳,但它的参数组合太多,手一抖写错一个数字,可能几天后才发现曲线不对。希望帮到你。
本文还有配套的精品资源,点击获取