RRDtool簡體中文教程_9:如何使用RPN
如何使用RPN
**********************************************************************************************************************
注 :該教程參考瞭如下內容 :
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
**********************************************************************************************************************
一)前言
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 的格式是
<value1>,<value2>,<operator>
,[<value1>,<value2>,<operator>]… 可以看出是操作數在前,操作符在後的格式
E)RPN 需要提到堆棧的概念(stack)。堆棧是用來存儲操作數和操作符的。
F)當堆棧中壓入(push)一個操作符時,就從堆棧中取出(pop)所需要的操作數進行計算(根據操作的不同pop出不同數量的操作數)。
結果再返回(push)堆棧,最終整個 RPN 應該只返回一個值,或者說堆棧中只有一個元素
G)在 CDEF 中書寫 RPN 操作符,要一律以大寫的格式出現
H) RPN 中,如果某個部分的運算結果非 0,則被認爲是 true ,只有 0 才被認爲是
false
三)RPN 操作符的分類
A)布爾操作符 :GT、GE、LT、LE、EQ、NE、
B)特殊值比較符 :UN、ISINF、
C)條件操作符 :IF
D)比較操作符 :MIN、MAX、LIMIT
E)算術操作符 :+ 、-、*、/、%、SIN, COS, LOG, EXP, SQRT、FLOOR, CEIL、ATAN、ATAN2、DEG2RAD,
RAD2DEG
F)數據集操作符 :所謂數據集(sets),就是指多個數據。SORT、REV、AVG、TREND
G)特殊值 :UNKN、INF、NEINF、PREV、COUNT
H)時間操作符 :NOW、TIME、LTIME
I)堆棧操作符 :POP、DUP、EXC
四)RPN 操作的結果
A)布爾操作符 :從堆棧中 pop 出兩個元素,並根據比較結果返回 0 (false) 或者 1 。任何同 UNKNOWN 或者 INF 、NEINF
比較的都爲 0
B)特殊值比較符 :從堆棧中 pop 出1個元素,並同 UNKNOWN 或者 INF、NEINF
比較。結果爲 0 或者 1
C)條件操作符 :從堆棧中pop出3個元素,如果最後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)數據集操作符 :
對於 SORT、REV 來說,先從堆棧中 POP 出一個元素,該元素的值就是下面要 pop 出的元素的數量。然後對堆棧從上到下的若干個元素
由第一次 pop 的出的那個元素的值決定)進行排序/反向排序。結果再重新入棧。
注意 :由於堆棧的特點是後進先出,所以要操作的元素是從SORT操作符往左方向計數。例如v1,v2,v3,v4,3,SORT是對 v2~v4 排序,
不是對 v1~v3 排序。 這點在書寫 RPN 時要特別注意。
注意 :SORT 操作是最小值在堆棧的最頂部;REV 則相反,最小值是在堆棧的最頂部。
對於 AVG 操作來說,同樣是先 pop 出1個元素,並按照指定的數量對後續的若干個操作數進行操作,但結果只有一個數值,併入棧。
G)特殊值 :
UNKN 表示壓入一個 UNKN 值;INF、NEINF 分別表示把 INF、NEINF
值壓入堆棧
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 表示返回
mydata,20 這兩個數值中較大的一個;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 就立即彈出第一個元素
七)如何表示 AND、OR 關係
A)我們知道 RPN 表達式的值除非0,否則都認爲是 true
B)我們可以利用 加法操作和乘法操作來實現 OR 和 AND 的邏輯關係;如果兩個 RPN 表達式的值相加不等於0,就一定爲 true ;
如果兩個 RPN 表達式的值相乘不等於0,就一定爲 true
C)AND 關係的例子 :例如要比較某個值(15,9)是否在特定範圍內可以用 :
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 < 10)+ (7 > 20) = 1+0
= 1,所以爲 true
15,10,LT,15,20,GT,+ ,結果爲 ( 15 <
10) + ( 15 > 20) = 0 + 0 =0 ,所以爲 false
E)不過使用 + 需要注意一個地方 :相加的雙方都必須是正數,否則可能出現問題,例如一個正數(-5,true)和另外一個正數(5,true)相加爲 0(false)
如果是按照 OR 的關係,應該是 true 的,但結果變成0(false),所以在使用 + 來表示 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”
實例2 :假設我們要把
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 相加,才得出真正入流量
實例3 :只看 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
實例4 :只繪製特定時間段(在 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 的認識應該更深了吧。一定要多做實驗,這樣才能做到熟能生巧,靈活應用。
其實剩下的還有 xport、dump、restore、resize、tune、rrdcgi 幾個操作沒講,而且有一些應用經驗方面的東西也沒有提到,
不過想要全部寫出來,可能太耗時間和精力了,這些東西足足寫了我2個星期才寫完。中間還要不斷的做實驗以驗證正確性,怕誤導了大家。
如果需要的話,可以自己下載官方文檔學習,或者能有熱心的朋友補充就更好了,^_^ 。
十、 本人的一點學習體會
本人從開始看 RRDtool 官方文檔到開始寫這篇教程,差不多用了2個月。 RRDtool 比學習 MRTG 難多了,資料少,RRDtool 的中文資料目前就只有 abel
兄寫的那一篇教程,如果沒有實際的上機操作,是不可能看懂的,所以 abel 兄也特別交代這點。如果只一心想速成,到頭來反而吃虧的是自己。
象sendmail、bind 這些服務器的配置,隨便在 google 上都可以搜到一大把所謂的“快速入門”,很多人也都照着做了。但明明別人可以的,爲什麼輪到自己
卻失敗呢?相信這是很多人心中曾有的鬱悶經歷。其實歸根到底就是基礎的問題,再深入一些就是學習心態的問題。“不積跬步,無以至千里;不積小流,無以成江海”。
配置一個服務器並不是照抄配置就可以的。環境的不同,需求的不同這些因素都要考慮在內。怎麼可能做到完全一樣呢?同一個語句換個環境可能就不行了。所以我很
少看那些所謂的快速入門,要麼看 manual ,要麼看書(說到這裏,感覺 O’Reilly 的書真是不錯!^_^),如果是象 RRDtool這種的,就只好看官方文檔了。
學習的同時也要注意選擇好的教材。有時候一本好書能帶給無窮的好處。這點在我第一次看 O’Reilly 的 《dns & bind 4th》就有感覺,老外的書很注重循序漸進,
通常他們都是從某個實際工作環境的一個小例子說起,逐步引入各個命令、配置語句。然後隨着需求的壯大,不斷引入新的內容,最後形成一個總體。這樣看完後會心中會
有一個整體的框架和概念。不象國內一些書,毫不顧及條理,一上來就講語法、命令,搞得讀者很快都沒有興趣。這樣的書可謂害人不淺。
同時也建議大家讀英文原版的書。爲什麼呢?雖然中文的看起來快一些,但學習不是競走比賽。不是比誰看的快,而是比誰學的牢。英文書的詞彙其實都是專業詞彙,
只要看多了,自然記住了。實在記不住,可以用金山詞霸等工具輔助。俺的英文水平只有二級,但並不妨礙我看書。況且看英文書,有一個“英文→中文”的轉換的過程。就
是揣摩作者這句話的含義,或者說這句話應該如何翻譯好。有些人覺得這個沒有什麼,但我覺得這個過程是你弄清作者思想的重要步驟。在你不斷的揣摩中,可能會有不同
的理解,直到你認爲這是最正確的那一種解釋爲止。如果是看中文書,可能會由於惰性,比較容易就接受作者的想法,而失去這個主動我思考的過程。
一時有感而發,胡亂寫了一通,請各位朋友見諒了。
書山有路勤爲徑,學海無涯苦做舟!
願以該座右銘和各位有志於Linux的朋友一起共勉!
2006/12/2 22:23