2004年6月2日

使用 RRDTool 整合系統狀態

RRDTool手册(簡)

RRDTool 和 MRTG 一樣都是將某些狀態的數值變化以圖形方式加以顯現的工具,其中最大的差別在於 RRDTool 可以在同一個圖示中整合多種看似無關的數據資料在同一個時間流之下,例如網頁存取次數與網路流量、CPU 使用率、以及記憶體使用率之間的關係。可以提供管理人員作為判別之用。

這份文件是參考 abelyang 在 酷!學園 討論區中標題為 [教學]大作 rrdtool (像 mrtg 的東東) 完全攻略 的內容後所做的實際測試,同時依個人的領悟狀況加上個人的解釋。

安裝 rrdtool

在 Gentoo 下,直接以 emerge -v rrdtool 即可安裝,portage 機制可以會自行處理相依性問題。事實上 rrdtool 須要的套件主要是 libgd (RedHat 叫 gd) 這個套件,通常在安裝 libgd 前會先安裝 libpng 及 freetype2 兩個套件。若使用中文修改版的 rrdtool 則還必須另外安裝 libiconv 套件,目前 Gentoo 中 libiconv 這個套件是 Masked 的。

使用 RRDTool 的基本步驟

使用 RRDTool 的基本步驟有三:

  1. 建立RRD資料記錄檔:也就是真正儲放資料的地方,基本上是要求 RRDTool 必須記錄多少項資訊,以及這些資訊的儲存規則。
  2. 擷取資料、寫入資料記錄檔:透過各種方式將當成圖示條件的資料寫入RRD記錄檔中,作為晝面顯示的依據。
  3. 繪出圖示:將已記錄下的資料依指定格式輸出成圖形檔,提供管理人員分析研判。

練習目標

由於我的 Server 上有提供 WEB 及 Mail Server 兩種服務,因此打算以這兩種服務的流量表作為這次練習的目標,依照前述的三步驟逐一建立。

同時,由於是追蹤流量的改變,因此必須使用 tcpdump 輔助工具協助擷取 TCP 封包資訊,不過這部份的使用不在此次介紹之列。其他像是 Shell Script, sed/awk, 或 Regular Expression 等使用也必須瞭解熟悉。

建立 RRD 記錄檔

建立 RRD 記錄檔的方式是透過 rrdtool create 方式達成,以下是完整的語法結構。

rrdtool create filename                 # filename 一般會以 .rrd 作結尾,方便辨視
[--start|-b start time]                 # 記錄起始時間, 為自1970-01-01 00:00:00迄今之秒數
[--step|-s step]                        # 每兩次記錄之間的時間間隔
[DS:ds-name:DST:heartbeat:min:max]      # 資料源,同一記錄檔中可有多個資料源
[RRA:CF:xff:steps:rows]                 # 資料保存方式

記錄起始時間用於標示該記錄檔有效起始時間,未指定時以建檔當時時間為預設值。

時間間隔則用於標示前後筆資料的相差時間(秒數)。

資料集合(DataSource, DS, 或稱為資料源):

  1. ds-name: 用來指定這個資料集合的名稱
  2. DST: 用來說明這個資料集合的型別為何,總共有四種:GAUGE、COUNTER、DERIVE及ABSOLUTE。GAUGE 是指前後兩個數據各自獨立,沒有關連的記錄方式;COUNTER 則是前後項資料之間有累計的性質。使用 COUNTER 會影響到圖示輸出的方式,其輸出的值則是兩數據之間的差。其他待查。
  3. heartbeat: 有效值,這是指多久時間之內若沒有取得資料時先用內插法取得欠缺的資料,但若超過這個限定時間長度的話則直接以 UNKNOW (UN) 表示。例如:假設step設為300, heartbeat 設為 600,某一個時間軸中的一點為t1,t2為t1+300秒,t3為t1+600秒, t4為t1+900秒。當t1有值、t3有值,但t2無資料時,會因為 t3 - t1 <= heartbeat 而由 rrdtool 自行將 t1 + t3 的值除以 2 作為 t2 的值;但若 t1 有值,t2, t3無值而t4有值,則因為 t4 - t1 >= heartbeat 所以 t2, t3 都會變成 UN,表示無資料。
  4. min: 可接受的最小值。
  5. max: 可接受的最大值。
