RRDtool运用

一、建立RRD数据库(.rrd文件)
[root@d-1701 bin]# ./rrdtool
RRDtool 1.2.12 Copyright 1997-2005 by Tobias Oetiker <tobi@oetiker.ch>
Compiled Feb 6 2006 10:33:43
Usage: rrdtool [options] command command_options
Valid commands: create, update, updatev, graph, dump, restore,last, first, info, fetch, tune, resize, xport
RRDtool is distributed under the Terms of the GNU General
Public License Version 2. (www.gnu.org/copyleft/gpl.html)
For more information read the RRD manpages
从以上可以看出,使用方法就是:
rrdtool [options] command command_options
而commands包括:
create, update, updatev, graph, dump, restore,last, first, info, fetch, tune, resize, xport
这一讲我们将着重介绍一下creat命令的使用

rrdtool create filename
[--start|-b start time]
[--step|-s step]
[DS:ds-name:DST:heartbeat:min:max]
// DS:ds-name:GAUGE | COUNTER | DERIVE | ABSOLUTE:heartbeat:min:max
[RRA:CF:xff:steps:rows]
我们用一个官方例子对整个语法进行解释(以下都用这个例子说明参数的使用):
rrdtool create target.rrd
--start 1023654125
--step 300
DS:mem:GAUGE:600:0:671744
RRA:AVERAGE:0.5:12:24
RRA:AVERAGE:0.5:288:31
简单的先说吧:
create 很容易理解,就是创建一个新的Round Robin Database (RRD) 数据库文件以存储信息。
filename习惯上会以 .rrd 结尾,请记住这个数据库文件的名字。
--start 这个参数可以指定 filename 的数据记录起始日期,你可以指定为 1970 年至今的秒数(参数为-b `date -d "1970/01/01" +%s`),如果你不指定,那么起始时间默认就是现在。
--step 采集数据的间隔时间,习惯上我们会设 300 (秒),当然你可以自行调整,这也是RRD的优势所在。但是采集周期不应该过短也不应小于你的update rrd文件周期,否则可能会造成服务器负载过重。

原文相关对照:
This example creates a database named target.rrd. Start time (1023654125) is specified in total number of seconds since epoch (time in seconds since 01-01-1970). While updating the 
database, update time is also specified. This update time MUST occur after start time and MUST be in seconds since epoch.
The step of 300 seconds indicates that database expects new values every 300 seconds. The wrapper script should be scheduled to run every step seconds so that it updates the database 
every step seconds.

后面两个参数需要慢慢理解,我把语法和例子拿下来对比一下,大家就可能明白了。
[DS:ds-name:DST:heartbeat:min:max]
// DS:ds-name:GAUGE | COUNTER | DERIVE | ABSOLUTE:heartbeat:min:max
对比例子
DS:mem:GAUGE:600:0:671744
下面以例子来说明:
DS:用来声明数据源的,也可以理解为声明数据变量的关键字。这个是必须写的,不能按照你的意愿修改成其他表述方式。
官方英文解释是这样的:
DS (Data Source) is the actual variable which relates to the parameter on the device that has to be monitored.
DS-NAME:变量名,可以理解为你给这个数据源起的助记符(简称DSN)。当每一个刷新周期到来的时候,数据文档中各变量对应的值就会被更新。这个变量对应的值在官方文档中也叫做主要数据点――PDP(Primary Data Point)。
DST:DS的类型,通常有:GAUGE, COUNTER, DERIVE, 和ABSOLUTE 四种,下面依次介绍:
GAUGE:
我们用的最多的就是GAUGE了,它的中文解释是:测量。在这里它表示实际的值。比如说输入次序为98 100 98,那么输出顺序也是98 100 98。
COUNTER:
累计值,自己进行计算,比如说输入次序为98 100 98,那么输出顺序也是2 -2,怎么出来的这两个数值呢?100-98 98-100,其实就是两个差值,它表示的是经过一个刷新周期的变化率。
DERIVE:
也是累计值,和COUNTER一样的,唯一不同的是它不存在负值,最小的是0,不如-2那么它就只划0,结果为 2 0
ABSOLUTE:
如同COUNTER,但COUNTER可能overflow(数值过大),所以会取绝对值
补充:COUNTER/DERIVE/AVSOLVTE 虽然都是取差值,但会再除以两次间隔间的秒数。
例,两次间隔间为300秒,那画出来的就是 2/300,-2/300 的值

