Chinaunix首页 | 论坛 | 博客
  • 博客访问: 779873
  • 博文数量: 95
  • 博客积分: 6011
  • 博客等级: 准将
  • 技术积分: 1342
  • 用 户 组: 普通用户
  • 注册时间: 2008-04-12 16:58
文章分类

全部博文(95)

文章存档

2009年(44)

2008年(51)

我的朋友

分类: 服务器与存储

2009-05-08 14:48:34

如何使用RPN

**********************************************************************************************************************
注 :该教程参考了如下内容 :
A
)官方文档 :
B
abel 兄的大作 :

作者 :ailms
版本 :v1
最后修改 :2006/11/17 17:35
**********************************************************************************************************************


一)前言

RPN 
代表逆波兰式(Reverse Polish Notation)。逆波兰式最早于1920年由Jan Lukasiewicz 发明,最神奇的地方是用它来表示数学表达式,

完全不需要括号。而且 RPN 不像普通的数学表达式那样,操作符在操作数的中间,而是在操作数的右边。例如 3+2  RPN 表示就是 3,2,+ 

3+
2X5) 用 RPN 表示就是 3,2,5,x,+ 最后运算的部分(加法部分)的操作符放在最后,乘号放在前面,表示先执行 2 x 5 ,在把结果和3相加。

 RRDtool 中,RPN 还可以用来表示 if-then-else 关系。这点在绘图中很有用。例如你要看 eth0 接口在一天当中流量 ≥ 10Mb/s 的部分,隐藏

其他低于 10Mb/s 的部分,则可以用到这个功能。

二)操作符

什么是 RPN

A
RPN  Reverse Polish Notation 的缩写,是用于表示算术运算和逻辑运算的一种语法格式。

B
RRDtool  CDEF 语句中就经常使用 RPN 来对 DEF 取出来的数据进行运算。

C
RPN 的特点是操作数和操作符出现的顺序和运算的顺序一致,这样就不需要使用括号了

D
RPN 的格式是 ,, ,[,,]… 可以看出是操作数在前,操作符在后的格式

E
RPN 需要提到堆栈的概念(stack)。堆栈是用来存储操作数和操作符的。

F
)当堆栈中压入(push)一个操作符时,就从堆栈中取出(pop)所需要的操作数进行计算(根据操作的不同pop出不同数量的操作数)。
  
    
结果再返回(push)堆栈,最终整个 RPN 应该只返回一个值,或者说堆栈中只有一个元素

G
)在 CDEF 中书写 RPN 操作符,要一律以大写的格式出现

H
 RPN 中,如果某个部分的运算结果非 0,则被认为是 true ,只有 0 才被认为是 false 

三)RPN 操作符的分类

A
)布尔操作符 :GTGELTLEEQNE

B
)特殊值比较符 :UNISINF

C
)条件操作符 :IF

D
)比较操作符 :MINMAXLIMIT

E
)算术操作符 :-*/%SIN, COS, LOG, EXP, SQRTFLOOR, CEILATANATAN2DEG2RAD, RAD2DEG

F
)数据集操作符 :所谓数据集(sets),就是指多个数据。SORTREVAVGTREND

G
)特殊值 :UNKNINFNEINFPREVCOUNT

H
)时间操作符 :NOWTIMELTIME

I
)堆栈操作符 :POPDUPEXC

四)RPN 操作的结果

A
)布尔操作符 :从堆栈中 pop 出两个元素,并根据比较结果返回 0 false) 或者 1 。任何同 UNKNOWN 或者 INF NEINF 比较的都为 0

B
)特殊值比较符 :从堆栈中 pop 1个元素,并同 UNKNOWN 或者 INFNEINF 比较。结果为 0 或者 1

C
)条件操作符 :从堆栈中pop3个元素,如果最后pop出的那个元素不为0(条件部分为 true),则第2 pop 出的那个元素被重新入栈(then部分);

    
否则第一次pop出的元素重新入栈(else部分)。结果为 then 部分或者 else 部分返回的值,不一定为0或者1

