搜尋此網誌

2013/05/04

RRDTool 的CDEF語法說明及範例


RRDTool 的CDEF語法說明及範例
RRDTool使用CDEF來對Data Source進行各種運算,而Cacti是利用RRDTool來進行資料的儲存和呈現,故適當的了解CDEF的用途是必要的。本文簡單的分享一下CDEF的用法和寫法。
CDEF無所不在
在Cacti內建的網路卡流量圖表中,就有使用到CDEF「Turn Bytes into Bits」:


從名稱可知道,它是把位元組轉換成位元;要看這個CDEF的內容,要先到選單CDEF下:






點進「Turn Bytes into Bits」的CDEF,我們可看到:


1:名稱
2:組合出來的CDEF
3:CDEF的項目,Cacti會把各項目用逗號串起來

CDEF使用RPN表示法 (全名Reverse Polish Notation,中文叫逆波蘭表示法),維基中有寫到:
“在逆波蘭記法中,所有操作符置於操作數的後面,因此也被稱為後綴表示法”
雖然在RRDTool中有定義資料來源,但是由於Cacti允許使用者隨時修改趨勢圖的內容,也就是Data Source並不是固定的,故在在Cacti中,又自行定義了幾個CDEF變數:




例如CURRENT_DATA_SOURCE就是Current Graph Item Data Source的意思,如此做法是減少使用者對應資料來源的麻煩。
上面的圖中,可以看到CDEF的定義是CURRENT_DATA_SOURCE,8,*,而RPN最簡單的讀法,就是遇到運算子後,取運算子前需要數量的值出來,例如「*」需要二個運算子,故把CURRENT_DATA_SOURCE,8取出後,我們可得到:
CDEF=CURRENT_DATA_SOURCE * 8
中序運算式轉RPN
中序運算式,即一般我們常用的表示式,而將之轉成Cacti中的CDEF格式,就是我們需要做的事情,就是遵照RPN的精神,將之進行轉換即可,例子:
5 + 3:+為運算符號,先把運算元5、3放進去,最後放入運算子,結果為:5,3,+
(1+2)*3:括號優先處理,故括號中的RPN可得到為12,+,這個RPN又要*3,運算元先放入,再放運算子,可得1,2,+,3,*
1+2*3;乘法運算先處理,故可得第一個RPN為2,3,*,套用前一個例子的解法,可得到 2,3,*,1,+
RPN轉中序運算式
通常RPN的運算式不會是就這麼短短的一行,而有可能是很長的一行,但是只要遵循RPN的精神,也可以很簡單的解譯出來,例如:d,c,-,b,-,a,-,1024,*,解法一樣是「遇到運算元,提取相對應需要的運算子數量後,進行運算」:




可得列出的式子為(d-c-b-a)*1024
邏輯運算子及條件式:大於、等於…..
RRDTool的RPN中也有大於、等於等運算式:LT、LE、GT、GE 及EQ分別代表「小於」、「小於等於」、「大於」、「大於等於」及「等於」;另外也有IF的判斷式:
LT、LE、GT、GE及EQ:以LT為例,一樣用RPN的表示式,式子為 「v1, v2, LT」時,代表「如果v1小於v2,傳回TRUE (1),否則傳回FALSE」
IF:格式為 b1,v1,v2,IF,代表「如果b1為真,則傳回v1,否則傳回v2」
例子:如果a大於3,則傳回100,不然傳回1000,一般程式語法有點像是這樣子:
If (a>3) {
 return 100;
}
else
 return 1000;
RPN表示法:「a,3,LT,100,1000,if」:


未知值的表示

RPN中也可回傳未知值,未知值並不是零,我們可以看成資料在該時間點時未進來,是個空值,在圖表中,常見到數值是顯示NaN時,找表它是個未知值。
我們可用if運算回傳未知值,用UNKN式是UN關鍵字來表示
無限大
RPN中也可傳回無限大,當用在例如要畫一塊區間時,使用無限大來畫,是個好主意。
要傳回無限大的值,可用INF
判斷式
在RRDTool中也有IF,例子如下:
「A,B,C,IF」 的意思就是:if (A) then (B) else (C)
我們拿「Advanced Ping」這個現成的Template中的CDEF來看:
Advanced Ping - Loss 1 - 2 % bottom, CDEF = d,0,GT,d,2,GT,UNKN,b,IF,UNKN,IF
這一串看起來有點複雜,先用前面解釋過的方式把式子拆開:


:紅線的GT是判斷d值是否大於0
:藍線的GT是判斷d值是否大於2
:黃色的IF是判斷乙式為真的話傳回UNKNOWN,否則傳回b
:綠色的式子是判斷甲式如果為真的話傳回丙,否則傳回UNKNOWN

式子拆開還是很模糊的話,試著把它寫成一般程式語言的if-then-else:


結果就是:是如果d介於0~2間,則傳回b
那麼,下列的式子又是做什麼呢?
a,UN,0,a,IF,b,UN,0,b,IF,+,c,UN,0,c,IF,+,d,UN,0,d,IF,+
一樣拆開來看:


拆開後好像哪裡怪怪的…但是上面的式子是可執行的!我誤打誤撞的試CDEF,結果上面的式子居然是可執行的。

前面有說過,IF的語法是「A,B,C,IF」上面的拆解法也是照規則來拆的,你會發現UN這個值被拿來判斷直偽,很明顯的就不對。上面的式子其實隱含了EQ的運算,式子展開後應該是:
a,UN,EQ,0,a,IF,b,UN,EQ,0,b,IF,+,c,UN,EQ,0,c,IF,+,d,UN,EQ,0,d,IF,+
以第一個if來說:「如果a是UNKNOWN,則傳回0,否則傳回a」
所以,應該拆解成如下:

程式碼可以寫
成這樣:



上面的式子解釋:由於任何值和UN作運算後,結果都是UN,所以如果想加總a,b,c,d四個值並畫出圖形,有可能因某個值當時是UNKNOWN而造成圖是空的,為了避免這狀況,要先把UN的值轉成0,加總後才不會變成UNKNOWN。
如果你有用Threshold這個外掛的話,就知道UN值有時真的讓人頭痛,你可強制它回傳-1之類的,就知道是抓不到資料了。
依這個用法,我做了一個CDEF長這樣,而且在使用中:



最後一個式子的例子:
a,UN,0,a,100000,GT,0,a,IF,IF




「A如果是UN或是大於100000時,傳回0,不然傳回a」
程式碼可寫成如下:



如果會以上的CDEF使用法的話,應該可以應付大部份的運算。




1 則留言:

Ying Enyo 提到...

您好,

請問我有一個Data Source是這樣
" 5 Secs ( 2.8953%) 60 Secs ( 3.5097%) 300 Secs ( 3.2547%)"

如果我要取3.5097%當中的3.5097,

CDEF要怎麼寫,

或是有其他的解決方法?