Code

Imported upstream SVN snapshot 1.4~rc2+20090928.
[pkg-rrdtool.git] / doc / rrd-beginners.html
1 <?xml version="1.0" ?>
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3 <html xmlns="http://www.w3.org/1999/xhtml">
4 <head>
5 <title>rrd-beginners</title>
6 <meta http-equiv="content-type" content="text/html; charset=utf-8" />
7 <link rev="made" href="mailto:root@localhost" />
8 </head>
10 <body style="background-color: white">
13 <!-- INDEX BEGIN -->
14 <div name="index">
15 <p><a name="__index__"></a></p>
16 <!--
18 <ul>
20         <li><a href="#name">NAME</a></li>
21         <li><a href="#synopsis">SYNOPSIS</a></li>
22         <li><a href="#description">DESCRIPTION</a></li>
23         <ul>
25                 <li><a href="#what_makes_rrdtool_so_special">What makes RRDtool so special?</a></li>
26                 <li><a href="#understanding_by_an_example">Understanding by an example</a></li>
27                 <li><a href="#graphical_magic">Graphical Magic</a></li>
28                 <li><a href="#wrapping_rrdtool_within_shell_perl_script">Wrapping RRDtool within Shell/Perl script</a></li>
29                 <ul>
31                         <li><a href="#shell_script__collects_data__updates_database_">Shell script (collects data, updates database)</a></li>
32                         <li><a href="#perl_script__retrieves_data_from_database_and_generates_graphs_and_statistics_">Perl script (retrieves data from database and generates graphs and statistics)</a></li>
33                 </ul>
35         </ul>
37         <li><a href="#author">AUTHOR</a></li>
38 </ul>
40 -->
43 </div>
44 <!-- INDEX END -->
46 <p>
47 </p>
48 <h1><a name="name">NAME</a></h1>
49 <p>rrd-beginners - RRDtool Beginners' Guide</p>
50 <p>
51 </p>
52 <hr />
53 <h1><a name="synopsis">SYNOPSIS</a></h1>
54 <p>Helping new RRDtool users to understand the basics of RRDtool</p>
55 <p>
56 </p>
57 <hr />
58 <h1><a name="description">DESCRIPTION</a></h1>
59 <p>This manual is an attempt to assist beginners in understanding the concepts
60 of RRDtool. It sheds a light on differences between RRDtool and other
61 databases. With help of an example, it explains the structure of RRDtool
62 database. This is followed by an overview of the &quot;graph&quot; feature of RRDtool.
63 At the end, it has sample scripts that illustrate the
64 usage/wrapping of RRDtool within Shell or Perl scripts.</p>
65 <p>
66 </p>
67 <h2><a name="what_makes_rrdtool_so_special">What makes RRDtool so special?</a></h2>
68 <p>RRDtool is GNU licensed software developed by Tobias Oetiker, a system
69 manager at the Swiss Federal Institute of Technology. Though it is a
70 database, there are distinct differences between RRDtool databases and other
71 databases as listed below:</p>
72 <ul>
73 <li>
74 <p>RRDtool stores data; that makes it a back-end tool. The RRDtool command set
75 allows the creation of graphs; that makes it a front-end tool as well. Other
76 databases just store data and can not create graphs.</p>
77 </li>
78 <li>
79 <p>In case of linear databases, new data gets appended at the bottom of
80 the database table. Thus its size keeps on increasing, whereas the size of
81 an RRDtool database is determined at creation time. Imagine an RRDtool
82 database as the perimeter of a circle. Data is added along the
83 perimeter. When new data reaches the starting point, it overwrites
84 existing data. This way, the size of an RRDtool database always
85 remains constant. The name &quot;Round Robin&quot; stems from this behavior.</p>
86 </li>
87 <li>
88 <p>Other databases store the values as supplied. RRDtool can be configured to
89 calculate the rate of change from the previous to the current value and
90 store this information instead.</p>
91 </li>
92 <li>
93 <p>Other databases get updated when values are supplied. The RRDtool database
94 is structured in such a way that it needs data at predefined time
95 intervals. If it does not get a new value during the interval, it stores an
96 UNKNOWN value for that interval. So, when using the RRDtool database, it is
97 imperative to use scripts that run at regular intervals to ensure a constant
98 data flow to update the RRDtool database.</p>
99 </li>
100 </ul>
101 <p>RRDtool is designed to store time series of data. With every data
102 update, an associated time stamp is stored. Time is always expressed
103 in seconds passed since epoch (01-01-1970). RRDtool can be installed
104 on Unix as well as Windows. It comes with a command set to carry out
105 various operations on RRD databases. This command set can be accessed
106 from the command line, as well as from Shell or Perl scripts. The
107 scripts act as wrappers for accessing data stored in RRDtool
108 databases.</p>
109 <p>
110 </p>
111 <h2><a name="understanding_by_an_example">Understanding by an example</a></h2>
112 <p>The structure of an RRD database is different than other linear databases.
113 Other databases define tables with columns, and many other parameters. These
114 definitions sometimes are very complex, especially in large databases.
115 RRDtool databases are primarily used for monitoring purposes and
116 hence are very simple in structure. The parameters
117 that need to be defined are variables that hold values and archives of those
118 values. Being time sensitive, a couple of time related parameters are also
119 defined. Because of its structure, the definition of an RRDtool database also
120 includes a provision to specify specific actions to take in the absence of
121 update values. Data Source (DS), heartbeat, Date Source Type (DST), Round
122 Robin Archive (RRA), and Consolidation Function (CF) are some of the
123 terminologies related to RRDtool databases.</p>
124 <p>The structure of a database and the terminology associated with it can be
125 best explained with an example.</p>
126 <pre>
127  rrdtool create target.rrd \
128          --start 1023654125 \
129          --step 300 \
130          DS:mem:GAUGE:600:0:671744 \
131          RRA:AVERAGE:0.5:12:24 \
132          RRA:AVERAGE:0.5:288:31</pre>
133 <p>This example creates a database named <em class="file">target.rrd</em>. Start time
134 (1'023'654'125) is specified in total number of seconds since epoch
135 (time in seconds since 01-01-1970). While updating the database, the
136 update time is also specified.  This update time MUST be large (later)
137 then start time and MUST be in seconds since epoch.</p>
138 <p>The step of 300 seconds indicates that database expects new values every
139 300 seconds. The wrapper script should be scheduled to run every <strong>step</strong>
140 seconds so that it updates the database every <strong>step</strong> seconds.</p>
141 <p>DS (Data Source) is the actual variable which relates to the parameter on
142 the device that is monitored. Its syntax is</p>
143 <pre>
144  DS:variable_name:DST:heartbeat:min:max</pre>
145 <p><strong>DS</strong> is a key word. <code>variable_name</code> is a name under which the parameter is
146 saved in the database. There can be as many DSs in a database as needed. After
147 every step interval, a new value of DS is supplied to update the database.
148 This value is also called Primary Data Point <strong>(PDP)</strong>. In our example
149 mentioned above, a new PDP is generated every 300 seconds.</p>
150 <p>Note, that if you do NOT supply new datapoints exactly every 300 seconds,
151 this is not a problem, RRDtool will interpolate the data accordingly.</p>
152 <p><strong>DST</strong> (Data Source Type) defines the type of the DS. It can be
153 COUNTER, DERIVE, ABSOLUTE, GAUGE. A DS declared as COUNTER will save
154 the rate of change of the value over a step period. This assumes that
155 the value is always increasing (the difference between the current and
156 the previous value is greater than 0). Traffic counters on a router
157 are an ideal candidate for using COUNTER as DST. DERIVE is the same as
158 COUNTER, but it allows negative values as well. If you want to see the
159 rate of <em>change</em> in free diskspace on your server, then you might
160 want to use the DERIVE data type. ABSOLUTE also saves the rate of
161 change, but it assumes that the previous value is set to 0. The
162 difference between the current and the previous value is always equal
163 to the current value. Thus it just stores the current value divided by
164 the step interval (300 seconds in our example). GAUGE does not save
165 the rate of change. It saves the actual value itself. There are no
166 divisions or calculations. Memory consumption in a server is a typical
167 example of gauge. The difference between the different types DSTs can be
168 explained better with the following example:</p>
169 <pre>
170  Values       = 300, 600, 900, 1200
171  Step         = 300 seconds
172  COUNTER DS   =    1,  1,   1,    1
173  DERIVE DS    =    1,  1,   1,    1
174  ABSOLUTE DS  =    1,  2,   3,    4
175  GAUGE DS     = 300, 600, 900, 1200</pre>
176 <p>The next parameter is <strong>heartbeat</strong>. In our example, heartbeat is 600
177 seconds. If the database does not get a new PDP within 300 seconds, it
178 will wait for another 300 seconds (total 600 seconds).  If it doesn't
179 receive any PDP within 600 seconds, it will save an UNKNOWN value into
180 the database. This UNKNOWN value is a special feature of RRDtool - it
181 is much better than to assume a missing value was 0 (zero) or any
182 other number which might also be a valid data value.  For example, the
183 traffic flow counter on a router keeps increasing. Lets say, a value
184 is missed for an interval and 0 is stored instead of UNKNOWN. Now when
185 the next value becomes available, it will calculate the difference
186 between the current value and the previous value (0) which is not
187 correct. So, inserting the value UNKNOWN makes much more sense here.</p>
188 <p>The next two parameters are the minimum and maximum value,
189 respectively. If the variable to be stored has predictable maximum and
190 minimum values, this should be specified here. Any update value
191 falling out of this range will be stored as UNKNOWN.</p>
192 <p>The next line declares a round robin archive (RRA). The syntax for
193 declaring an RRA is</p>
194 <pre>
195  RRA:CF:xff:step:rows</pre>
196 <p>RRA is the keyword to declare RRAs. The consolidation function (CF)
197 can be AVERAGE, MINIMUM, MAXIMUM, and LAST. The concept of the
198 consolidated data point (CDP) comes into the picture here. A CDP is
199 CFed (averaged, maximum/minimum value or last value) from <em>step</em>
200 number of PDPs. This RRA will hold <em>rows</em> CDPs.</p>
201 <p>Lets have a look at the example above. For the first RRA, 12 (steps)
202 PDPs (DS variables) are AVERAGEed (CF) to form one CDP. 24 (rows) of
203 theses CDPs are archived. Each PDP occurs at 300 seconds. 12 PDPs
204 represent 12 times 300 seconds which is 1 hour. It means 1 CDP (which
205 is equal to 12 PDPs) represents data worth 1 hour. 24 such CDPs
206 represent 1 day (1 hour times 24 CDPs). This means, this RRA is an
207 archive for one day. After 24 CDPs, CDP number 25 will replace the 1st
208 CDP. The second RRA saves 31 CDPs; each CPD represents an AVERAGE
209 value for a day (288 PDPs, each covering 300 seconds = 24
210 hours). Therefore this RRA is an archive for one month. A single
211 database can have many RRAs. If there are multiple DSs, each
212 individual RRA will save data for all the DSs in the database. For
213 example, if a database has 3 DSs and daily, weekly, monthly, and
214 yearly RRAs are declared, then each RRA will hold data from all 3 data
215 sources.</p>
216 <p>
217 </p>
218 <h2><a name="graphical_magic">Graphical Magic</a></h2>
219 <p>Another important feature of RRDtool is its ability to create
220 graphs. The &quot;graph&quot; command uses the &quot;fetch&quot; command internally to
221 retrieve values from the database. With the retrieved values it draws
222 graphs as defined by the parameters supplied on the command line. A
223 single graph can show different DS (Data Sources) from a database. It
224 is also possible to show the values from more than one database in a
225 single graph. Often, it is necessary to perform some math on the
226 values retrieved from the database before plotting them. For example,
227 in SNMP replies, memory consumption values are usually specified in
228 KBytes and traffic flow on interfaces is specified in Bytes. Graphs
229 for these values will be more meaningful if values are represented in
230 MBytes and mbps. The RRDtool graph command allows to define such
231 conversions. Apart from mathematical calculations, it is also possible
232 to perform logical operations such as greater than, less than, and
233 if/then/else. If a database contains more than one RRA archive, then a
234 question may arise - how does RRDtool decide which RRA archive to use
235 for retrieving the values? RRDtool looks at several things when making
236 its choice. First it makes sure that the RRA covers as much of the
237 graphing time frame as possible. Second it looks at the resolution of
238 the RRA compared to the resolution of the graph. It tries to find one
239 which has the same or higher better resolution. With the &quot;-r&quot; option
240 you can force RRDtool to assume a different resolution than the one
241 calculated from the pixel width of the graph.</p>
242 <p>Values of different variables can be presented in 5 different shapes
243 in a graph - AREA, LINE1, LINE2, LINE3, and STACK. AREA is represented
244 by a solid colored area with values as the boundary of this
245 area. LINE1/2/3 (increasing width) are just plain lines representing
246 the values. STACK is also an area but it is &quot;stack&quot;ed on top AREA or
247 LINE1/2/3. Another important thing to note is that variables are
248 plotted in the order they are defined in the graph command. Therefore
249 care must be taken to define STACK only after defining AREA/LINE. It
250 is also possible to put formatted comments within the graph.  Detailed
251 instructions can be found in the graph manual.</p>
252 <p>
253 </p>
254 <h2><a name="wrapping_rrdtool_within_shell_perl_script">Wrapping RRDtool within Shell/Perl script</a></h2>
255 <p>After understanding RRDtool it is now a time to actually use RRDtool
256 in scripts. Tasks involved in network management are data collection,
257 data storage, and data retrieval. In the following example, the
258 previously created target.rrd database is used. Data collection and
259 data storage is done using Shell scripts. Data retrieval and report
260 generation is done using Perl scripts. These scripts are shown below:</p>
261 <p>
262 </p>
263 <h3><a name="shell_script__collects_data__updates_database_">Shell script (collects data, updates database)</a></h3>
264 <pre>
265  #!/bin/sh
266  a=0
267  while [ &quot;$a&quot; == 0 ]; do
268  snmpwalk -c public 192.168.1.250 hrSWRunPerfMem &gt; snmp_reply
269      total_mem=`awk 'BEGIN {tot_mem=0}
270                            { if ($NF == &quot;KBytes&quot;)
271                              {tot_mem=tot_mem+$(NF-1)}
272                            }
273                      END {print tot_mem}' snmp_reply`
274      # I can use N as a replacement for the current time
275      rrdtool update target.rrd N:$total_mem
276      # sleep until the next 300 seconds are full
277      perl -e 'sleep 300 - time % 300'
278  done # end of while loop</pre>
279 <p>
280 </p>
281 <h3><a name="perl_script__retrieves_data_from_database_and_generates_graphs_and_statistics_">Perl script (retrieves data from database and generates graphs and statistics)</a></h3>
282 <pre>
283  #!/usr/bin/perl -w
284  # This script fetches data from target.rrd, creates a graph of memory
285  # consumption on the target (Dual P3 Processor 1 GHz, 656 MB RAM)</pre>
286 <pre>
287  # call the RRD perl module
288  use lib qw( /usr/local/rrdtool-1.0.41/lib/perl ../lib/perl );
289  use RRDs;
290  my $cur_time = time();                # set current time
291  my $end_time = $cur_time - 86400;     # set end time to 24 hours ago
292  my $start_time = $end_time - 2592000; # set start 30 days in the past</pre>
293 <pre>
294  # fetch average values from the RRD database between start and end time
295  my ($start,$step,$ds_names,$data) =
296      RRDs::fetch(&quot;target.rrd&quot;, &quot;AVERAGE&quot;,
297                  &quot;-r&quot;, &quot;600&quot;, &quot;-s&quot;, &quot;$start_time&quot;, &quot;-e&quot;, &quot;$end_time&quot;);
298  # save fetched values in a 2-dimensional array
299  my $rows = 0;
300  my $columns = 0;
301  my $time_variable = $start;
302  foreach $line (@$data) {
303    $vals[$rows][$columns] = $time_variable;
304    $time_variable = $time_variable + $step;
305    foreach $val (@$line) {
306            $vals[$rows][++$columns] = $val;}
307    $rows++;
308    $columns = 0;
309  }
310  my $tot_time = 0;
311  my $count = 0;
312  # save the values from the 2-dimensional into a 1-dimensional array
313  for $i ( 0 .. $#vals ) {
314      $tot_mem[$count] = $vals[$i][1];
315      $count++;
316  }
317  my $tot_mem_sum = 0;
318  # calculate the total of all values
319  for $i ( 0 .. ($count-1) ) {
320      $tot_mem_sum = $tot_mem_sum + $tot_mem[$i];
321  }
322  # calculate the average of the array
323  my $tot_mem_ave = $tot_mem_sum/($count);
324  # create the graph
325  RRDs::graph (&quot;/images/mem_$count.png&quot;,   
326              &quot;--title= Memory Usage&quot;,    
327              &quot;--vertical-label=Memory Consumption (MB)&quot;, 
328              &quot;--start=$start_time&quot;,      
329              &quot;--end=$end_time&quot;,          
330              &quot;--color=BACK#CCCCCC&quot;,      
331              &quot;--color=CANVAS#CCFFFF&quot;,    
332              &quot;--color=SHADEB#9999CC&quot;,    
333              &quot;--height=125&quot;,             
334              &quot;--upper-limit=656&quot;,        
335              &quot;--lower-limit=0&quot;,          
336              &quot;--rigid&quot;,                  
337              &quot;--base=1024&quot;,              
338              &quot;DEF:tot_mem=target.rrd:mem:AVERAGE&quot;, 
339              &quot;CDEF:tot_mem_cor=tot_mem,0,671744,LIMIT,UN,0,tot_mem,IF,1024,/&quot;,
340              &quot;CDEF:machine_mem=tot_mem,656,+,tot_mem,-&quot;,
341              &quot;COMMENT:Memory Consumption between $start_time&quot;,
342              &quot;COMMENT:    and $end_time                     &quot;,
343              &quot;HRULE:656#000000:Maximum Available Memory - 656 MB&quot;,
344              &quot;AREA:machine_mem#CCFFFF:Memory Unused&quot;,   
345              &quot;AREA:tot_mem_cor#6699CC:Total memory consumed in MB&quot;);
346  my $err=RRDs::error;
347  if ($err) {print &quot;problem generating the graph: $err\n&quot;;}
348  # print the output
349  print &quot;Average memory consumption is &quot;;
350  printf &quot;%5.2f&quot;,$tot_mem_ave/1024;
351  print &quot; MB. Graphical representation can be found at /images/mem_$count.png.&quot;;</pre>
352 <p>
353 </p>
354 <hr />
355 <h1><a name="author">AUTHOR</a></h1>
356 <p>Ketan Patel &lt;<a href="mailto:k2pattu@yahoo.com">k2pattu@yahoo.com</a>&gt;</p>
358 </body>
360 </html>