D
)比较操作符 :

    
对于 MIN/MAX 操作符来说,从堆栈中 pop 出两个操作符,并把较大/小的那个重新入栈。如果其中有一个 unknown ,则结果为 unknonw

    
对于 LIMIT 操作符来说,先从堆栈中 pop 2个操作数,作为边界的定义;再 pop 1个操作数,比较该操作数是否落在前面定义的范围内。
   
    
如果是则把最后 pop 出的那个元素重新入栈;否则把 UNKN 值入栈;注意,是 UNKN ,不是 0

E
)算术操作符 :根据操作符 pop 出所需数量的操作数,并把算术运算的结果重新入栈

F
)数据集操作符 :

对于 SORTREV 来说,先从堆栈中 POP 出一个元素,该元素的值就是下面要 pop 出的元素的数量。然后对堆栈从上到下的若干个元素

由第一次 pop 的出的那个元素的值决定)进行排序/反向排序。结果再重新入栈。

注意 :由于堆栈的特点是后进先出,所以要操作的元素是从SORT操作符往左方向计数。例如v1,v2,v3,v4,3,SORT是对 v2~v4 排序,

         
不是对 v1~v3 排序。   这点在书写 RPN 时要特别注意。

注意 :SORT 操作是最小值在堆栈的最顶部;REV 则相反,最小值是在堆栈的最顶部。

对于 AVG 操作来说,同样是先 pop 1个元素,并按照指定的数量对后续的若干个操作数进行操作,但结果只有一个数值,并入栈。


G
)特殊值 :

UNKN 
表示压入一个 UNKN 值;INFNEINF 分别表示把 INFNEINF 值压入堆栈

H
)时间操作符 :

TIME 
返回当前所提取的记录的 timestamp ,注意 TIME 直接返回当前记录的 timestamp ,不用任何参数

NOW 
返回当前时间,同样 NOW 不用任何参数

I
)堆栈操作符 :

POP 
:弹出堆栈的最顶部的那个元素

   EXC 
:交换堆栈顶部的第一个和第二个元素的值

五)如何阅读 RPN

A
)首先按照从左到右的顺序,找出第一个 RPN 操作符,并根据上一节的内容,对相应的操作数进行操作

B
)操作结果分成两种 :

如果是一个值,直接替换掉该部分 RPN 

如果是多个值(数据集操作,但 AVG 操作只返回一个值),则结果可能为多个数值。则把这若干个数值用 ‘,’ 隔开,替换原来那部分 RPN 

C
)如此循环,一直到整个 RPN 只返回一个值为止

六、RPN 实例

A
)布尔型操作符 :2,1,GE 表示 2>=1 

B
)特殊值比较符 :mydata,UN 表示 mydata == UNKNOWN 

C
)条件操作符 :mydata,UN,0,mydata,IF 表示如果 mydata 等于 UNKNOWN ,则返回 0;否则还是返回 mydata 本身

D
)比较操作符 :mydata,20,MAX 表示返回 mydata20 这两个数值中较大的一个;alpha,0,100,LIMIT 表示测试 alpha 的值是否小于等于0,大于等于100

E
)算术操作符 :1,2,- 表示 1-2=-1

F
)数据集操作符 :

v1,v2,v3,v4,v5,4,SORT 
表示对 v1~v4 进行正向排序,结果堆栈中还是有5个元素;

v1,v2,v3,v4,3,AVG,+,2,/ 
表示对 v4,v3,v2 进行求平均值,并把结果入栈。假设v2~v4的结果为 k ,则为 v1,k,+,2,/ 也就是返回 (v1+k)/2

G
)特殊值 :mydata,0,GT,UNKN,mydata,IF 表示如果 mydata 大于 0则返回 UNKNOWN ,否则还是 mydata 