下面给出官方英文解释:
COUNTER will save the rate of change of the value over a step period. This assumes that the value is always increasing (difference between last two values is more than 0). Traffic counters on
 a router is an ideal candidate for using COUNTER as DST.

DERIVE is same as COUNTER but it allows negative values as well. If you want to see the rate of change in free diskspace on your server, then you might want to use the DERIVE data type.

ABSOLUTE also saves the rate of change but it assumes that previous value is set to 0. The difference between current and previous value is always equal to the current value. So, it stores
 the current value divided by step interval (300 seconds in our example).

GAUGE does not save the rate of change. It saves the actual value itself. There are no divisions/calculations. Memory consumption in a server is an ideal example of gauge.

再给出一个例子帮助大家理解:

Values = 300, 600, 900, 1200 实际值输入值(每隔300S输入一个)
Step = 300 seconds 刷新周期
COUNTER DS = 1, 1, 1, 1 COUNTER定义的DS的值
DERIVE DS = 1, 1, 1, 1 DERIVE定义的DS的值
ABSOLUTE DS = 1, 2, 3, 4 ABSOLUTE定义的DS的值
GAUGE DS = 300, 600, 900, 1200 GAUGE定义的DS的值

heartbeat 心跳有效期
比 如在例子中,我们定义了心跳有效时间是600秒,也就是两个刷新周期。举个例子,在12点的时候没有产生数据,那么前后300S(共600S)的平均值就 会绘成12点的值,但如果在两个刷新周期内,都没有接收到数据更新,那么这个时候,必须往数据文档中写入一个(UN)UNKNOWN值。这是  RRDTool的一个特别的地方。要知道MRTG在处理网络中断的时候,记录的是0值。这个0和UN还是有一定区别的。

官方原文如下:
In our example, heartbeat is 600 seconds. If database does not get a new PDP within 300 seconds, it will wait for another 300 seconds (total 600 seconds). If it doesnt receive any PDP with in 
600 seconds, it will save an UNKNOWN value into database. This UNKNOWN value is a special feature of RRDTool - it is much better than to assume a missing value was 0 (zero). For example,
the traffic flow counter on a router keeps on increasing. Lets say, a value is missed for an interval and 0 is stored instead of UNKNOWN. Now when next value becomes available, it will 
calculate difference between current value and previous value (0) which is not correct. So, inserting value UNKNOWN makes much more sense here.

min:max 记录数据的最小值和最大值
DS数值的有效范围,超出就是UN喽。也可以写成 U:U 代表不限范围。
小技巧:将数据源建立方式记为 "三文字,三数字"

DS讲完了就该讲RRA了,那么什么是RRA呢?
RRA: 更简单,它的作用就是定义更新的数据是如何记录的,RRA 即 Round Robin Archive,Archive是什么,存档。比如我们每5分钟 产生一条刷新的数据,那么一个小时就是12条。每天就是288条。这么庞大的数据量,一定不可能都存下来。肯定有一个合并(consolidate)数据 的方式,那么这个就是RRA的作用了。
下面具体介绍怎么应用RRA:
使用方法:RRA:AVERAGE | MIN | MAX | LAST:xff:steps:rows
RRA:用以声明RRAs的关键字
CF:consolidation function 合并方式,包含四类:
AVERAGE, MIN,MAX, LAST //平均值,最大值,最小值,最后一笔
上面说过了,经过一个刷新周期,会获得一个主数据点(PDP),将若干个PDPs使用合并方式(CF)合并后会产生一个合并数据点CDP(consolidated data point)。
xff:xfiles factor 和unkown数据有关,很多资料都取0.5
step:有step条PDP合并形成一条CDP
row:记录的合并数据点CDP条数
对应官方的描述为:
RRA is the keyword to declare RRAs. The consolidation function (CF) can be AVERAGE, MINIMUM, MAXIMUM, and LAST. The concept of the consolidated data point (CDP) comes into the 
picture here. A CDP is CFed (averaged, maximum/minimum value or last value) from step number of PDPs. This RRA will hold rows CDPs.

