在FreeBSD用RRD监控网络流量

时间:2007-06-03 17:50:29   来源:明水轩工作室  作者:  点击:次  出处:技术无忧
关键字:MRTG RRD 监控 网络流量


4.实例(检测某核心交换的端口)(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

五、数据的更新(update)

在创建好文档后,我们要用程序定时更新数据文档(.rrd)然后才能根据数据文档画图。以采集核心交换流量为例,首先我们要抓到各端口的流量,我们可以通过snmp协议来取得数据。

1.在FreeBSD上以Port方式安装net-snmp
$ cd /usr/ports/net-mgmt/p5-SNMP
$ make install clean
会让你填一些email 操作系统的资料,直接回车就可以了。

测试snmp是否安装成功,在提示符下键入:
$ snmpwalk
No hostname specified.
Usage: snmpwalk [options...] <hostname> {<community>} [<objectID>]
UCD-snmp version: 4.2.6
-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安装成功。

2.snmp的使用
$ snmpwalk -v 2c 核心交换IP地址 设备的community_string

3.数据文档的更新

语法:rrdtool update filename [--template|-t ds-name[:ds-name]...] N|timestamp:value[:value...] [timestamp:value[:value...] ...]

第一个参数为当前时间值(秒累计),后面把所有的更新的数据,按照DS定义的顺序用冒号格开。

4.用Shell的正则表达式过滤通过snmp取得得信息

我们看到了,通过snmp取得的核心交换的信息是非常之多的,这些信息当然不可能都用到,我们要从中选取我们要的信息。我们使用正则表达式对字符流进行过滤并排列成我们需要的方式。
对于正则表达式,这里不做解释,大家可以通过参考一些书辅助一些例子学习。
我们要取得的是端口的流入和流出的数据,所以我们使用snmp中的两个选项:ifInOctets和ifOutOctets 。分别对应的是端口的流入流量和流出流量。
特别地,对于采集100M及其以下的端口流量,这两个参数是完全正确的,但是如果是1000M的端口,就会出现流量和实际值相差甚远。在查过很多资料后发现,原因是这样方式的计数模式,计数字长为32bit,如果采集1000M端口数据会发生数据溢出。我们要使用64bit的字长来计数。所以我们应该选用的OID参数为:ifHCInOctets和ifHCOutOctets。

5.实例(NIC_7609.sh)

综合4和5我们一起来看一个实例,这个实例是配合第四点的实例中的DS定义的更新脚本。

RRD_FILE=/www/rrd/NIC_7609.rrd (.rrd数据文档的位置)
sec=300 #睡眠时间,也就是采集周期

while [ 1 ] #用一个死循环,呵呵
do
rrd_data="" #下面实际用到的是正则表达式的串拼接
rrd_data=$rrd_data`snmpwalk -v 2c IP地址 snmp团体名 ifHCInOctets |grep ".*ifHCInOctets.1 = " | sed -e 's/.*: \(.*\)$/\1/'| tr '\n' ':'`
rrd_data=$rrd_data`snmpwalk -v 2c IP地址 snmp团体名 ifHCInOctets |grep ".*ifHCInOctets.2 = " | sed -e 's/.*: \(.*\)$/\1/'| tr '\n' ':'`
rrd_data=$rrd_data`snmpwalk -v 2c IP地址 snmp团体名 ifHCInOctets |grep ".*ifHCInOctets.9 = " | sed -e 's/.*: \(.*\)$/\1/'| tr '\n' ':'`
rrd_data=$rrd_data`snmpwalk -v 2c IP地址 snmp团体名 ifHCInOctets |grep ".*ifHCInOctets.11 = " | sed -e 's/.*: \(.*\)$/\1/'| tr '\n' ':'`
rrd_data=$rrd_data`snmpwalk -v 2c IP地址 snmp团体名 ifHCInOctets |grep ".*ifHCInOctets.14 = " | sed -e 's/.*: \(.*\)$/\1/'| tr '\n' ':'`
rrd_data=$rrd_data`snmpwalk -v 2c IP地址 snmp团体名 ifHCInOctets |grep ".*ifHCInOctets.53 = " | sed -e 's/.*: \(.*\)$/\1/'| tr '\n' ':'`
rrd_data=$rrd_data`snmpwalk -v 2c IP地址 snmp团体名 ifHCOutOctets |grep ".*ifHCOutOctets.1 = " | sed -e 's/.*: \(.*\)$/\1/'| tr '\n' ':'`
rrd_data=$rrd_data`snmpwalk -v 2c IP地址 snmp团体名 ifHCOutOctets |grep ".*ifHCOutOctets.2 = " | sed -e 's/.*: \(.*\)$/\1/'| tr '\n' ':'`
rrd_data=$rrd_data`snmpwalk -v 2c IP地址 snmp团体名 ifHCOutOctets |grep ".*ifHCOutOctets.9 = " | sed -e 's/.*: \(.*\)$/\1/'| tr '\n' ':'`
rrd_data=$rrd_data`snmpwalk -v 2c IP地址 snmp团体名 ifHCOutOctets |grep ".*ifHCOutOctets.11 = " | sed -e 's/.*: \(.*\)$/\1/'| tr '\n' ':'`
rrd_data=$rrd_data`snmpwalk -v 2c IP地址 snmp团体名 ifHCOutOctets |grep ".*ifHCOutOctets.14 = " | sed -e 's/.*: \(.*\)$/\1/'| tr '\n' ':'`
rrd_data=$rrd_data`snmpwalk -v 2c IP地址 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 #循环体结束

六、数据绘图

语法很多 ,不可能一一罗列,有兴趣的可以到官方网站上去查Manual这里提供一些常用的。

常用语法:rrdtool graph filename 图的文件名
[-s|--start seconds] 绘图起始时间距离1970的秒数
[-t|--title title] 图上显示的标题
[-v|--vertical-label text] Y轴上的说明文字
[-w|--width pixels] [-h|--height pixels] 绘图区域,注意哦,是画图区宽和高

画图的配套参数就介绍这么多,我们要把重点放在图的数据变量的描述和画图具体过程上面。

1.DEF(Define)就是定义一个变量

语法:DEF:vname=rrd:ds-name:CF

很容易看出来,这是定义一个虚拟的变量,变量从(.rrd)数据文件中取得数据源(DS)经过数据合并(CF)后的数据。看到这里,大家应该知道,前面在定义文档中为什么有那么多的参数,其实都是为了绘图做准备的。

① vname:虚拟变量名,我们自己取的,以后还要用到。
② rrd: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

2.CDEF

语法: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,-,*,+

其实画图似乎用不到这么复杂的表达式,还有不懂的就只有翻看相关的书籍了。

3.画图(最常用的是:线、区域)

从图中可以看出有两种表示流量的方式,流入用绿色的区域(AREA),流出用蓝色的线(LINE)。这就是画图的几个元素。我们还是先看一下语法。

语法:AREA:vname[#rrggbb[:legend]]
LINE{1|2|3}:vname[#rrggbb[:legend]]

① vname:根据虚拟变量(vname)画图。
② #rrggbb:颜色的16进制表示,用过firework就很熟悉喽
③ legend:该颜色的提示
④ 特别的,画线有粗细之分,所以有LINE1-LINE3

例子:AREA:in_bits_1#00cc00: " Current In"
LINE1:out_bits_1#0000ff: " Current Out "

4.零零碎碎的提示

都希望图下面给点提示,比如最大流量,平均值,等等。那么我们就必须使用这两条指令GPRINT和COMMENT。

语法:GPRINT:vname:CF:format
COMMENT:text

没有什么难点,有点像C语言的表达式,举两个例子大家就会很好理解的。例:
COMMENT: "Hello World .\c " 以居中的方式显示Hello world
GPRINT:in_bits_1:AVERAGE:"Average Current\:%.2lf%S bps"
显示in_bits_1的值,精确到小数点后面两位

5.实例(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 #端口循环结束


写在最后:
本来5月底,就可以把这个文章给发了,至少和大家一块分享,结果被乱七八糟的事情给搅了。进了公司,又开始搞OpenCMS相关,一点兴趣都米有,越发郁闷了,今天终于把这篇给贴了出来。
上面代码都是实际中可以运行通过的。是自己的一些经验,希望能够和大家一同交流。本文参考了挺多Abelyang的大作,这里再次提出感谢。

有关操作系统的更多文章请进:技术无忧


文章评论

共有 0 位网友发表了评论 此处只显示部分留言 点击查看完整评论页面