H
)时间操作符 : TIME,`date –d “2006-10-01 10:00” +%s`,GT,0,1,IF 表示如果当前记录的采集时间是在 2006-10-01 10:00 之后就返回1,否则返回 0

I
)堆栈操作符 :POP 就立即弹出第一个元素


七)如何表示 ANDOR 关系

A
)我们知道 RPN 表达式的值除非0,否则都认为是 true

B
)我们可以利用 加法操作和乘法操作来实现 OR  AND 的逻辑关系;如果两个 RPN 表达式的值相加不等于0,就一定为 true 

    
如果两个 RPN 表达式的值相乘不等于0,就一定为 true

C
AND 关系的例子 :例如要比较某个值(159)是否在特定范围内可以用 :

15,10,GT,15,20,LT,* 
,结果就是(15>10*15 < 20= 1 * 1 =1 ,所以为 true

    9,10,GT,9,20,LT,* 
,结果就是 (9 >10 9 < 20= 0 * 1 =0 ,所以为 false

D
OR 关系的例子:同上例如要比较某个值(7,15)小于10,或者大于20

    7,10,LT,7,20,GT,+ 
,结果为 (7 < 107 > 20 = 1+0 = 1,所以为 true

    15,10,LT,15,20,GT,+ 
,结果为 ( 15 < 10) + ( 15 > 20) = 0 + 0 =0 ,所以为 false

E
)不过使用 + 需要注意一个地方 :相加的双方都必须是正数,否则可能出现问题,例如一个正数(-5true)和另外一个正数(5true)相加为0false

如果是按照 OR 的关系,应该是 true 的,但结果变成0false),所以在使用 + 来表示 OR 的关系时,要注意该问题

F
)使用 * 则没有该问题了,正数 * 负数 = 负数 (true)。所以如果遇到 OR 关系的时候,可以转换为 AND 关系来计算。

    
例如要表达 (x < a) OR ( x > b) 的关系,可以改为 (x >a) AND ( x < b ) ,诀窍就是把比较操作符调反方向,把 + 改为 *

八)实例

实例1:例如要看 eth0的总流量,可以用如下的定义

CODE:

DEF:value1=eth0.rrd:eth0_in:AVERAGE \
DEF:value2=eth0.rrd:eth0_out:AVERAGE \
CDEF:value3=value1,value2,+ \
AREA:value3#ff0000:”total”


实例:假设我们要把 eth0  lo 的流入流量相加,得出总的流入流量

CODE:

DEF:value1=eth0.rrd:eth0_in:AVERAGE \
DEF:value2=lo.rrd:lo_out:AVERAGE \
CDEF:value3=value2,UN,0,value2,IF \
CDEF:value4=value1,value3,+ \
AREA:value4#00ff00:”total in”


由于 lo.rrd 一直没有数据插入,所以一直都是 NaN ,如果直接把 value1  value2 相加,由于 value2  UNKNOWN

所以相加的结果也是 UNKNOWN 。图表上将什么都不显示,所以需要对 value2 进行判断,如果 value2 的值 UNKNOWN value2,UN),

则返回0,否则返回 value2 本身。然后把这个值赋予变量 value3 ,最后把 value1  value3 相加,才得出真正入流量

实例:只看 eth0 中流量大于 10Mb/s 的部分,其余不看

CODE:

DEF:value1=eth0.rrd:eth0_in:AVERAGE \
DEF:value2=eth0.rrd:eth0-_out:AVERAGE \
CDEF:value3=value1,1000000,GT,value1,UNKN,IF \
CDEF:value4=value2,1000000,GT,value2,UNKN,IF \
AREA:value3#00ff00:”traffic_in \> 10M\/s” \
AREA:value4#ff0000:”traffic_out \> 10Mb\/s”:STACK


实例:只绘制特定时间段(在 2006/11/29 10:30 ~ 2006/11/29 12:30)的数据

CODE:

DEF:value1=eth0.rrd:eth0_in:AVERAGE \
DEF:value2=eth0.rrd:eth0_out:AVERAGE \
CDEF:value3=TIME,$(date –d ‘2006-11-29 10:30’ +%s),GT,TIME,$(date –d '2006-11-29 12:30' +%s),LT,*,value1,UNKN,IF \
CDEF:value4=TIME,$(date –d ‘2006-11-29 12:30’ +%s),GT,TIME,$(date –d '2006-11-29 13:30' +%s),LT,*,value2,UNKN,IF \
AREA:value3#00ff00:”traffic_in” \
AREA:value4#ff0000:”traffic_out”:STACK


九、完结

相信到目前为止,大家对 RRDtool 的认识应该更深了吧。一定要多做实验,这样才能做到熟能生巧,灵活应用。

其实剩下的还有 xportdumprestoreresizetunerrdcgi 几个操作没讲,而且有一些应用经验方面的东西也没有提到,

不过想要全部写出来,可能太耗时间和精力了,这些东西足足写了我2个星期才写完。中间还要不断的做实验以验证正确性,怕误导了大家。

如果需要的话,可以自己下载官方文档学习,或者能有热心的朋友补充就更好了,^_^ 

十、 本人的一点学习体会

   
本人从开始看 RRDtool 官方文档到开始写这篇教程,差不多用了2个月。 RRDtool 比学习 MRTG 难多了,资料少,RRDtool 的中文资料目前就只有 abel兄写的那一篇教程,如果没有实际的上机操作,是不可能看懂的,所以 abel 兄也特别交代这点。如果只一心想速成,到头来反而吃亏的是自己。

sendmailbind 这些服务器的配置,随便在 google 上都可以搜到一大把所谓的快速入门,很多人也都照着做了。但明明别人可以的,为什么轮到自己

却失败呢?相信这是很多人心中曾有的郁闷经历。其实归根到底就是基础的问题,再深入一些就是学习心态的问题。不积跬步,无以至千里;不积小流,无以成江海

配置一个服务器并不是照抄配置就可以的。环境的不同,需求的不同这些因素都要考虑在内。怎么可能做到完全一样呢?同一个语句换个环境可能就不行了。所以我很

少看那些所谓的快速入门,要么看 manual ,要么看书(说到这里,感觉 O’Reilly 的书真是不错!^_^),如果是象 RRDtool这种的,就只好看官方文档了。

   
学习的同时也要注意选择好的教材。有时候一本好书能带给无穷的好处。这点在我第一次看 O’Reilly 的 《dns & bind 4th》就有感觉,老外的书很注重循序渐进,
  
通常他们都是从某个实际工作环境的一个小例子说起,逐步引入各个命令、配置语句。然后随着需求的壮大,不断引入新的内容,最后形成一个总体。这样看完后会心中会

有一个整体的框架和概念。不象国内一些书,毫不顾及条理,一上来就讲语法、命令,搞得读者很快都没有兴趣。这样的书可谓害人不浅。

同时也建议大家读英文原版的书。为什么呢?虽然中文的看起来快一些,但学习不是竞走比赛。不是比谁看的快,而是比谁学的牢。英文书的词汇其实都是专业词汇,

只要看多了,自然记住了。实在记不住,可以用金山词霸等工具辅助。俺的英文水平只有二级,但并不妨碍我看书。况且看英文书,有一个英文中文的转换的过程。就

是揣摩作者这句话的含义,或者说这句话应该如何翻译好。有些人觉得这个没有什么,但我觉得这个过程是你弄清作者思想的重要步骤。在你不断的揣摩中,可能会有不同

的理解,直到你认为这是最正确的那一种解释为止。如果是看中文书,可能会由于惰性,比较容易就接受作者的想法,而失去这个主动我思考的过程。

   
一时有感而发,胡乱写了一通,请各位朋友见谅了。

   
书山有路勤为径,学海无涯苦做舟!

愿以该座右铭和各位有志于Linux的朋友一起共勉!


阅读(1161) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~