rrd-beginners - Beginners guide
RRDtool has a lot to do with time. With every data update, it also needs to know the time when that update occurred. Time is always expressed in seconds passed since epoch (01-01-1971). RRDTool can be installed on Unix as well as Windows. It has command set to carry out various operations on rrd database. This command set can be accessed from the command line, and from shell or perl scripts. The scripts act as wrappers for accessing data stored in RRDtool database.
The structure of a database and the terminology associated with it can be best explained with an example.
rrdtool create target.rrd --start 1023654125 --step 300 DS:mem:GAUGE:600:0:671744 RRA:AVERAGE:0.5:12:24 RRA:AVERAGE:0.5:288:31
This example creates a database named target.rrd. Start time (1023654125) is specified in total number of seconds since epoch (time in seconds since 01-01-1970). While updating the database, update time is also specified. This update time MUST occur after start time and MUST be in seconds since epoch.
The step of 300 seconds indicates that database expects new values every 300 seconds. The wrapper script should be scheduled to run every step seconds so that it updates the database every step seconds.
DS (Data Source) is the actual variable which relates to the parameter on the device that has to be monitored. Its syntax is
DS:variable_name:DST:heartbeat:min:max
DS is a key word. "variable_name" is a name under which the parameter is saved in database. There can be as many DSs in a database as needed. After every step interval, a new value of DS is supplied to update the database. This value is also called as Primary Data Point (PDP). In our example mentioned above, a new PDP is generated every 300 seconds.
Note, that if you do NOT supply new datapoints exaclty every 300 seconds, this is not problem, RRDTool will interpolate the data accordingly.
DST (Data Source Type) defines type of DS. It can be COUNTER, DERIVE, ABSOLUTE, GAUGE. A DS declared as COUNTER will save the rate of change of the value over a step period. This assumes that the value is always increasing (difference between last two values is more than 0). Traffic counters on a router is an ideal candidate for using COUNTER as DST. DERIVE is same as COUNTER but it allows negative values as well. If you want to see the rate of change in free diskspace on your server, then you might want to use the DERIVE data type. ABSOULTE also saves the rate of change but it assumes that previous value is set to 0. The difference between current and previous value is always equal to the current value. So, it stores the current value divided by step interval (300 seconds in our example). GAUGE does not save the rate of change. It saves the actual value itself. There are no divisions/calculations. Memory consumption in a server is an ideal example of gauge. Difference among different types DSTs can be explained better with following example:
Values = 300, 600, 900, 1200 Step = 300 seconds COUNTER DS = 1, 1, 1, 1 DERIVE DS = 1, 1, 1, 1 ABSOLUTE DS = 1, 2, 3, 4 GAUGE DS = 300, 600, 900, 1200
The next parameter is heartbeat. In our example, heartbeat is 600 seconds. If database doesn not get a new PDP within 300 seconds, it will wait for another 300 seconds (total 600 seconds). If it doesnt receive any PDP with in 600 seconds, it will save an UNKNOWN value into database. This UNKOWN value is a special feature of RRDTool - it is much better than to assume a missing value was 0 (zero). For example, the traffic flow counter on a router keeps on increasing. Lets say, a value is missed for an interval and 0 is stored instead of UNKNOWN. Now when next value becomes available, it will calculate difference between current value and previous value (0) which is not correct. So, inserting value UNKNOWN makes much more sense here.
The next two parameters are the minimum and maximum value respectively. If variable to be stored has predictable maximum and minimum value, this should be specified here. Any update value falling out of this range will be saved as UNKNOWN.
The next line declares a round robin archive (RRA). The syntax for declaring an RRA is
RRA:CF:xff:step:rows
RRA is the keyword to declare RRAs. The consolidation function (CF) can be AVERAGE, MINIMUM, MAXIMUM, and LAST. The concept of the consolidated data point (CDP) comes into the picture here. A CDP is CFed (averaged, maximum/minimum value or last value) from step number of PDPs. This RRA will hold rows CDPs.
Lets have a look at the example above. For the first RRA, 12 (steps) PDPs (DS variables) are AVERAGEed (CF) to form one CDP. 24 (rows) of theses CDPs are archived. Each PDP occurs at 300 seconds. 12 PDPs represent 12 times 300 seconds which is 1 hour. It means 1 CDP (which is equal to 12 PDPs) represents data worth 1 hour. 24 such CDPs represent 1 day (1 hour times 24 CDPs). It means, this RRA is an archive for one day. After 24 CDPs, CDP number 25 will replace the 1st CDP. Second RRA saves 31 CDPs; each CPD represents an AVERAGE value for a day (288 PDPs, each covering 300 seconds = 24 hours). Therefore this RRA is an archive for one month. A single database can have many RRAs. If there are multiple DSs, each individual RRA will save data for all the DSes in the database. For example, if a database has 3 DSs; and daily, weekly, monthly, and yearly RRAs are declared, then each RRA will hold data from all 3 data sources.
Values of different variables can be presented in 5 different shapes in a graph - AREA, LINE1, LINE2, LINE3, and STACK. AREA is represented by a solid colored area with values as the boundary of this area. LINE1/2/3 (increasing width) are just plain lines representing the values. STACK is also an area but it is ``stack''ed on AREA or LINE1/2/3. Another important thing to note, is that variables are plotted in the order they are defined in graph command. So, care must be taken to define STACK only after defining AREA/LINE. It is also possible to put formatted comments within the graph. Detailed instructions be found under graph manual.
Shell script (collects data, updates database)
#!/bin/sh a=0 while [ "$a" == 0 ]; do snmpwalk -c public 192.168.1.250 hrSWRunPerfMem > snmp_reply total_mem=`awk 'BEGIN {tot_mem=0} { if ($NF == "KBytes") {tot_mem=tot_mem+$(NF-1)} } END {print tot_mem}' snmp_reply` # I can use N as a replacement for the current time rrdtool update target.rrd N:$total_mem # sleep until the next 300 seconds are full perl -e 'sleep 300 - time % 300' done # end of while loop
Perl script (retrieves data from database and generates graphs and statistics)
#!/usr/bin/perl -w #This script fetch data from target.rrd, creates graph of memory consumption on target (Dual P3 Processor 1 GHz, 656 MB RAM)
#calling RRD perl module use lib qw( /usr/rrdtool-1.0.41/lib/perl ../lib/perl ); use RRDs; my $cur_time = time(); # setting current time my $end_time = $cur_time - 86400; # setting end time to 24 hours behind current time my $start_time = $end_time - 2592000; # setting start time to 30 days from end time
#fetching average values from rrd database between start and end time my ($start,$step,$ds_names,$data) = RRDs::fetch("target.rrd", "AVERAGE", "-r", "600", "-s", "$start_time", "-e", "$end_time"); #saving fetched values in 2-dimensional array my $rows = 0; my $columns = 0; my $time_variable = $start; foreach $line (@$data) { $vals[$rows][$columns] = $time_variable; $time_variable = $time_variable + $step; foreach $val (@$line) { $vals[$rows][++$columns] = $val;} $rows++; $columns = 0; } my $tot_time = 0; my $count = 0; #saving values from 2-dimensional into 1-dimensional array for $i ( 0 .. $#vals ) $tot_mem[$count] = $vals[$i][1]; $count++; } my $tot_mem_sum = 0; #calculating total of all values for $i ( 0 .. ($count-1) ) { $tot_mem_sum = $tot_mem_sum + $tot_mem[$i]; } #calculating average of array my $tot_mem_ave = $tot_mem_sum/($count); #creating graph RRDs::graph ("/images/mem_$count.png", \ "--title= Memory Usage", \ "--vertical-label=Memory Consumption (MB)", \ "--start=$start_time", \ "--end=$end_time", \ "--color=BACK#CCCCCC", \ "--color=CANVAS#CCFFFF", \ "--color=SHADEB#9999CC", \ "--height=125", \ "--upper-limit=656", \ "--lower-limit=0", \ "--rigid", \ "--base=1024", \ "DEF:tot_mem=target.rrd:mem:AVERAGE", \ "CDEF:correct_tot_mem=tot_mem,0,671744,LIMIT,UN,0,tot_mem,IF,1024,/",\ "CDEF:machine_mem=tot_mem,656,+,tot_mem,-",\ "COMMENT:Memory Consumption between $start_time",\ "COMMENT: and $end_time ",\ "HRULE:656#000000:Maximum Available Memory - 656 MB",\ "AREA:machine_mem#CCFFFF:Memory Unused", \ "AREA:correct_tot_mem#6699CC:Total memory consumed in MB"); my $err=RRDs::error; if ($err) {print "problem generating the graph: $err\n";} #printing the output print "Average memory consumption is "; printf "%5.2f",$tot_mem_ave/1024; print " MB. Graphical representation can be found at /images/mem_$count.png.";
Закладки на сайте Проследить за страницей |
Created 1996-2024 by Maxim Chirkov Добавить, Поддержать, Вебмастеру |