从 RRD 文件中提取数据
**********************************************************************************************************************
注 :该教程参考了如下内容 :
A )官方文档 :http://oss.oetiker.ch/rrdtool/doc/index.en.html
B )abel 兄的大作 :http://bbs.chinaunix.net/viewthread.php?tid=552224&highlight=rrdtool
http://bbs.chinaunix.net/viewthread.php?tid=552220&highlight=rrdtool
作者 :ailms <ailms{@}263{dot}net>
版本 :v1
最后修改 :2006/11/17 17:35
**********************************************************************************************************************
一)前言
RRD 是 Round Robin Database 的意思,那么是否可以象普通的数据库进行查询操作呢?
答案是可以的。fetch 就是用来做这种事情的工具。当然 fetch 不能和 select 语句相比,它只是根据用户指定的时间,
从合适的 RRA 中取出数据,并加以格式化。不过和 MRTG 相比,已经好很多了,至少你不用取看该死的 log 文件。
实际上,fetch 操作其实可以不学,因为 RRDtool 会自动帮你选好数据。但你如何确定 RRDtool 取的数据就是你想要的呢?
或者说你如何证明 RRDtool 绘制出来的图是正确的呢?
废话少说,下面开始正文
二)fetch 操作的语法
CODE:
rrdtool fetch filename CF [--resolution|-r resolution] [--start|-s start] [--end|-e end]
其中 --start 、--end 、-r 都是可选的 。RRDtool 默认的 --end 是 now ,--start 是 end-1day ,也就是1 天前。
CF 可以是 AVERAGE 、MAX 、MIN 、LAST ,当然必须建库时有该 CF 类型的 RRA 才可以查,否则会报错。
三)fetch 如何取数据
在确定了时间范围后,RRDtool 会从多个 RRA 中挑选最佳的那个 RRA 的数据。至于什么是“ 最佳” ,则从两个方面考虑 :
A )第一是该 RRA 的数据要尽可能的覆盖所请求的时间范围。 如何计算一个 RRA 的覆盖时间呢?以 eth0.rrd 的第一个RRA 为例,
有 600 个记录,每个记录相隔300 秒,则总的时间覆盖范围是180000 秒≈2 天,所以如果 –-start 和 -–end 规定的时间范围
大于2 天,则 RRDtool 不会从该 RRA 中取数据。
B )第二是 resolution 的要求。 还是上面的例子,如果是要画3 天的数据,从时间覆盖范围上来讲,第2 、3 、4 个 RRA 都符合要求。
那究竟挑选那个 RRA 的数据呢?如果 fetch 中有指定 –r 选项,则挑选 resolution 等于 –r 指定的值那个 RRA 的数据。如果没有
–r 选项,则从第一个合适的 RRA 中取数据。
C )fetch 如果不加 –-start 、--end 、-r ,则默认输出 resolution 最小的那个 RRA 的数据。就像下面的例子1 一样。
四)实际例子
实例一 :默认情况
CODE:
[root@dns1 bob]# rrdtool fetch eth0.rrd AVERAGE |more
eth0_in eth0_out
1164467700: 1.1337243905e+01 9.6323712631e-02
1164468000: 1.7896453039e+01 0.0000000000e+00
1164468300: 1.8469136234e+01 1.2215723119e+00
。。。。(中间省略)
1164553800: 6.9634610564e+01 4.9644415243e+01
1164554100: nan nan
CODE:
[root@dns1 bob]# date (当前时间)
日 11 月 26 23:11:12 CST 2006
[root@dns1 bob]# date -d '1970-1-1 1164554100 sec utc' ( 最后一个记录的时间)
日 11 月 26 23:15:00 CST 2006
[root@dns1 bob]#
[root@dns1 bob]# date -d '1970-1-1 1164467700 sec utc' (第一个记录的时间)
六 11 月 25 23:15:00 CST 2006
[root@dns1 bob]#
fetch 输出的第一列是 timestamp ,表示后面的数据是在什么时间收到的。”:” 后面就是DS 的值。fetch 不能指定只取那个 DS 的数据,
只能一次性取出全部 DS 的值。可以看到,eth0.rrd 有两个 DS :eth0_in 和 eth0_out ,每个 DS 的值用 空格进行分隔,一律采用科学记数法的格式。
如果 fetch 不指定 –-start 和 -–end ,则默认取从当前时刻算起,往前1 天的数据(289 个记录)。因为现在是 23:11 ,还不到 23:15, 所以最后一个记
录的值是 NaN (Not a Number ),也就是 UNKNOWN 的意思。可以看到,两个记录之间的时间间隔是300 。
实例二:使用 --start 和 --end 指定时间范围
CODE:
[root@dns1 bob]# rrdtool fetch eth0.rrd AVERAGE --start 1164467700 --end 1164553800 |more
eth0_in eth0_out
1164468000: 1.7896453039e+01 0.0000000000e+00
1164468300: 1.8469136234e+01 1.2215723119e+00
1164468600: 1.5988336199e+01 1.4417769382e-01
。。。。。(中间省略很多)
1164553800: 6.9634610564e+01 4.9644415243e+01
1164554100: 1.7481962958e+02 2.3086574912e+02
[root@dns1 bob]#
可以看到第一个记录和最后一个记录都比 –-start 和 –-end 晚了300 秒。
实例三 :使用 AT 风格的时间
CODE:
[root@dns1 bob]# rrdtool fetch eth0.rrd AVERAGE --start end-1day --end 1164553800 |more
eth0_in eth0_out
1164467700: 1.1337243905e+01 9.6323712631e-02
1164468000: 1.7896453039e+01 0.0000000000e+00
。。。。。。。(中间省略很多)
1164554100: 1.7481962958e+02 2.3086574912e+02
[root@dns1 bob]#
注意 --start 的值是 end-1day ,这就是 AT 风格的时间。end 就是 --end 中给出的1164553800 。具体的时间范围是表示起始时间从1164553800 往前1 天 。
可以看到,现在第一个记录和实例二相比,提前了300 秒。和例2 中的 –start 一致了。所以能够用 AT 风格的时间的时候还是用 AT 风格的时间比较方便。
可以省去计算的麻烦,别人也比较容易看。
实例四 :提取指定 resolution 的数据
CODE:
[root@dns1 bob]# rrdtool fetch eth0.rrd AVERAGE --start 1164467700 --end start+1day -r 1200 |more
eth0_in eth0_out
1164468000: 1.7899370295e+01 3.8782610300e+00
1164469200: 2.0828335735e+01 3.4166666667e-01
1164470400: 1.4581351504e+01 3.5000000000e-02
。。。。。。(中间省略很多)
1164554400: 9.4367707174e+01 9.4866775629e+01
[root@dns1 bob]
可以看到,现在记录两两之间的时间间隔变成了1200 了。输出的行数为 (86400/1200 )+1=73 (72+1 )。
实例五:如果指定一个不存在的 resolution 呢?
CODE:
[root@dns1 bob]# rrdtool fetch eth0.rrd AVERAGE --start 1164467700 --end start+1day -r 1000 |more
eth0_in eth0_out
1164468000: 1.7899370295e+01 3.8782610300e+00
1164469200: 2.0828335735e+01 3.4166666667e-01
。。。。。。(中间省略很多)
1164554400: 9.4367707174e+01 9.4866775629e+01
[root@dns1 bob]#
我们指定的 resolution 是 1000 ,但并没有那个 RRA 的 resolution 为 1000 ,所以 RRDtool 挑选了第一个合适的 resolution ,
也就是 1200 的那个 RRA 的数据作为结果输出。注意,RRDtool 只会挑选 resolution 比 –r 指定的值相等或者更高的 RRA ,不会挑
选比 –r 指定的值小的 RRA 。 例如在该例子中,RRDtool 就不会挑选 resolution=300 的第一个 RRA 。为什么呢?
各位可以自己根据第三部分“fetch 如何提取数据” 的两个准则考虑一下
实例六 :再来看一个 –r 的例子
如果我不想指定 –-start 或者 –end ,就想看 resolution 为 1200 呢?
CODE:
[root@dns1 bob]# rrdtool fetch eth0.rrd AVERAGE -r 1200
eth0_in eth0_out
1164470400: 1.4581351504e+01 3.5000000000e-02
1164471600: 1.9312781373e+01 3.5000000000e-02
。。。。。(中间省略很多)
1164555600: 8.5249300043e+01 7.0171152327e+01
1164556800: nan nan
[root@dns1 bob]#
咦?为什么还是使用记录的时间间隔还是 300 秒呢?我们不是指定了 –r 1200 吗?
老实说,这种方法 90% 以上的机率是不会成功吗?那应该怎么办呢?
实例七 :正确使用 –r 的方式
CODE:
[root@dns1 bob]# rrdtool fetch eth0.rrd AVERAGE -r 1200 --end $((($(date +%s)/1200)*1200)) |more
eth0_in eth0_out
1164470400: 1.4581351504e+01 3.5000000000e-02
1164471600: 1.9312781373e+01 3.5000000000e-02
1164472800: 1.7383358822e+01 3.5000000000e-02
1164474000: 1.4781054841e+01 3.3225406191e-01
。。。。。。(中间省略很多)
1164555600: 8.5249300043e+01 7.0171152327e+01
1164556800: nan nan
[root@dns1 bob]#
现在 resolution 已经变成 1200 的了。同理,如果想看 7200 ,86400 resolution 的 RRA ,只要把 end 部分的 ( )中的数字替换为相应的值就可以了。
CODE:
[root@dns1 bob]# rrdtool fetch eth0.rrd AVERAGE -r 7200 --end $((($(date +%s)/7200)*7200))
[root@dns1 bob]# rrdtool fetch eth0.rrd AVERAGE -r 86400 --end $((($(date +%s)/86400)*86400))
实例八 :关于 fetch 提取数据准则1 的测试
CODE:
[root@dns1 bob]# rrdtool fetch eth0.rrd --start now-3day AVERAGE |more
eth0_in eth0_out
1164298800: nan nan
1164300000: nan nan
。。。。。。(中间省略很多)
1164556800: 6.4118014239e+01 1.8871145267e+01
1164558000: nan nan
[root@dns1 bob]#
和第一个例子不同,这次的 resolution 是 1200 了?为什么呢?因为我们指定的时间范围是3 天,而第一个 RRA 只保存2 天的数据多一点,所以 RRDtool 不会从
该 RRA 取数据,那么会从那个 RRA 取数据呢?由于我们没有指定 –r 选项,所以 RRDtool 选择1200 的那个 RRA
实例九 :关于 fetch 提取数据准则2 的测试
CODE:
[root@dns1 bob]# rrdtool fetch eth0.rrd --start now-3day AVERAGE -r 7200 |more
eth0_in eth0_out
1164304800: nan nan
1164312000: nan nan
1164319200: nan nan
。。。。。。(中间省略很多)
1164549600: 5.1899602485e+01 4.3073128067e-01
1164556800: 7.9766222122e+01 4.0644151093e+01
1164564000: nan nan
[root@dns1 bob]#
现在 resolution 不再是 1200 ,而是指定的 7200 了。
因为虽然 resolution=1200 的 RRA 就可以满足 --start 和 --end 的需求,
但因为 -r 指定 resolution=7200 ,所以从第3 个 RRA 中取数据
五)总结
从上面我们可以看出,fetch 实际上是非常复杂的一个命令,如果想要输出你所要的数据,就必须考虑好几个因素 :
A )第一是具体想输出的时间范围?
B )第二是计算好 –-start 和 –end 。建议至少给出一个,最好2 个都给出
C )第三是如果有多个RRA 符合条件,则使用 –r 指定具体的 resolution
使用RRDtool 进行绘图(一)
**********************************************************************************************************************
注 :该教程参考了如下内容 :
A )官方文档 :http://oss.oetiker.ch/rrdtool/doc/index.en.html
B )abel 兄的大作 :http://bbs.chinaunix.net/viewthread.php?tid=552224&highlight=rrdtool
http://bbs.chinaunix.net/viewthread.php?tid=552220&highlight=rrdtool
作者 :ailms <ailms{@}263{dot}net>
版本 :v1
最后修改 :2006/11/17 17:35
**********************************************************************************************************************
一)前言
使用RRDtool 我们最关心什么?当然是如何把数据画出来了。虽然前面谈了很多,但这些都是基础来的。掌握好了,可以让你在绘图时更加得心应手。
本来还有 RPN (反向波兰表达式)一节的,但考虑一下,觉得还是放到后面,先从基本的绘图讲起。
这一节的内容虽然很多,但基本都是实验性的内容,只要多试几次就可以了。
二、graph 操作的语法
CODE:
rrdtool graph filename [option ...]
[data definition ...]
[data calculation ...]
[variable definition ...]
[graph element ...]
[print element ...]
其中的 data definiton 、variable definition 、data calculation 、分别是下面的格式
CODE:
DEF:<vname>=<rrdfile>:<ds-name>:<CF>[:step=<step>][:start=<time>][:end=<time>][:reduce=<CF>]
VDEF:vname=RPN expression
CDEF:vname=RPN expression
其中 filename 就是你想要生成的图片文件的名称,默认是 png 。你可以通过选项修改图片的类型,可以有 PNG 、SVG 、EPS 、PDF 四种。
A )DEF 是 Definition (定义)的意思。定义什么呢?你要绘图,总要有数据源吧?DEF 就是告诉 RRDtool 从那个 RRD 中取出指定
DS (eth0_in 、eth0_out )的某个类型的统计值(还可以指定 resolution 、start 、end ),并把这一切放入到一个变量 <vname> 中 。
你可能会感到奇怪,为什么还有一个 CF 字段?因为 RRA 有多种 CF 类型,有些 RRA 可能用来保存平均值、有些 RRA 可能用于统计最大值、
最小值等等。所以你必须同时指定使用什么 CF 类型的 RRA 的数据。至于 :start 和 :end 、:reduce 则用得比较少,最常用的就是 :step 了,
它可以让你控制 RRDtool 从那个 RRA 中取数据。
B )VDEF 是 Variable Definition (变量定义)的意思。定义什么呢?记得 MRTG 在图表的下面有一个称之为 Legend 的部分吗?
那里显示了1 个或者2 个 DS (MRTG 没有 DS 一说,这里是借用 RRDtool 的)的 “ 最大值” 、“ 平均值” 、“ 当前值” 。这些值是如何
计算的呢?
RRDtool 中用 VDEF 来定义。这个变量专门存放某个 DS 某种类型的值,例如 eth0_in 的最大值、eht0_out 的当前值等。当你需要象
MRTG 一样输出数字报表(Legend ) 时,就可以在 GPRINT 子句(sub clause )中调用它。
同样它也需要用一个变量来存放数值。要注意的是,旧版 的 RRDtool 中是用另外一种格式来达到相同的目的。新版的 RRDtool 则推荐使用
VDEF 语句。但在使用过程中,却发现 VDEF 的使用反而造成了困扰。 例如你有5 个 DS 要画,每个 DS 你都想输出最大值、最小值、平均值
、当前值。 如果使用 VDEF ,则需要 4 * 5 = 20 个 VDEF 语句,这会造成极大的困扰。具体例子可以看第十一节“ 数字报表” 部分。
C )CDEF 是 Calculation Define 的意思。使用过MRTG 的都会体会到一点,MRTG 的计算能力实在太差了。例如你有两个 Target ,
一个是 eth0_in , 一个是 eth0_out, 如果要把它们相加起来,再除以8 ,得出 bytes 为单位的值,如何计算呢?或者说你只想看
eth0_in 中超过 10Mb/s 的那部分, 其余的不关心,又如何实现呢?因为 MRTG 不能对它从 log 取出来的数据进行修改,只能原
原本本的表现,所以很难满足我们的要求。而使用 CDEF , 这一切都可以很容易的实现。CDEF 支持很多数学运算,甚至还支持简
单的逻辑运算 if-then-else ,可以解决前面提到的第2 个问题:如何只绘制你所关 心的数据。不过这一切都需要熟悉 RPN 的语法,
所以我们放到下一节介绍,这一节就介绍如何把 RRDtool 中的数据以图表的方式显示出来。
三)选项分类
本部分我们按照官方文档的方式,把选项分成几大类,分为 :
A )Time range : 用于控制图表的X 轴显示的起始/ 结束时间,也包括从RRA 中提取指定时间的数据。
B )Labels : 用于控制 X/Y 轴的说明文字。
C )Size : 用于控制图片的大小。
D )Limits : 用于控制 Y 轴的上下限。
E )Grid : 用于控制 X/Y 轴的刻度如何显示。
F )Miscellaneous : 其他选项。例如显示中文、水印效果等等。
G )Report : 数字报表
需要说明的是,本篇当中并不是列出了所有选项的用法,只是列出较为常用的选项,如果想查看所有选项的的用法,可以到官方站点下载文档,
这里就不一一列出了,望各位见谅。
四)时间范围控制(Time Range )
CODE:
[-s|--start time] [-e|--end time] [-S|--step seconds]
既然要绘图,就应该有一个起始/ 结束的时间。Graph 操作中有 –s ,-e 选项。这两个选项即可以用于控制图表的 X 轴显示的时间范围,也可以用
于控制 RRDtool 从 RRA 中提取对应时间的数据。如果没有指定 –-end ,默认为 now ;如果没有指定 –-start ,则默认为1 天前。如果两者都没有
指定,则图表默认显示从当前算起1 天内的。数
回头看一下 DEF 中,也有 :start ,:end , :step ,这些和 –-start 、--end 、--step 之间有什么关系呢?
让我们先看 :step 和 –step 之间的关系是如何的。
下面以 eth0.rrrd 为例,假设要绘制的时间范围 range 等于 end -start[
A )如果 0 < ragne < 180000 (第一个 RRA 的时间覆盖范围) ,则默认从第1 个RRA 中取数据 :
如果 DEF 中给出的 :step > 300 ,例如 1000 ,则从 resolution= 1000 的或者第一个高于 1000 的RRA 中挑选数据,由于 eth0.rrd 中没有
resolution = 1000 的 RRA ,则 RRDtool 会从 resolution = 1200 的第2 RRA 中取数据。
如果 DEF 中给出的 :step <= 300 ,例如 200 ,则 RRDtool 会忽略该设定,还是从第一个 RRA 中取数据。
B )如果 180000 < range < 720000 ,由于第一个RRA 只能保存2 天的数据,所以默认从第2 个RRA 中取数据 :
如果 DEF 中给出的 :step > 1200 ,例如 1800 ,则 RRDtool 会从 resolution = 7200 的第3 RRA 中取数据
如果 DEF 中给出 :step<= 1200 ,例如 300 ,则 RRDtool 会忽略,还是从第2 个 RRA 中取数据
C )如果 720000 < range < 4320000 ,则默认从第三个 RRA 中取数据 :
如果 DEF 中给出的 :step > 7200 ,例如 10000 ,则从第4 个 RRA 中取数据
如果 DEF 中给出的 :step <= 7200 , 例如 1200 ,则忽略该值,并还是从第3 个 RRA 中取数据
D )如果 4320000 < range < 63072000 ,则默认从第4 个 RRA 中取数据 :
如果 DEF 中给出的 :step > 86400 ,则行为未知
如果 DEF 中给出的 :step <=86400 ,则从第4 个 RRA 中取数据
E )-S 选项可以直接控制 RRDtool 如何挑选 RRA 。
例如 -S 1200 ,即使DEF 中不加 :setp ,则 RRDtool 会从第2 个 RRA 中取数据,即使 rang < 180000
如果 -S 和 :step 同时出现,则 :step 优先。
F )DEF 中的 :start 和 :end 可以覆盖 –-start 和 –-end 的值。
默认情况下,如果 DEF 中不加 :start 和 :end ,则等于 –-start 和 –end
如果 DEF 中定义了 :start 和 :end ,则以 :start 和 :end 为准。
实例1 :使用 –-start 指定 X 轴的起始时间
CODE:
[root@dns1 bob]# rrdtool graph 1.png /
> --start now-120000 / # 表示起始时间是当前时间往前 120000 秒,也就是 33 个小时左右
> DEF:value1=eth0.rrd:eth0_in:AVERAGE / # 从eth0.rrd 中取出 eth0_in 的数据,CF 类型为 AVERAGE
> AREA:value1#ff0000 # 用“ 方块” 的形式来绘制 value1 ,注意这里是用 value1 ,不是用 eth0_in
481x154 # 如果 RRDtool 有绘图方面的语句,则这里显示图片大小,否则为 0x0 。
[root@dns1 bob]#
可以看到 X 轴的文字有些是乱码,不过不要紧,你可以临时已用 env LANG=C rrdtool xxxx 来解决该问题,或者在后面用
–n 来设定 RRDtool 使用中文字体,就不会出现这样的情况了
实例2 :使用 :step 从第2 个RRA 中取数据
CODE:
[root@dns1 bob]# rrdtool graph 2.png /
> --start now-120000 /
> DEF:value1=eth0.rrd:eth0_in:AVERAGE:step=1000 / # :step 指定 resolution=1000
> AREA:value1#ff0000
481x154
[root@dns1 bob]#
这里是 :step=1000 ,但 RRDtool 会取 :step=1200 的 第2 个 RRA 的数据来绘图, 可以和上面的 1.png 比较,发现比较平滑。
实例3 :使用 –S 从第2 个RRA 中取数据
CODE:
[root@dns1 bob]# rrdtool graph 4.png
> -S 1200 / # 使用 –S 控制 RRDtool 从 resolution=1200 的 RRA 中取数据
> --start now-120000 /
> DEF:value1=eth0.rrd:eth0_in:AVERAGE /
> AREA:value1#ff0000
481x154
[root@dns1 bob]#
可以看到和上面的图一样,说明 RRDtool 的确按照 -S 的设置从第2 个RRA 中取数据了
使用 –S 可以对 DEF 中所有的 DS 都使用相同的 resolution ,等于在每个 DEF 后都加上 :step=<value> ,value 是 –S 的值
实例4 :同时使用 –S 和 :step
CODE:
[root@dns1 bob]# rrdtool graph 5.png
> -S 1200 / # -S 指定 resolution=1200
> --start now-120000 /
> DEF:value1=eth0.rrd:eth0_in:AVERAGE:step=300 / # :step 指定 resolution=300
> AREA:value1#ff0000
481x154
[root@dns1 bob]#
可以看到 5.png 和 1.png 是一样的,也就是说 –S 1200 并没有起作用,而是 :step=300 起作用了
实例5 :使用 :start 和 :end 只显示指定时间内的数据
CODE:
[root@dns1 bob]# rrdtool graph 1.png /
> --start now-1h / # X 轴显示1 个小时的长度
> DEF:value1=eth0.rrd:eth0_in:AVERAGE:start=now-600:end=now-300 / # 但只取10 分钟前到5 分钟前的这部分
> AREA:value1#00ff00:in
475x168
[root@dns1 bob]#
如果我们不加 :start 和 :end ,则效果如下 :
我们甚至可以让两个对象显示不同的时间,例如
实例6 :让两个对象显示不同时间段的数据
CODE:
[root@dns1 bob]# rrdtool graph 1.png /
> --start now-2h / # 规定时间为2 小时内
> DEF:value1=eth0.rrd:eth0_in:AVERAGE:end=now:start=end-1h / # 规定时间为1 小时内
> DEF:value2=eth0.rrd:eth0_out:AVERAGE / # 没有指定 :start 和 :end ,默认和 –-start 一样也是2 小时
> AREA:value1#00ff00:in /
> LINE2:value2#ff0000:out:STACK
475x168
[root@dns1 bob]#
实例7 :把一段时间分为几段分别显示 :
CODE:
[root@dns1 bob]# rrdtool graph 1.png /
> DEF:value1=eth0.rrd:eth0_in:AVERAGE:end=now:start=end-1h / # 当前1 小时内
> DEF:value2=eth0.rrd:eth0_in:AVERAGE:end=now-1h:start=now-2h / # 2 小时前
> DEF:value3=eth0.rrd:eth0_in:AVERAGE:end=now-2h:start=now-3h / # 3 小时前
> LINE1:value1#00ff00:"1 hours ago" /
> LINE2:value2#ff0000:"2 hours ago" /
> LINE3:value3#000000:"3 hours ago"
475x168
[root@dns1 bob]
我们把3 个小时内的数据用三种不同粗细、不同颜色的曲线画了出来。
看到了吗,out 部分(红色)显示了2 个小时内的流量,而in 部分(绿色)则只显示了1 个小时内的部分
在这里要提一点,虽然我们指定了 –-start 或者 –-end , 或者 :start , :end ,但并不意味着曲线就一定会从指定的时间点开始和结束。
例如我们上面指定了 :start=now-600:end=now-300 ,也就是只显示5 分钟的数据。但图表出来的效果却是10(10:05-10:15) 分钟
的数据,这是因为我们挑选的时间当中“ 不慎” 横垮了两个周期(10:05-10:10,10:10-10:15) ,所以 RRDtool 会把它们全部画出来,而不是只画其中的5 分钟。