資料保存方式 (RRA):
  1. CF: 資料使用方式,共有AVERAGE,MIN,MAX,LAST四種,分別表示在指定的區間(steps)內的所有數據的『平均值』、『最小值』、『最大值』、『最後值』 。
  2. xff: 用途不明,其值限定在 0 到 1 之間,我試過填入 0 或填入 0.5 似乎都沒差。
  3. steps: 指出這個保存方式橫跨幾個step, step表示多長時間則由建檔時指定。
  4. rows: 在指定的steps間隔下,必須保留最新的多少筆資料。例如若step=300,steps=1,rows=800即表示5分鐘間隔的記錄要存800筆;step=300,steps=6,row=300表示30分鐘間隔的記錄要存300筆。
經由以上的說明,可以使用以下的命令建立符合練習目標的rrd記錄檔。

# 指令請自行串接成一行
rrdtool create ~/tcpdump.rrd
-s 300
DS:smtp:GAUGE:600:0:U
DS:http:GAUGE:600:0:U
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

上述指令的完整意思說明如下:

  1. 建立一個叫 tcpdump.rrd 的rrd記錄檔。
  2. tcpdump.rrd的資料計算區間為300秒。
  3. 有一個叫smtp的資料集,單一數值記錄,最長有效時間為600秒,最小值為0,最大值無限制。
  4. 有一個叫http的資料集,單一數值記錄,最長有效時間為600秒,最小值為0,最大值無限制。
  5. 資料保存時必須記錄5分鐘的資料平均值603筆。
  6. 資料保存時必須記錄30分鐘的資料平均值603筆。
  7. 資料保存時必須記錄2小時的資料平均值603筆。
  8. 資料保存時必須記錄一天的資料平均值800筆。
  9. 資料保存時必須記錄5分鐘的資料最大值603筆。
  10. 資料保存時必須記錄30分鐘的資料最大值603筆。
  11. 資料保存時必須記錄2小時的資料最大值603筆。
  12. 資料保存時必須記錄1天的資料最大值800筆。

更新RRD記錄檔

要更新RRD記錄檔必須透過 rrdtool update 方式進行,以下是指令的架構:

rrdtool update filename                # 欲更新的RRD檔檔名 
[--template|-t ds-name[:ds-name]...]   # 指定要更新的資料源順序,未輸入時以建立時的順序為預設值
N|timestamp:value[:value...]           # 記錄時間及相關數據
  1. --template|-t: 用於標示後續的資料要依何種順序寫入RRD記錄檔中,若有多個資料源則以 : 加以區隔。
  2. N|timestamp: 用於標示此筆資料的建立時間,若記錄的時間是目前的時間時,可以用 N 表示。這個數值的單位是秒,在 bash 下可以使用如下方式取得:
    NOW=$(date +%s)
  3. value: 實際欲寫入的數據,必須和 template 指定的項數建檔時的資料集合項數 符合。
簡單的說,更新RRD記錄檔的方式就是將須填入的資料準備好,再依指令規定的格式串接即可透過指令寫入記錄檔中。

寫入新資料時,必須注意rrdtool在繪出圖檔時似乎是以 08:00 + step 設定的秒數 UTC +0000 為時間軸的參考點(所以實際的起始時間必須配合 TimeZone 來確認,如 Taipei 時區就變成 08:00 為起始點),因此在實際繪出圖形時若發現預期外的小數點輸出時,請修改寫入記錄檔時所設定的 timestampe ,使之配合 0 + step 的週期即可。

以下是此次測試使用的資料擷取程式片段,我採用 crontab 方式執行。