我们在例子中对RRA是这样定义的:
RRA:AVERAGE:0.5:12:24 //1天
RRA:AVERAGE:0.5:288:31 //1月
对 于第一个RRA,12条的PDP(每经过一个刷新周期产生一个PDP)经过CFed(AVERAGE),也就是取平均值,产生一个CDP,24个  CDPs存档。我们一起来计算一下时间,如果一个周期是300秒,那么12个PDP的产生时间就是一个小时,也就是一个小时产生一个CDP。24个  CDPs时间就是一天。说明这条通过这条RRA,我们可以取得一天的数据值。一天后,又经过一个小时。就会产生第25条,那么如何记录这个第25条数据 呢?根据我们这个RRA的定义,它将会替代第一条CDP的位置。我们通过下面这个图来说明:


实例(检测某核心交换的端口)(create_nic_7609.sh)
/usr/local/rrd/bin/rrdtool create /www/rrd/NIC_7609.rrd -s 300 \
DS:ifInOctets1:COUNTER:600:U:U \
DS:ifInOctets2:COUNTER:600:U:U \
DS:ifInOctets9:COUNTER:600:U:U \
DS:ifInOctets11:COUNTER:600:U:U \
DS:ifInOctets14:COUNTER:600:U:U \
DS:ifInOctets53:COUNTER:600:U:U \
DS:ifOutOctets1:COUNTER:600:U:U \
DS:ifOutOctets2:COUNTER:600:U:U \
DS:ifOutOctets9:COUNTER:600:U:U \
DS:ifOutOctets11:COUNTER:600:U:U \
DS:ifOutOctets14:COUNTER:600:U:U \
DS:ifOutOctets53:COUNTER:600:U:U \
RRA:AVERAGE:0.5:1:4800 \
RRA:AVERAGE:0.5:6:2400 \
RRA:AVERAGE:0.5:24:1200 \
RRA:AVERAGE:0.5:288:600 \
RRA:MAX:0.5:1:4800 \
RRA:MAX:0.5:6:2400 \
RRA:MAX:0.5:24:1200 \
RRA:MAX:0.5:288:600


我们举例来看
RRA:AVERAGE:0.5:1:603 \
RRA:AVERAGE:0.5:6:603 \
RRA:AVERAGE:0.5:24:603 \
RRA:AVERAGE:0.5:288:800 \
RRA:MAX:0.5:1:603 \
RRA:MAX:0.5:6:603 \
RRA:MAX:0.5:24:603 \
RRA:MAX:0.5:288:800
解释一下,首先你要记得step我们设置为300秒,那么
0.5:1:603
因为我们将step设置为300秒,若原计算时间点为12:00,记录时11:57:30~12:02:30的平均值为主,这个值若在此时间点內只有一笔资料的话,其意即是平均值,所以此一值即表共要记录几笔,603是指要存603笔,超過603筆,則最早一笔將被移出。
0.5:6:603 仅就6解释,取6笔资料(每笔为step值,在此意即5分钟)为平均值( 30 分钟), 存 603 笔
0.5:24:603 24 即2小時
0.5:288:800 288 即1天
请 注意,不是0.5:1:603中的1 就是五分钟,这个是依据你的--step值而定,如果--step 3600,那0.5:6:603这一行就是六小 时合起來的平均值了。若将 AVERAGE 换成MIN/MAX 的意义则是取该时间点中 (如上例之5min/30min/2hr..)之最大值或最小 值,而通常在监测系统时最大值与平均值是比较有实际意义的。下面这个图来帮助你记忆。

