
简介RRDTool 1.4.7 是一套面向时序数据存储与绘图的成熟开源工具常作为 Smokeping、Cacti、MRTG 等监控系统的底层组件解决网络流量、CPU 使用率、内存占用等性能数据的采集、归档与可视化问题适合运维工程师、监控平台开发者及数据可视化爱好者。该源码包体积 1.29MB共 314 个文件主要包含 C 源码与头文件、POD/HTML/TXT 格式文档、configure 等构建脚本、man 手册页以及 Perl/Python 辅助脚本既可直接编译部署也可作为二次开发的基础。包内收录 rrdcreate、rrdgraph、rrdtutorial 等完整手册清晰讲解环形数据库创建、Heartbeat 心跳间隔、RPN 绘图语法、数据更新与压缩机制等核心概念同时结合 Smokeping 延迟监控、Cacti 数据采集、MRTG 流量图等集成说明读者可以系统掌握从数据定义、存储策略、定时更新到图表绘制的完整流程并理解各监控工具调用 RRDTool 的典型方式。当前已有 264 人学习下载适合需要搭建自定义监控大盘或想深入理解时序数据存储原理的运维与开发人员。1. 还在装 rrdtool-1.4.7.tar.gz老版本到底哪里值得接手一台老监控服务器时我第一眼看到/usr/local/src/rrdtool-1.4.7.tar.gz其实是拒绝的。都什么年代了rrdtool 早更新到 1.9、2.x怎么还有人从 1.4.7 开始折腾但真正上手后我发现这个 1.4.7 源码包在特定场景下几乎是唯一的选择CentOS 6 这类老系统的官方源里只有 1.4.7而 Cacti、老版本 collectd 对它依赖得很熟升新版本反而可能让 PHP 绘图接口和 RRD 文件头格式出兼容问题。rrdtool-1.4.7.tar.gz 本质上是 RRDRound Robin Database轮询数据库工具 1.4.7 版本的源码发行包解决的是「固定大小文件里按时间序列存储监控数据、并绘制成图」这件事。适合谁运维、SRE、以及需要离线安装监控栈的开发者。今天这篇我把编译、落库、出图和避坑一次性讲透。2. 编译前先想清楚依赖、选型与 configure 参数2.1 源码包校验与 1.4.7 的老朋友依赖我习惯先做两件事校验源码包完整性再确认系统里有没有编译所需的「老伙伴」依赖。下载下来的 tar.gz 如果校验和不符后面 configure 报错会让你怀疑人生。常见的做法是拿到发布方的.md5或.sha256文件然后比对。注意具体哈希值以你实际下载的来源为准网上流传的数值未必可靠。# 在源码包所在目录执行 sha256sum rrdtool-1.4.7.tar.gz # 输出形如xxxxxxxx rrdtool-1.4.7.tar.gz # 将输出结果与发布方提供的 sha256 值比对一致再继续这里顺便说明校验不是走过场。我见过有人跳过校验直接解压结果编译到一半报出奇怪的语法错误最后发现下载的压缩包被截断了几 KB。另一个原因是rrdtool 源码包本身没有内置版本管理系统自校验你无法通过make check来确认 tarball 是否完整所以解压前的哈希比对是最便宜的保险。接下来是依赖。rrdtool 1.4.7 的 configure 脚本会检查一堆库最常出问题的是这么几个依赖库在 rrdtool 中的作用缺失时典型症状libpng / zlibPNG 图片输出configure 报 missing libpngfreetype字体渲染往图里写字缺库或编译时报 fontconfig 相关错误libxml2 / expatXML 解析rrdtool dump输出 XMLdump 功能不可用或 configure 告警cairo / pango1.4.7 新版绘图后端configure 到 graph 部分失败glib-2.0部分工具与绑定依赖路径检查失败注意这里有最容易踩的陷阱系统里已经装了 libpng但缺的是libpng-devel开发头文件。rrdtool 的 configure 找的是头文件png.h和链接库libpng.so只装运行库远远不够。我一般直接用发行版包管理器把带-devel后缀的一起装上。在 CentOS 6 上命令大概是yum install libpng-devel freetype-devel libxml2-devel glib2-devel cairo-devel pango-devel具体包名以你系统的实际仓库为准。2.2 configure 的关键参数与编译环境准备解压之后直接./configure make也能编译但那只是「能跑」。我从第一次做离线安装时就养成了把 configure 参数写在文档里的习惯因为你不知道三个月后自己还会不会记得当时开了哪些特性。对于 rrdtool-1.4.7 这个版本我常用的 configure 参数是这样# 先解压 tar zxf rrdtool-1.4.7.tar.gz cd rrdtool-1.4.7 ./configure \ --prefix/usr/local/rrdtool-1.4.7 \ --disable-tcl \ --disable-perl \ --disable-python \ --with-pic几个参数的逻辑说明--prefix/usr/local/rrdtool-1.4.7指定安装目录。这样做的最大好处是将来想升级或卸载直接删掉这个目录就能清理大部分文件不会把/usr/bin里搞得一塌糊涂。缺点是你需要把这个目录下的bin加进PATH。--disable-tcl / --disable-perl / --disable-python如果你不需要 rrdtool 的 Python、Perl、Tcl 语言绑定建议关掉。语言绑定本身会引入更多依赖比如 Python 绑定需要对应版本的 Python 头文件。很多人用 rrdtool 只是通过命令行出图绑定完全用不到。--with-pic在静态编译或配合某些第三方库时有用一般加上不影响动态编译。configure 结束后先看一眼它是否提示missing或有 warning。1.4.7 的 configure 对缺失库的处理比较「温柔」有时候会以警告形式跳过绘图模块编译出来的 rrdtool 没有 graph 功能。你可以在 configure 输出里搜graph相关行确认 PNG 支持的开关是 yes。还有一个很多人忽略的环境变量PKG_CONFIG_PATH。如果你的依赖库装在非标准路径比如/usr/local/lib/pkgconfigconfigure 根本找不到。我一般会在 configure 前先导出export PKG_CONFIG_PATH/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH export LDFLAGS-L/usr/local/lib -Wl,-rpath,/usr/local/lib export CPPFLAGS-I/usr/local/include这段的意思是让编译系统在找库和头文件时多搜一层自定义路径。cmake 时代大家习惯用 GUI但在 rrdtool 1.4.7 这种 autotools 项目里PKG_CONFIG_PATH 就是命脉。如果跳过这里直接在 configure 阶段报缺库再回来补环境变量就得重跑一遍很浪费时间。3. 把 rrdtool-1.4.7 装成可用集make 与安装目录体系3.1 编译三部曲configure、make、make install 的常规操作configure 通过后下一步就是经典的make make install。但我不建议直接敲这两个命令而是拆开执行这样每一步的报错都能定位到具体环节。# 第一步编译 make -j2 # 如果报错去掉 -j2 单线程重试看完整错误信息 # 第二步安装 make install # 第三步验证安装结果 /usr/local/rrdtool-1.4.7/bin/rrdtool --version # 期望输出类似RRDtool 1.4.7 Copyright by Tobias Oetiker-j2是让 make 以 2 个并行任务编译能明显缩短时间。但如果机器内存小低于 1GB并行编译可能因为内存不足中途崩掉表现是报一堆如gcc: internal compiler error的错误这时候把-j2去掉重来就好。注意并行编译失败后重新执行make时脚本一般会从断开的地方继续但某些情况下也需要make clean后重来。我碰到过好几次旧对象文件残留导致第二次编译仍然失败所以只要报错不明显直接 clean 重来最省心。安装路径方面装到/usr/local/rrdtool-1.4.7之后这个目录结构大概长这样目录名根据你--prefix参数而定具体的二进制和库文件路径也因系统习惯而异。bin/下是rrdtool可执行文件lib/下是librrd.so这类库文件share/下会有一些示例和帮助文件。把这些工具链加进 PATH 的方法我写在系统环境里# 在 /etc/profile.d/rrdtool.sh 里写入以 root 身份 export PATH/usr/local/rrdtool-1.4.7/bin:$PATH export LD_LIBRARY_PATH/usr/local/rrdtool-1.4.7/lib:$LD_LIBRARY_PATH # 保存后执行 source /etc/profile.d/rrdtool.sh 使其立即生效这里要注意LD_LIBRARY_PATH是运行时库搜索路径。如果你不设置它运行rrdtool时可能会报error while loading shared libraries: librrd.so.4: cannot open shared object file。另一个更优雅的方案是修改/etc/ld.so.conf.d/rrdtool.conf然后执行ldconfig但很多线上环境不允许随便改系统链接配置所以用LD_LIBRARY_PATH反而是最克制的方式。3.2 并行编译、安装目录与卸载/升级安排既然讲到安装就不得不提前考虑以后卸载或升级怎么办。rrdtool 1.4.7 的 Makefile 里有没有make uninstall我不确定即便有它也只能删除它记录过的文件你在它之后手工创建的数据文件、配置文件一概不动。因此我的习惯是把安装信息记全记录 configure 时的完整命令行保存到/usr/local/rrdtool-1.4.7/BUILD_INFO.txt不把 rrdtool 的关键二进制做软链到/usr/bin/rrdtool除非你确认系统里没有其他版本。为什么要控制软链因为多个 rrdtool 版本共存时rrdtool命令本身并不涉及运行时库的严重冲突只要LD_LIBRARY_PATH指对了就行。但不同版本的librrd.so的 ABI 版本可能不同其他依赖它的程序比如 PHP 的 rrd 扩展是通过librrd.so链接的你把软链切来切去可能导致 Cacti 绘图直接白屏或报 undefined symbol。我踩过一次这个坑为了尝鲜把软链切到 1.7结果 Cacti 的graph_json调用全面崩溃最后只能切回来。所以如无必要保持单一版本安装不要让环境里同时存在多个活跃的 rrdtool。升级安排也是一个被忽略的点。rrdtool 的 RRD 文件格式在不同小版本间有兼容要求。1.4.x 系列生成的.rrd文件一般能被 1.5 以上版本读取但反过来不一定。你在升级前做一次rrdtool dump old.rrd old.xml升级后再用新版本rrdtool restore old.xml new.rrd这是最稳妥的迁移路径。1.4.7 这个版本本身处于 1.4 系列的后段它的文件格式和 1.4.8、1.4.9 高度一致所以如果是同系列内升级基本不用做转换。4. 最小可用的 RRD 闭环建库、写数据、出图4.1 RRD 环形缓冲原理为什么 1.4.7 能省这么多磁盘很多人以为 rrdtool 就是画图的其实它的核心是「环形缓冲数据库」。我尽量用一个具体的例子解释。普通监控数据库比如 MySQL 里存性能数据它会无限增长。RRD 的做法是每个.rrd文件在一开始就指定好大小和几个「归档区」RRARound Robin Archive。数据写进去后按照时间窗口的粒度被聚合、被覆盖。就像一个固定的圆环指针绕一圈后新数据覆盖最旧的数据。文件大小始终保持稳定不随运行时间增长。这个「聚合」动作也带来一个关键特性1.4.7 的 RRA 可以保存不同分辨率的统计数据。比如最近一天的数据按每分钟一条保留最近一周的数据按每五分钟一条保留。这个过程中RRD 会做自动归并CF 可选取 AVERAGE、MIN、MAX、LAST你在rrdcreate时决定用哪种聚合方式。理解这一点你就明白为什么很多人说 RRD 适合长时间周期监控——磁盘占用固定历史数据分层清晰。在动手建库前我建议你先计算「step」和「RRA」两个量。step 是数据写入的基本时间间隔比如 300 秒RRA 的 rows 决定了这个归档区保留多少行。一分钟一条、保存 7 天的 RRArows 大概是 10080。这个计算一旦设错后期修改很麻烦可能需要重建文件。所以最开始宁可把 rows 设大一点因为文件虽然变大但和普通数据库相比仍然非常小。4.2 rrdcreate 建库与 rrdupdate 写入的最小命令与参数现在做一个最直观的演示。我们要监控一台 Linux 服务器的 CPU 使用率每 60 秒写入一条数据保存 2 天的一分钟粒度数据同时保存 2 周的 5 分钟均值数据。RRD_FILE/tmp/cpu.rrd # 第一步建库 rrdtool create $RRD_FILE \ --start $(date -d 1 hour ago %s) \ --step 60 \ DS:cpu:GAUGE:120:0:100 \ RRA:AVERAGE:0.5:1:2880 \ RRA:AVERAGE:0.5:5:4032参数说明--start文件的起始时间戳单位是 epoch 秒。这里用date命令动态生成 1 小时前的秒数是为了给历史数据留一点回填空间。注意不能让--start比当前时间晚否则写入会失败。--step 60每条数据之间的时间间隔。这里的值是「秒」。DS:cpu:GAUGE:120:0:100DS 是数据源定义。cpu是数据源名字GAUGE表示存的值就是当前采样值不做过多的速率换算120是 heartbeat——超过这个秒数没有收到新数据这段空缺就会被标记为未知NaN0:100是值的最小、最大范围超出范围的采样会被当成 NaN。RRA:AVERAGE:0.5:1:2880第一个归档。AVERAGE是聚合函数0.5是 xfiles factor表示归档里允许有多少比例的数据是 NaN 仍保持有效0.5 是常用值1表示每 1 个原始数据点聚合一次即保持原始分辨率2880是这个归档的槽位数60 秒 × 2880 48 小时。第二个 RRA 的5表示每 5 个原始点即 300 秒聚合成一个归档点4032 个点约等于 2 周。建好库后用rrdupdate写入数据# 写入一条固定值 rrdtool update $RRD_FILE $(date %s):42.5 # 批量写入用 N 表示当前时间 rrdtool update $RRD_FILE N:50.0 N:51.2 N:49.8N是 rrdtool 里的特殊记号代表当前时间。如果写入的时间戳不是 step 的整数倍rrdtool 会自动对齐到最近的整 step 上这一点初用者容易被吓到觉得它「改了我的数据」。实际上这不是改值而是数据库按固定时隙存储的必然行为。若想避开这种时隙漂移还是建议在采集端就精确控制时间戳。写完几笔数据后立刻验证是否正确rrdtool info $RRD_FILE | grep -E last_update|ds[cpu] # 可以看到 last_update 相关时间戳以及 cpu 数据源的状态rrdtool info输出里最关键的是last_update字段它表示最后一次成功写入的时间。如果它一直不前进说明你的写入时间戳有问题通常是写入时间比文件--start还早或者类型不匹配。4.3 rrdgraph 出图把数据变成监控图的最小姿势数据有了接下来就是用rrdgraph绘图。这是 rrdtool 里参数最复杂的一部分但最小可用命令其实很短rrdtool graph /tmp/cpu.png \ --start end-24h \ --end now \ --vertical-label CPU % \ --width 600 --height 200 \ DEF:cpuval$RRD_FILE:cpu:AVERAGE \ LINE2:cpuval#FF0000:CPU usage这里有几个值得展开的关键点--start end-24hrrdtool 支持这种相对时间语法表示从结束时间往前推 24 小时。--end now是截止到当前。这个语法可以避开你需要手动算 epoch 秒的问题。DEF:cpuval$RRD_FILE:cpu:AVERAGE从 rrd 文件里取数据源cpu使用 AVERAGE 归档区。注意它取的是 RRA 里存的聚合值不是原始数据点——这正是 RRD 的特色。LINE2:cpuval#FF0000画一条宽度为 2 像素的线。如果你想画面积图改成AREA即可但注意AREA和LINE叠加时要先画AREA再画LINE顺序反了区域会盖住线条。出图后用任意看图工具打开cpu.png。如果图片是空的只有坐标轴没有线条很可能是这段时间内根本没有数据写入成功。这时我一般会用rrdtool fetch检查原始数据rrdtool fetch $RRD_FILE AVERAGE --start end-24h --end now | head -20 # 输出每行形如1634567890: 42.5000000000fetch的输出如果全是nan说明问题在写入端如果有几个数值但 graph 没线问题在--start/--end时间范围设置。这招非常实用能把出图和入库两个阶段的问题快速隔离。5. 编译与使用中绕不开的 5 个坑现象、原因、排查5.1 configure 卡在 missing required library现象运行./configure时输出一段configure: error: Cant find include file png.h或类似提示然后退出。在某些精简环境中报错会提前到检查 zlib 就停住。原因最常见的是系统里有libpng的运行时库但没有libpng-devel开发包。configure 查找的是头文件而不是.so文件。另外库装到了非标准路径比如/usr/local/libPKG_CONFIG_PATH没晒出来。解决先用包管理器确认开发包已安装再检查环境变量。不要一条条试直接先执行find /usr/include -name png.h如果只有/usr/local/include/png.h就把CPPFLAGS-I/usr/local/include导出后重新 configure。注意 configure 有缓存改完环境变量后建议把源码目录里的config.cache删掉再重跑。5.2 出图中文乱码与字体路径现象rrdtool graph生成的图片中中文标签全部变成方块或英文正常但中文是乱码。有时候报错信息直接提示找不到字体文件。原因rrdtool 1.4.7 用 freetype 渲染文字渲染时需要指定一个可用的 TTF 字体文件。默认配置里GDFONTPATH环境变量没设置或系统里根本没有中文字体。解决两种做法。第一在 graph 命令里显式指定字体用FONT指令FONT:path/to/font.ttf。第二设置全局环境变量GDFONTPATH并把它指向中文字体所在目录比如存放了思源黑体或文泉驿字体的目录。我实际测试过GDFONTPATH只需要指向目录不指定具体文件名rrdtool 会在里面找默认字体。一个隐蔽细节某些精简的容器镜像里连fontconfig都没有TTF 文件就算存在也加载不了那就得先把 fontconfig 相关包补上。5.3 写入的时间与实际时间对不上现象rrdtool fetch出来的数据时间戳与数据产生时刻相差 8 小时或者图表的横轴起点偏了。原因这是时区问题。RRD 文件内部存储的时间戳一律是 UTCepoch 秒而rrdtool graph在绘图时会读系统本地时区你手动写date %s时得到的是 UTC 秒数本身没问题但如果你把「2025-06-01 12:00」这种本地时间字符串直接转成 epoch没有带时区标志就会偏。解决写数据时始终用date %s获取 UTC 秒不要手动拼日期。绘图时如果希望按本地时间显示在 graph 命令里加--imglabel-localtime或者确保TZ环境变量正确。如果不确定在终端执行date -u看 UTC 时间与系统时间差多少就能快速确认是否时区导致。5.4 数据全部 NaN 但明明 insert 成功了现象确认执行了rrdtool update返回也没有报错但fetch出来全是 nangraph 上没线。原因三个可能。一是写入时间超出了 DS 定义中 heartbeat如 120 秒的跨度rrdtool 认为数据断档二是数据值超出了 DS 的 min/max 范围比如0:100范围内写入了 120三是写入时间戳比--start还早或落后太多rrdtool 判断为过期数据丢弃。解决先用rrdtool last查看文件最后更新时间戳再用date %s对比当前时间确认两者差距。如果差距大于一个 heartbeat把 heartbeat 调大。注意修改 heartbeat 不需要重建文件可以直接rrdtool tune $RRD_FILE --heartbeat cpu:300这个命令能在不丢失现有数据的情况下调整 DS 参数是 rrdtool 里一个低调但好用的「后悔药」。5.5 想卸载升级时发现源码安装留下了一地鸡毛现象rrdtool 装了半年后想升级执行make uninstall发现根本没这个目标或者卸载后旧.rrd数据文件被新版本读取后出现兼容性报错。原因源码安装不像 RPM/deb 有包管理系统做统一登记卸载全靠你当时是否把文件集中在一个目录。而.rrd数据文件通常是建在/var/lib下的更不会跟着源码安装被清理。解决我没法给你一个自动清理脚本但可以给出一个防患于未然的操作习惯把--prefix指向固定目录记录BUILD_INFO.txt升级前先rrdtool dump所有需要保留的 rrd 文件不要直接删除旧版本而是先装新版本到另一个 prefix 目录测试读取旧 rrd 文件成功后再做切换。这套「先共存、后切换」的流程在 1.4.7 升级时少踩很多坑也避免影响正在运行的监控采集任务。6. 进阶用 python-rrdtool 或命令封装实现自动化监控落库到这里你已经能用命令行完成建库、写值、出图。但在真实运维环境里我们不会手动敲rrdtool update。常见的做法是用 Python 脚本或 shell 封装来定时采集数据并落库。如果你在编译时没有开启 Python 绑定--disable-python最简单的封装其实是直接用subprocess调命令行工具这反而更省心因为它不依赖任何 Python 头文件版本匹配。import subprocess import time import psutil # 需要预先安装或换成别的采集来源 RRD_FILE /var/lib/monitor/cpu.rrd def update_cpu(): # 采集 CPU 使用率 cpu_percent psutil.cpu_percent(interval1) # 把值写入 RRD subprocess.run( [rrdtool, update, RRD_FILE, N: str(cpu_percent)], checkTrue, capture_outputTrue ) # 验证一条检查最近数据点是否正常 result subprocess.run( [rrdtool, fetch, RRD_FILE, AVERAGE, --start, end-5min, --end, now], capture_outputTrue, textTrue ) print(result.stdout) while True: update_cpu() time.sleep(60)关于这个脚本的解释N时间戳和上一条数据相差 60 秒所以建库时step必须也是 60否则会出现「数据均匀但时间戳斜」的问题。checkTrue让subprocess在 rrdtool 返回非零退出码时抛出异常方便采集中段发现问题。配合外部 cron 或 systemd timer 使用比脚本里的while True更可靠——毕竟这个脚本一断后面所有数据都不会写入。psutil.cpu_percent(interval1)的interval1会让采集多等待 1 秒这会让实际落库时间比整点晚 1 秒但只要小于 heartbeat没有任何问题。最后我想说的是我在第一次用 rrdtool 时犯过一个低级错误建库时--step写了 300而采集脚本每 60 秒写一次结果大量数据因为 heartbeat 只有 120 秒而被判为 NaN。当时整整一周的监控曲线全是缺口最后是用rrdtool tune把 heartbeat 调到 600 才救回来。这个经验让我养成一个习惯凡是写历史数据的系统先验证再信任fetch出来的原始数据比出图更值得信赖。希望这篇关于 rrdtool-1.4.7.tar.gz 的完整编译、建库、出图和排错笔记能帮你在这个老版本上少走弯路。本文还有配套的精品资源点击获取