#!/bin/bash
# tcpdump.sh, 產生 smtp 及 http 兩個 port 上的流量表並寫入 rrd 記錄檔
RRD_PATH="/root/tcpdump.rrd"
image_path="/root"
sec=300
# 此段用於產生新的 tcpdump 記錄檔
killall tcpdump
mv /root/ip.packet /root/ip.packet.1
/usr/sbin/tcpdump -w /root/ip.packet tcp &
# 指定要計算的 port 列表
scan_port="25 80"
rrd_data=""
# 開始擷取相關資料,算出來的流量單位是 5 分鐘內的平均 bytes 數
# 請注意:這邊對流量的計算方式僅適用於 Gentoo 下的 tcpdump v3.8.3 版,
#        這是因為 tcpdump 輸出格式似乎有依套件及版本別不同而有不同的格式。
for sport in $scan_port
do
        port=$(/usr/sbin/tcpdump -r /root/ip.packet.1 port $sport -v | sed -e 's/.*, length: ([^)]*)) .*$/1/g' | tr 'n' '+')
        port=$(echo ${port}0| bc)
        port=$(expr $port / $sec)
        rrd_data="$rrd_data$port:"
done
# 濾掉前一個迴圈中額外產生的 : 符號
rrd_data=$(echo $rrd_data | sed -e 's/:$//')
# 將指令寫入 tcpdump.cmd 中,若須重建 rrd 資料庫時可以重覆利用
echo "rrdtool update $RRD_PATH N:$rrd_data" >> /root/tcpdump.cmd
rrdtool update $RRD_PATH N:$rrd_data

輸出圖形

RRDTool 的繪圖指令格式