RRA:MIN:0.5:1:600 \
RRA:MIN:0.5:6:700 \
RRA:MIN:0.5:24:775 \
RRA:MIN:0.5:288:797 //一般可按cacti标准取值

rrdtool第二讲

第二讲:rrd数据的更新(update)
原档:http://cacti.linuxmine.com/viewtopic.php?p=85#85
在 创建好文档后,我们要用程序定时更新数据文档(.rrd)然后才能根据数据文档画图。以采集核心交换流量为例,首先我们要抓到各端口的流量,可以通过  snmp协议来取得数据。如果你机器上没有snmp,那么安装最新的net-snmp包,安装完成后测试snmp,在提示符下键入:
$ snmpwalk
No hostname specified.
Usage: snmpwalk [options...] <hostname> {<community>} [<objectID>]
UCD-snmp version: 5.1.2
-h this help message.
-H Display configuration file directives understood.
-V display version number.
-v 1|2c|3 specifies snmp version to use.
SNMP Version 1 or 2c specific
……
出现以上信息表示net-snmp安装成功。
snmp的使用:
# snmpwalk -v 2c 核心交换IP地址 设备的community_string OID
具体的snmp用法及系统默认的OID还有Shell文件的执行方法可参考 cacti 中文论坛 的相关文档,这里我就不废话了。我们这一讲将主要说说如何更新rrd文件信息。

语法:
rrdtool{update|updatev} filename [--template|-t ds-name[:ds-name]...] N|timestamp:value[:value...] at-timestamp@value[:value...] [timestamp:value[:value...] ...]
例如:
$ rrdtool update tcpdump.rrd 1061811856:114:0:50:1199:0:821073
上面的 1061811856 即时间值,如果就是要现在的时间值,可以 N 代表,但要转换成秒值,通常我們都会用
$ timestamp=`date +%s `
来转现在秒数,如果是某些特定时间,则可以
$ timestamp=`date -d "2003/08/15 12:00" +%s`
后面跟着所有的更新的数据,按照DS定义的顺序用冒号格开。
关 于更新的数据需要你写个小程式取数据,或用snmpget/snmpwalk抓资料来做rrdtool update,然后用crontab根据你在  rrdtool create 时的step决定执行的时间点。这里就应该用到shell的知识了,最常见的就是用Shell的正则表达式过滤通过 snmp取得的信息
我们看到了,通过snmp取得的核心交换的信息是非常之多的,这些信息当然不可能都用到,我们要从中选取我们要的信息。我们使用正则表达式对字符流进行过滤并排列成我们需要的方式。
对于正则表达式,这里不做解释,大家可以通过参考一些书辅助一些例子学习。
我们要取得的是端口的流入和流出的数据,所以我们使用snmp中的两个选项:ifInOctets和ifOutOctets 。分别对应的是端口的流入流量和流出流量。
特 别地,对于采集100M及其以下的端口流量,这两个参数是完全正确的,但是如果是1000M的端口,就会出现流量和实际值相差甚远。在查过很多资料后发 现,原因是这样方式的计数模式,计数字长为32bit,如果采集1000M端口数据会发生数据溢出。我们要使用64bit的字长来计数。所以我们应该选用 的OID参数为:ifHCInOctets和ifHCOutOctets。