rrdtool graph filename                      # filename 圖檔名稱
[-s|--start seconds]                        # 起始時間,自1970年1月1日起以秒為單位,預設為24小時前
[-e|--end seconds]                          # 結束時間,規則同起始時間,預設為繪圖當時之時間
[-x|--x-grid x-axis grid and label] 
[-y|--y-grid y-axis grid and label] 
[-Y|--alt-y-grid] 
[-R|--alt-y-mrtg] 
[-A|--alt-autoscale] 
[-M|--alt-autoscale-max] 
[-N|--no-minor]                             # 不要繪出副隔線 
[-X|--units-exponent] value]> 
[-L|--units-length] value]> 
[-v|--vertical-label text]                  # Y 軸上的說明
[-w|--width pixels]                         # 圖檔寬度
[-h|--height pixels]                        # 圖檔高度
[-i|--interlaced] 
[-f|--imginfo formatstring] 
[-a|--imgformat GIF|PNG|GD]                 # 圖檔格式,預設為 GIF 格式
[-B|--background value] 
[-O|--overlay value] 
[-U|--unit value] 
[-z|--lazy] 
[-o|--logarithmic] 
[-u|--upper-limit value]                    # 設定 Y 軸上最高顯示範圍
[-l|--lower-limit value]                    # 設定 Y 軸上最低顯示範圍
[-g|--no-legend] 
[-j|--only-graph]                           # 關閉說明列 
[-F|--force-rules-legend] 
[-r|--rigid] 
[-S|--step value]                           
[-b|--base value] 
[-c|--color COLORTAG#rrggbb]                # 指定物件(COLORTAG)顏色 
[-t|--title title]                          # 圖形抬頭
[DEF:vname=rrd:ds-name:CF]                  # 定義rrd檔中的資料集合對應之變數名稱
[CDEF:vname=rpn-expression]                 # 定義經計算過後之變數名稱
[PRINT:vname:CF:format]                     # 格式化字串
[GPRINT:vname:CF:format]                    # 格式化字串
[COMMENT:text]                              # 註解訊息
[HRULE:value#rrggbb[:legend]]  
[VRULE:time#rrggbb[:legend]] 
[LINE{1|2|3}:vname[#rrggbb[:legend]]]       # 設定線條格式(有寬、中、細三種,分別為LINE3, LINE2, LINE1) 
[AREA:vname[#rrggbb[:legend]]]              # 設定區塊格式
[STACK:vname[#rrggbb[:legend]]]
  • RRDTool 其實是不支援中文的,以下附的中文範例其實是因為使用了 abelyang 修改過的版本,請注意這項不同。
以下僅就範例所需解釋各參數的意義:
  1. -s|--start : 繪圖的起始時間點,以1970年1月1日0時0分0秒開始計算所經的秒數。預設值為 1 天前。
  2. -e|--end : 繪圖的結束時間點,以1970年1月1日0時0分0秒開始計算所經的秒數,預設值為現在。
  3. -N|--no-minor : 不要繪出副格線,在長時段下若繪出副格線有時會顯的凌亂不已。
  4. -v|--vertical-label : Y 軸上的說明文字。
  5. -w|--width : 資料輸出的有效寬度,單位是點。實際輸出寬度會因 Y 軸上的說明文字所佔用空間及兩側空白之故而略寬。
  6. -h|--height : 資料輸出的有效高度,單位是點。實際輸時會因為線條的說明文字及上下兩端空白之故而略高。
  7. -a|--imgformat GIF|PNG|GD : 指定圖形檔輸出格式,預設值是GIF,並不因為指定的圖檔副檔名而自動調整。
  8. -u|--upper-limit : 指定Y軸上的最高數據值,這個值一定大於或等於指定時間區段中的資料最大值。
  9. -l|--lower-limit : 指定Y軸上的最低數據值,這個值一定小於或等於指定時間區段中的資料最小值。
  10. -c|--color COLORTAG#rrggbb : 設定圖形輸出色彩值,COLORTAG中指定設定的項目,rrggbb是實際顏色值。COLORTAG共有BACK, CANVAS, SHADEA, GRID, MGRID, FONT, FRAME, ARROW 8種,詳細用途請自行參考 RRD TOOL -- RRD GRAPH 說明。
  11. -t|--title : 圖形抬頭。
  12. DEF:vname=rrd:ds-name:CF : 定義來自RRD資料檔的資料源對應,簡單的說就是要將某變數(vname)定義成資料檔(rrd)中的那一個資料源(ds-name)的那一種型別(CF)。例如:
    DEF:v1=/root/tcpdump.rrd:smtp:MAX
    表示將tcpdump.rrd記錄檔中的smtp資料源中記錄的最大值命名為v1這個變數。
  13. CDEF:vname=rpn-expression : 定義運算公式 (rpn-expression),並賦予公式名稱 (vname)。通常在原始資料不一定適合直接顯示在畫面上,此時可透過運算公式對原始資料進行處理。整個公式的表示採用後序方式表示,也就是必須將運算子擺到尾巴的方式。如果想要更清楚的瞭解公式的表達方式可以參考官方網站 CDE TutorialRPN Tutorial 網頁說明。
  14. GPRINT:vname:CF:format : 將指定的變數(vname),種類(CF)依規範的格式化字串(format)格式輸出到圖形的說明區中。
  15. COMMENT:text : 註解訊息,可在字串末端加上 LF 符號表示換行。
  16. LINE{1|2|3}:vname[#rrggbb[:legend]] : 線段設定,將指定變數(vname)的數據內容以指定的顏色(#rrggbb)及寬度(LINE3最粗,LINE1最細)繪出。legend用於說明該顏色/變數所代表的意義。
  17. AREA:vname[#rrggbb[:legend]] : 區塊設定,指將指定變數(vname)的數據內容以指定的顏色(#rrggbb)繪出。legend用於說明該顏色/變數所代表的意義。
RRD_FILE=/root/tcpdump.rrd
NOW_STR=$(date +"%Y-%m-%d %H:%M:%S")

# 以下指令請自行串接為一行,\\n 因 SnipSnap 限制,其意是換行符號 LF。 rrdtool graph /home/blog/ada/flowrate.png --title "伺服器網路服務流量表 - 最近 2 小時內" DEF:d1=$RRD_FILE:smtp:MAX DEF:d2=$RRD_FILE:http:MAX COMMENT:"服務別 --- 最大值 -- 平均值 -- 最小值 -- 現值 -- \\n" LINE3:d1#0000ff:"SMTP: " GPRINT:d1:MAX:"%10.0lf" GPRINT:d1:AVERAGE:"%11.0lf" GPRINT:d1:MIN:"%11.0lf" GPRINT:d1:LAST:"%9.0lf \\n" LINE3:d2#ff0000:"HTTP: " GPRINT:d2:MAX:"%10.0lf" GPRINT:d2:AVERAGE:"%11.0lf" GPRINT:d2:MIN:"%11.0lf" GPRINT:d2:LAST:"%9.0lf \\n" --no-minor -h 200 -w 320 -s `date -d "-2 hour" +%s` COMMENT:" 最後更新: $NOW_STR"

上述指令的說明如下:

  1. 定義一個叫 d1 的變數,其資料來源是 RRD 檔中的 smtp 資料集合中的 MAX 類型之資料。
  2. 定義一個叫 d2 的變數,其資料來源是 RRD 檔中的 http 資料集合中的 MAX 類型之資料。
  3. 使用 LINE3 線段繪出 d1 的變動情形,此時線段使用的顏色是紅色,同時附帶一個簡短的訊息文字,內容是 "SMTP:"。
  4. 格式化輸出 d1 的各種狀態的值。
  5. 使用 LINE3 線段繪出 d2 的變動情形,此時線段使用的顏色是藍色,同時附帶一個簡短的訊息文字,內容是 "HTTP:"。
  6. 格式化輸出 d2 的各種狀態的值。
  7. 不要顯示副格線。
  8. 有效高度是 200 畫素。
  9. 有效寬度是 320 畫素。
  10. 起時日期是 2 小時前。
  11. 輸出最後更新時間為 $NOW_STR。
圖檔輸出範例:
example

中文版本安裝 - 使用 Gentoo Linux

※目前 rrdtool 應已內建輸出 UTF-8 字元之能力!

若打算在 Gentoo 上使用 abelyang 所修改的 rrdtool 套件,必須完成以下作業:

  1. 自行建立 gnroff 的 soft link。
    ln -s /usr/bin/nroff /usr/bin/gnroff
  2. make 前要修改 perl-piped 及 perl-shared 目錄下的 Makefile, 將 perl 版本別改為系統上的狀態。例如在 vim 下執行下述指令可以完成修改作業。
    :1,$s/5.8.0/5.8.2/g
  3. make 前要修改 perl-piped 及 perl-shared 目錄下的 Makefile, 將 i386-linux-thread-multi 改為系統上的狀態。在 vim 下執行以下指令可完成修改作業。
    :1,$s/i386-linux-thread-multi/i686-linux/g
  4. 安裝中文字形檔 media-fonts/arphicfonts。
  5. 修改 gd1.3/gd.c 中字型檔位置
    gdImageStringTTF(im,&brect[0], color, "/usr/share/fonts/ttf/zh_TW/bkai00mp.ttf",12,0.0,x-2,y+13,UTF8_String((char *)s));
  6. 最後安裝 rrdtool 時不要使用 configure, 直接 make clean; make; make install 即可。

中文版本安裝 - 使用 RedHat Linux

若打算在 Redhat 上使用 abelyang 所修改的 rrdtool 套件,必須完成以下作業:

  1. 安裝 libpng, libjpeg, freetype2 的函式標頭檔。
  2. 安裝 gd 套件,可以先找找 rpm 套件包,也別忘記安裝函式標頭檔。同樣的,若 rrdtool 無法 make 成功時,請考慮自行編譯 gd ,同時指定 --prefix=/usr/local 。最後在 ./configure 後必須檢查是否已開啟 freetype, libpng, libjpeg 等支援。
  3. 安裝 libiconv 套件,可以先試著找找看有無 rpm 套件包(記得安裝函式標頭檔),若找不到的話就下載原始程式檔自行編譯安裝。安裝時記得要在 configure 時設定 --prefix=/usr/local ,否則可能 rrdtool 會 make 失敗。另外若發現已確實安裝 libiconv 卻仍然無法成功 make 時,可以試著更改 libiconv 的版本,如 libiconv v1.8 版。
  4. 若有更新過 Perl 時,必須要和 Gentoo 一樣去修改 rrdtool 目錄下的 perl-piped 及 perl-shared 中的 Makefile,將路徑修正成系統的實際設定。
  5. 記得安裝中文字形檔 ttfonts-zh_TW-2.11-19.noarch.rpm 。
  6. 安裝 rrdtool 時不要使用 configure, 直接 make clean; make; make install 即可。

中文版本安裝 - 使用 GB2312 編碼

  1. 請先完成套件本身有關之相依性設定。
  2. 修改 gd1.3/gd.c 中的設定,將
    cd=iconv_open("UTF-8","BIG5");
    修改為
    cd=iconv_open("UTF-8","GB2312");
  3. 開始禱告我的猜測是正確的… :p
  4. 安裝 rrdtool 時不要使用 configure, 直接 make clean; make; make install 即可。