让我们来看个例子
RRD_FILE=/www/rrd/NIC_7609.rrd (.rrd数据文档的位置)
sec=300 //睡眠时间,也就是采集周期
while [ 1 ] //用一个循环
do
rrd_data="" //下面实际用到的是正则表达式的串拼接
rrd_data =$rrd_data`snmpwalk -v 2c IP地址 -c snmp团体名  ifHCInOctets |grep ".*ifHCInOctets.1 = " | sed -e 's/.*: \(.*\)$/\1/'| tr '\n' ':'`
rrd_data =$rrd_data`snmpwalk -v 2c IP地址 -c snmp团体名  ifHCInOctets |grep ".*ifHCInOctets.2 = " | sed -e 's/.*: \(.*\)$/\1/'| tr '\n' ':'`
rrd_data =$rrd_data`snmpwalk -v 2c IP地址 -c snmp团体名  ifHCInOctets |grep ".*ifHCInOctets.9 = " | sed -e 's/.*: \(.*\)$/\1/'| tr '\n' ':'`
rrd_data =$rrd_data`snmpwalk -v 2c IP地址 -c snmp团体名 ifHCInOctets |grep ".*ifHCInOctets.11 = " | sed -e 's/.*: \(.*\)$/\1/'| tr '\n' ':'`
rrd_data =$rrd_data`snmpwalk -v 2c IP地址 -c snmp团体名  ifHCInOctets |grep ".*ifHCInOctets.14 = " | sed -e 's/.*: \(.*\)$/\1/'| tr '\n' ':'`
rrd_data =$rrd_data`snmpwalk -v 2c IP地址 -c snmp团体名  ifHCInOctets |grep ".*ifHCInOctets.53 = " | sed -e 's/.*: \(.*\)$/\1/'| tr '\n' ':'`
rrd_data =$rrd_data`snmpwalk -v 2c IP地址 -c snmp团体名  ifHCOutOctets |grep ".*ifHCOutOctets.1 = " | sed -e 's/.*: \(.*\)$/\1/'| tr '\n' ':'`
rrd_data =$rrd_data`snmpwalk -v 2c IP地址 -c snmp团体名  ifHCOutOctets |grep ".*ifHCOutOctets.2 = " | sed -e 's/.*: \(.*\)$/\1/'| tr '\n' ':'`
rrd_data =$rrd_data`snmpwalk -v 2c IP地址 -c snmp团体名  ifHCOutOctets |grep ".*ifHCOutOctets.9 = " | sed -e 's/.*: \(.*\)$/\1/'| tr '\n' ':'`
rrd_data =$rrd_data`snmpwalk -v 2c IP地址 -c snmp团体名  ifHCOutOctets |grep ".*ifHCOutOctets.11 = " | sed -e 's/.*: \(.*\)$/\1/'| tr '\n' ':'`
rrd_data =$rrd_data`snmpwalk -v 2c IP地址 -c snmp团体名  ifHCOutOctets |grep ".*ifHCOutOctets.14 = " | sed -e 's/.*: \(.*\)$/\1/'| tr '\n' ':'`
rrd_data =$rrd_data`snmpwalk -v 2c IP地址 -c snmp团体名  ifHCOutOctets |grep ".*ifHCOutOctets.53 = " | sed -e 's/.*: \(.*\)$/\1/'| tr '\n' '\0'`

now=`date +%s` //当前时间距离1970的秒数
/usr/local/rrd/bin/rrdtool update $RRD_FILE $now:${rrd_data} //调用更新指令
sh ./NIC_7609_Graph.sh //调用绘图脚本画图,下面一节就介绍
sleep $sec //休息,等待下一个周期的到来
done //循环体结束

[补充]如果你得到了如下提示:
IF-MIB::ifHCInOctets = No Such Object available on this agent at this OID
有可能你的网卡是100M,那么就用ifOutOctets来测试就可以了。

rrdtool第三讲:画图

画图的语法很多,我只把最有用的列出来,有兴趣的朋友可以到官方网站上去查Manual。
方法:rrdtool graph image-filename,参数介绍如下
image-filename:图的文件名,比如test.png等
[-s|--start seconds]:绘图起始时间,预设是一天前(-1d),可用-s `date …`来指定时间
[-e|--end time]:绘图结束时间, 预设是现在(now),除date 的应用外,可用 -e -1w 表示绘图的时间结束于一周前
[-t|--title title]:图上显示的标题
[-v|--vertical-label text]:Y轴上的说明文字
[-w|--width pixels]:绘图区域,画图区宽的大小
[-h|--height pixels]:绘图区域,画图区高的大小
-u:Y轴正值高度
-l:Y轴负值高度
--no-minor 不要副格线
画图的配套参数就介绍这么多,我们要把重点放在图的数据变量的描述和画图具体过程上面。
DEF(Define):就是定义一个变量
语法:
DEF:vname=rrd_filename:DS_name:CF
用如下表示更清楚一些
DEF:vname=rrd_filename:DS_name:[AVERAGE|MAX..]
主要用处在于您要取出哪个 RRD 档案的 DSN 到这个 graph 來。
从上很容易看出,你要定义一个虚拟的变量,变量从(.rrd)数据文件中取得数据源(DS)经过数据合并(CF)后的数据。看到这里,大家应该知道,前面在定义文档中为什么有那么多的参数,其实都是为了绘图做准备的。
① vname:虚拟变量名,我们自己取的,以后还要用到。
② rrd_filename:DS_name:CF :数据文件(.rrd)的全路径->数据源变量->合并方法。
举个例子吧:DEF:in_bytes_1=$RRD_PATH:ifInOctets1:AVERAGE
官方解释为:
Define virtual name for a data source. This name can then be used in the functions explained below. The DEF call automatically chooses an RRA which contains CF consolidated data in a 
resolution appropriate for the size of the graph to be drawn. Ideally this means that one data point from the RRA should be represented by one pixel in the graph. If the resolution of the RRA
is higher than the resolution of the graph, the data in the RRA will be further consolidated according to the consolidation function (CF) chosen.
然而,我们觉得光有记录的数据源变量还是不够的,我们希望这些数据源变量可以计算。比如我希望把某两个端口的流量加在一起作为一个变量画图,那么这是我们就需要CDEF

CDEF 一個虚拟的变数,其值为 DEF 的某些运算,语法如下:
语法:CDEF:vname=rpn-expression
先举一个例子,我们从例子中说明问题。我们取得某端口流入流量的字节数,我们希望画在图上的是bit为单位,很明显我们要将字节数乘以8。
例:
DEF:in_bytes_1=$RRD_PATH:ifInOctets1:AVERAGE //这句刚刚说过了
CDEF:in_bits_1= 8,in_bytes_1,* //将DEF中定义的in_bytes_1×8放在in_bits_1
很好理解吧?那为什么不写成in_bits_1= in_bytes_1* 8?现在我们回到语法解释:
rpn(Reverse Polish Notation)逆波兰表达式,它的语法规定,表达式必须以逆波兰表达式的方式给出。那么什么是逆波兰表达式呢?逆波兰表达式又叫做后缀表达式。这个知识点在数据结构和编译原理这两门恐怖的课程中都有介绍,下面是一些例子:
正常的表达式 逆波兰表达式
a+b a,b,+
a+(b-c) a,b,c,-,+
a+(b-c)*d a,d,b,c,-,*,+
那么a=1+3 就写成 a=1,3 +了。
http=(smtp+http+telnet)/1024 写成什么呢?
http=1024,smtp,http,telnet,+,+,/
下面终于到画图了,最常用的是:线和区域,什么是线什么是区域呢?看这个图:

从图中可以看出有两种表示流量的方式,流入用绿色的区域(AREA),流出用蓝色的线(LINE)。这就是画图的几个元素。我们还是先看一下语法。
AREA:vname[#rrggbb[:legend]]
LINE{1|2|3}:vname[#rrggbb[:legend]]
STACK:vname[#rrggbb[:legend]]
① vname:根据虚拟变量(vname)画图。
② #rrggbb:颜色的16进制表示,可以找个软件来看。
③ legend:对该颜色的提示,最后会写在图上的。
④ 特别的,画线有粗细之分,所以有LINE1-LINE3,line1最细,LINE3最粗。
⑤ AREA 可以画出资料数值至0之间的区块图
⑥ STACK 是表现在的图的值,叠在上一个值上
例子:
AREA:in_bits_1#00cc00: " Current In"
LINE1:out_bits_1#0000ff: " Current Out "
请注意,如果使用 AREA/STACK 则需特別注意图盖图的问题,一定要先画大的值, 再画小的值,才会有层次的效果,不然,最大的数据若最后画,你就看不到前面的值了,都被最后一个图给压过去了。
关于图下面的提示怎么画呢?我们必须使用这两条指令GPRINT和COMMENT
语法:
GPRINT:vname:CF:format
COMMENT:text
没有什么难点,有点像C语言的表达式,举两个例子大家就会很好理解的。例:
COMMENT: "Hello World .\c " 以居中的方式显示Hello world
GPRINT:in_bits_1:AVERAGE:"Average Current\:%8.2lf %S bps"
//显示in_bits_1的值,精确到小数点后面两位
这些说明性文字都可以用 \n 等换行符号
例如:
GPRINT:telnet:AVERAGE:"%10.0lf \n"
意即要输出这段时间中 (-s ~ -e 中,telnet的平均值,%10.0lf 则是为了好算位置)

例子1:
#tcpdump.sh
RRD_PATH="/root/study/tcpdump.rrd"
image_path="/root/study/html"
sec=300
killall tcpdump
mv ip.packet ip.packet.1
tcpdump -w ip.packet tcp or udp or icmp &
scan_port="23 25 53 80 110"
rrd_data=""
for sport in $scan_port
do
port=`tcpdump -r ip.packet.1 port $sport -v | sed -e 's/.*, len \(.*\))/
\1/g' | tr '\n' '+'`
port=`echo ${port}0| bc`
port=`expr $port / $sec`
rrd_data="$rrd_data$port:"
done
total=`tcpdump -r ip.packet.1 -v |grep -v 'config'| sed -e 's/.*, len \(.*\))/\
1/g' | tr '\n' '+'`
total=` echo ${total}0 | bc`
now=`date +%s`
echo "rrdtool update tcpdump.rrd $now:$rrd_data$total" >>tcpdump.cmd
rrdtool update tcpdump.rrd $now:$rrd_data$total

image_path=/home/httpd/html/enum/study
now=`date "+%Y/%m/%d %H:%M:%S"`
start_time=`date -d "2003/08/12 19:00" +%s`
time="hour day week month year"
for t in $time
do
/usr/local/bin/rrdtool graph $image_path/example-$t.png \
--title "本機重要 port 流量" \
DEF:t1=$RRD_PATH:telnet:AVERAGE \
DEF:t2=$RRD_PATH:smtp:AVERAGE \
DEF:t3=$RRD_PATH:domain:AVERAGE \
DEF:t4=$RRD_PATH:http:AVERAGE \
DEF:t5=$RRD_PATH:total:AVERAGE \
CDEF:v1=t1,t2,t3,t4,+,+,+ \
CDEF:v2=t1,t2,t3,+,+ \
CDEF:v3=t1,t2,+ \
CDEF:v4=t1 \
CDEF:v5=t5,1024,/ \
COMMENT:"各 PORT 流量統計---最大------平均-------最小-------?#123;在\n" \
AREA:v1#339966:"HTTP" \
GPRINT:t4:MAX:" %12.0lf " \
GPRINT:t4:AVERAGE:"%12.0lf " \
GPRINT:t4:MIN:"%12.0lf " \
GPRINT:t4:LAST:"%12.0lf \n" \
AREA:v2#ffff00:"DNS" \
GPRINT:t3:MAX:" %12.0lf " \
GPRINT:t3:AVERAGE:"%12.0lf " \
GPRINT:t3:MIN:"%12.0lf " \
GPRINT:t3:LAST:"%12.0lf \n" \
AREA:v3#FF0000:"SMTP" \
GPRINT:t2:MAX:" %12.0lf " \
GPRINT:t2:AVERAGE:"%12.0lf " \
GPRINT:t2:MIN:"%12.0lf " \
GPRINT:t2:LAST:"%12.0lf \n" \
AREA:v4#0000ff:"TELNET" \
GPRINT:t1:MAX:" %12.0lf " \
GPRINT:t1:AVERAGE:"%12.0lf " \
GPRINT:t1:MIN:"%12.0lf " \
GPRINT:t1:LAST:"%12.0lf \n" \
LINE2:v5#000000:"全部(Kb)" \
GPRINT:v5:MAX:" %12.0lf " \
GPRINT:v5:AVERAGE:"%12.0lf " \
GPRINT:v5:MIN:"%12.0lf " \
GPRINT:v5:LAST:"%12.0lf \n" \
COMMENT:"\n" \
COMMENT:"\n" \
COMMENT:" Last Updated: $now" \
-v "per second (bytes)" -M -U 10 \
-Y -X b -h 200 -w 480 -s `date -d "-1 $t" +%s`
done

例子2(NIC_7609_Graph.sh):
绘图的时候,我们还特别画出了采集端口的日流量、周流量、月流量和年流量。配合Shell脚本的使用,可以达到很好的效果。

image_path=/www/web/nicimages
RRD_PATH=/www/rrd/FJNUNIC_7609.rrd
port="1 2 9 11 14 53" #端口列表
for p in $port #对每个端口的循环
do
DEFin="DEF:in_bytes_$p=$RRD_PATH:ifInOctets$p:AVERAGE"
DEFout="DEF:out_bytes_$p=$RRD_PATH:ifOutOctets$p:AVERAGE"
CDEF="CDEF:in_bits_$p=8,in_bytes_$p,* CDEF:out_bits_$p=8,out_bytes_$p,*"
ddate=`date` #取得当前日期
#以下流入
DRAW_IN="COMMENT:\"Last updated time : $ddate\c\"" #最后更新
DRAW_IN="${DRAW_IN} COMMENT:\"\n\"" #换行
DRAW_IN="${DRAW_IN} AREA:in_bits_$p#00cc00:\" Current In \n\" " #流入流量
DRAW_IN="${DRAW_IN} COMMENT:\" \" GPRINT:in_bits_$p:LAST:\"Last Current\:%.2lf%S bps\"" #流入当前流量文字提示
DRAW_IN="${DRAW_IN}GPRINT:in_bits_$p:AVERAGE:\"Average Current\:%.2lf%S bps\"" #流入平均流量文字提示
DRAW_IN="${DRAW_IN} GPRINT:in_bits_$p:MAX:\"Max Current\:%.2lf%S bps\n\""
#流入最大流量文字提示

#以下流出
DRAW_OUT="LINE1:out_bits_$p#0000ff:\" Current Out\n\" " #流出流量
DRAW_OUT="${DRAW_OUT}COMMENT:\" \" GPRINT:out_bits_$p:LAST:\"Last Current\:%.2lf%S bps\"" #流出当前流量文字提示
DRAW_OUT="${DRAW_OUT}GPRINT:out_bits_$p:AVERAGE:\"Average Current\:%.2lf%S bps\"" #流出平均流量文字提示
DRAW_OUT="${DRAW_OUT} GPRINT:out_bits_$p:MAX:\"Max Current\:%.2lf%S bps\n\"" #流出最大流量文字提示
ttime="d w m y" #时间列表;d日;w周;m月;y年
for t in $ttime #对每个时间循环
do
sec=`date -v-1$t +%s` #绘图起始时间的确定
cmd="/usr/local/rrd/bin/rrdtool graph \
$image_path/FJNUNIC_7609_IF${p}_${t}.png \
--title '${ttitle}' \
-v ' Bits Per Second' \
-s $sec \
-l 0 -h 150 -w 500 $DEFin $DEFout $CDEF $DRAW_IN $DRAW_OUT
--color CANVAS#ffffff
--color BACK#ffffff \
--color FONT#000000 \
--color MGRID#80C080 \
--color GRID#808020 \
--color FRAME#808080 \
--color ARROW#ff0000 \
--color SHADEA#404040 \
--color SHADEB#404040"
eval $cmd # 执行画图
done #时间循环结束
done #端口循环结束 
posted @ 2010-02-04 17:14  留心_frankliujava  阅读(9933)  评论(0编辑  收藏  举报