<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:wfw="http://wellformedweb.org/CommentAPI/">
<channel>
<title>dwt&#039;s life - RRD</title>
<link>https://www.dwt.life/tag/RRD/</link>
<atom:link href="https://www.dwt.life/feed/tag/RRD/" rel="self" type="application/rss+xml" />
<language>zh-CN</language>
<description></description>
<lastBuildDate>Wed, 30 Jun 2021 13:48:00 +0800</lastBuildDate>
<pubDate>Wed, 30 Jun 2021 13:48:00 +0800</pubDate>
<item>
<title>RRD浅析</title>
<link>https://www.dwt.life/archives/15/</link>
<guid>https://www.dwt.life/archives/15/</guid>
<pubDate>Wed, 30 Jun 2021 13:48:00 +0800</pubDate>
<dc:creator>Ricky</dc:creator>
<description><![CDATA[本文是对开源监控工具Ganglia使用的RRD数据库的一个简单介绍，此外还有一些有关RRDTool的基本操作。RRD数据库RRD是Round Robin Database的缩写，是一种环形数据库...]]></description>
<content:encoded xml:lang="zh-CN"><![CDATA[
<p>本文是对开源监控工具Ganglia使用的RRD数据库的一个简单介绍，此外还有一些有关RRDTool的基本操作。</p><h1>RRD数据库</h1><p>RRD是Round Robin Database的缩写，是一种环形数据库，它是专门设计来存储时序数据的。每当有新的数据到来时，一般也会有一个时间戳伴随着被存储起来，这里的时间戳是epoch值。RRDTool是RRD数据库配套的一个工具，它可以安装在Unix或者Windows系统上，RRDTool提供了一系列的命令集来对RRD进行不同的操作。</p><p>RRD数据库与其他数据库的不同:</p><p>RRDTool既是后端工具，又是前端工具；之所以这么说，是因为作为数据库，首先RRDTool可以存储数据，此外，RRDTool也提供了一个根据数据库数据进行绘图的功能，这让它具备了前端的特性。</p><p><img src="https://pic.8oh.com.cn/cos/2021/06/30/3b06f3c28d2d3_1625031953.png" alt=" title="截图"" title=" title="截图""></p><p>对于线性数据库，一般新的数据都被插入到数据库表的最后，所以数据库的大小随着数据的插入而不断的增长；而对于RRD数据库，其大小在创建时就已经指定。简单的说，可以把RRD数据库想象成一个环，数据都被插入到环的周边，有一个指针时钟指向新的数据要插入到的位置，当指针达到起始点时，就会覆盖原来存在的数据，这样一来，数据库的大小就固定不变了，这也是“Round Robin”的由来。</p><p>其他数据库的数据都是被提供的，而RRD数据库可以通过配置，来计算旧的数据到新的数据之间的变化，并把这些信息存储起来。<br>其他数据库更新的驱动是新的数据被提供，而RRD数据库的更新是按照按照预先定义的时间间隔来进行的；如果在固定的事件间隔内没有获得新的数据，那么RRDTool将会存储一个UNKNOWN值，所以一般使用RRD数据库都会有一个脚本每隔一段时间就向RRD提供一个数据。</p><h1>RRD的基本结构</h1><p>因为RRD数据库设计目的是监控，所以它的结构比较简单，创建一个RRD数据库的方式如下：</p><pre><code>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</code></pre><p>下面是相关的一些基本概念：</p><p>DS: Data Source, 它指的是设备上被监控的变量，一个RRD数据库中可能有多个DS。其声明格式如下：</p><blockquote>DS:variable_name:DST:heartbeat:min:max</blockquote><p>每隔一个step, DS的一个新的值就会到来，然后数据库就会被更新，这个值也被叫做 PDP(Primary Data Point)，PDP的范围由min,max来制定，如果在heartbeat时间内没有 收到数据，那么该PDP就会被置为UNKNOWN。在上面的例子中，每隔300s就会产生一个新的 PDP。</p><p>DST: Data Source Type, 指的是DS的类型，可以是COUNTER, DERIVE, ABSOLUTE, GAUGE，详细解释如下表：</p><p><img src="https://pic.8oh.com.cn/cos/2021/06/30/ac669ca6c8351_1625032200.png" alt="1625032199147.png" title="1625032199147.png"></p><p>CF: Consolidation Function, 是指合并数据的方式，可选的有AVERAGE, MAX, MIN, LAST。</p><p>RRA: Round Robin Archive, 是对采集到的数据以某种方式(CF)的归档。声明格式如下</p><blockquote>RRA:CF:xff:step:rows</blockquote><p>在这里又有一个新的概念CDP(consolidated data point), 一个CPD是把step个PDP按照指定的CF进行合并得到的一个数值，而这个RRA中包含rows个CDPs。这里的xff是指CDP合并时允许出现的UNKNOWN的最大比率，在本例中即是，如果step个PDP中有一半是UNKNOWN，那么该CDP是UKNOWN,否则就去不是UKNOWN值的平均值。如下图是RRA的结构以及数据更新的方式：</p><p><img src="https://pic.8oh.com.cn/cos/2021/06/30/8a349d96a33be_1625032260.png" alt="1625032258688.png" title="1625032258688.png"></p><p>如图所示，在RRD数据库中会为一个RRA分配一部分空间，n(step)个sample(PDP)合并成一个CDP然后存储到这块区域的开头位置，如果空间已满则旧的数据会被覆盖，这样的方式就保证了数据库的大小是不会增长的，同时将PDP合并成CDP的做法，又可以保证RRD可以存储很长一段时间的数据。</p><p>了解了这些基本概念之后，上面的这个例子就比较容易理解了,首先给这个数据库命名为target.rrd，数据的开始时间是epoch时间1023654125，每隔300s获取一个PDP，然后DS制定了实际被监控的变量及其类型和值域，最后定义了两个RRA，对于第一个RRA, 12(steps)个PDPs以平均(CF)的方式进行合并得到一个CDP，24个这样的CDP组成一个RRA归档。PDP之间的间隔是300s,所以CDP之间的间隔就是12*300，即1小时，24个这样的CDP就是1天，因此我们可以得知，第一个RRA就是mem的一天的监控统计。</p><h1>RRDTool常用命令</h1><h2>rrdtool dump</h2><blockquote>rrdtool dump filename.rrd [filename.xml] [–header|-h {none,xsd,dtd}] [–no-header|-n] [–daemon|-d address] [&gt; filename.xml]</blockquote><p>含义：将一个rrd数据库导出为xml文件<br>示例：<br><code>rrdtool dump load_one.rrd test.xml</code></p><h2>rrdtool fetch</h2><blockquote>rrdtool fetch filename CF [–resolution|-r resolution] [–start|-s start] [–end|-e end] [–align-start|-a] [–daemon|-d address]</blockquote><p>含义：从一个rrd数据库根据条件取出数据<br>示例：</p><pre><code>rrdtool fetch load_one.rrd AVERAGE -r 12 -s e-1200 -e now</code></pre><h2>rrdtool xport</h2><blockquote>rrdtool xport [-s|–start seconds] [-e|–end seconds] [-m|–maxrows rows] [–step value] [–json] [–enumds] [–daemon|-d address] [DEF:vname=rrd:ds-name:CF] [CDEF:vname=rpn-expression] [XPORT:vname[:legend]]</blockquote><p>含义：可以从若干个RRD中得到XML或JSON格式的数据。<br>示例：</p><pre><code>rrdtool xport --start end-1h --end now --step 10 
DEF:ds1=load_one.rrd:sum:AVERAGE DEF:ds2=load_one.rrd:num:AVERAGE XPORT:ds1:sum XPORT:ds2:num</code></pre><h2>rrdtool graph</h2><blockquote>rrdtool graph|graphv filename [option …] [data definition …] [data calculation …] [variable definition …] [graph element …] [print element …]</blockquote><p>含义：根据RRD数据库中的数据绘制图形，生成图片。<br>示例：</p><pre><code>rrdtool graph new.png --end now --start end-150 --title cpu_user --vertical-label % --width 250 --height 150 DEF:ds=cpu_user.rrd:sum:AVERAGE:step=3 AREA:ds#0000FF:cpu_user</code></pre><p>生成的图片：<br><img src="https://pic.8oh.com.cn/cos/2021/06/30/dbbab11cf7ca7_1625032286.png" alt="1625032285027.png" title="1625032285027.png"></p>
]]></content:encoded>
<slash:comments>0</slash:comments>
<comments>https://www.dwt.life/archives/15/#comments</comments>
<wfw:commentRss>https://www.dwt.life/feed/tag/RRD/</wfw:commentRss>
</item>
<item>
<title>RRD 数据库简介及操作</title>
<link>https://www.dwt.life/archives/13/</link>
<guid>https://www.dwt.life/archives/13/</guid>
<pubDate>Wed, 30 Jun 2021 13:35:00 +0800</pubDate>
<dc:creator>Ricky</dc:creator>
<description><![CDATA[RRD 数据库简介及操作最近公司在部署了一套小米开源的监控平台 — open-falcon，有机会认识了 RRD(更多被称作 RRDTool)。好久没 blog 了，今天跟大家分享一下这个数据库...]]></description>
<content:encoded xml:lang="zh-CN"><![CDATA[
<p>RRD 数据库简介及操作<br>最近公司在部署了一套小米开源的监控平台 — open-falcon，有机会认识了 RRD(更多被称作 RRDTool)。好久没 blog 了，今天跟大家分享一下这个数据库。</p><p>RRD 简介</p><blockquote><p>RRDtool refers to Round Robin Database tool.</p><p>Round robin is a technique that works with a fixed amount of data, and<br>a pointer to the current element.</p><p>Think of a circle with some dots plotted on the edge. These dots are<br>the places where data can be stored.</p><p>Draw an arrow from the center of the circle to one of the dots; this<br>is the pointer.</p><p>When the current data is read or written, the pointer moves to the<br>next element.</p><p>As we are on a circle there is neither a beginning nor an end, you can<br>go on and on and on.</p><p>After a while, all the available places will be used and the process<br>automatically reuses old locations.</p><p>This way, the dataset will not grow in size and therefore requires no<br>maintenance.</p><p>RRDtool works with Round Robin Databases (RRDs). It stores and<br>retrieves data from them.</p></blockquote><p>以上摘自RRDTool 官网的表述。</p><p>RRD 数据库是一个环形的数据库，你可以把它想象成表，中心处有一个指针，随着时间的变化，指针也在变，当指针指到 12 点处，也就是这个记录要被擦除覆盖的时候，所以它是大小固定的。</p><p>总结起来，RRD 的关键词就是：</p><p>环形、大小固定、无需运维、绘图</p><p>时序数据库<br>看完 RRD 的简介，尤其是它的关键词，是不觉得“我靠这么nb”。数据库按照功能和种类可以分成很多，各自术业有专攻，针对专门的领域进行数据存储。比如 mysql 的优势就是存储结构型数据，nosql 就是针对非结构型数据的。</p><p>在运维领域里，需要不断的对服务器、交换机等支持性设备的性能和运行进行监控，这类监控的数据的特点就是跟着时间走 —— 它们的指标只会随着时间的变化而变化，不会涉及回头修改。这就区别于常见的数据库，会不断的修改历史数据，对数据进行 U（pdate） 操作。</p><p>所以就应运而生了一系列数据库，名曰“时序数据库”。常见的时序数据库有：influxdb、opentsdb、rrd 等。</p><p>其实如果你对 mysql 的引擎有足够了解的话，除了常见的 innodb 和 myisam ，还有一个引擎叫 archive ，它的作用和 rrd 差不多，支持插入和查询操作，比较专。</p><p>RRD 的安装<br>我的环境是 centos6.5 。<br>安装的 rrdtool 版本是 1.4.7 ，源码安装。</p><pre><code>wget http://oss.oetiker.ch/rrdtool/pub/rrdtool-1.4.7.tar.gz
tar zxvf rrdtool-1.4.7.tar.gz
cd rrdtool-1.4.7
./configure --prefix=/usr/local
make
make install</code></pre><p>至此 rrdtool 的安装已经完成。读者要是缺啥依赖，请自行 google || baidu 解决。</p><p>RRD 的操作<br>下面介绍一下 RRD 数据库的操作，包括创建、增、查、绘：</p><p>创建<br>命令：</p><pre><code>rrdtool create filename \
               [--start|-b start time] \
               [--step|-s step] \
               [DS:ds-name:DST:heartbeat:min:max] \
               [RRA:CF:xff:steps:rows] \

               [--template|-t template-file] \
               [--source|-r source-file] \
               [--no-overwrite|-O] \
               [--daemon|-d address] </code></pre><p>例子：</p><pre><code>rrdtool create test.rrd             \
            --start 1469341292       \
            DS:speed:COUNTER:600:U:U  \
            RRA:AVERAGE:0.5:1:24       \
            RRA:AVERAGE:0.5:6:10</code></pre><p>讲解：</p><p>命令中，有用的基本上只有前五行，逐行解释。<br><code>rrdtool create filename</code></p><p>这个一看就很明白，就是通过 rrdtool 命令进行数据库创建，名为 filename 。<br>例子里创建了一个名为 test.rrd 的数据库，其中 .rrd 为 rrd 数据库的后缀名。</p><p>[--start|-b start time] </p><p>这句的意思是要指明该数据库的起始时间戳，例如例子中的 1469341292 是一个写此文的 unix timestamp 。<br>你当然要指明起始时间了，因为这是时序数据库，肯定得有一个开始。</p><p>[--step|-s step]</p><p>这个 step 的意思是“你多久向数据库上报一次数据”，以秒为单位。例如例子中的，噢，例子里没有。。。。好吧，默认是 300s 一上报，也就是 5 分钟一上报，你可以按自己的需求上报。</p><p>[DS:ds-name:DST:heartbeat:min:max]</p><p>这个复杂些，我们拆开看。<br>DS， DataSource，数据源，后面 ds-name 是需要你来指明的，比如，我给我们的数据源起个标示名为：speed。意思是，我这个数据库里面记录的都是关于 speed 的数据。<br>DST， DataSourceType，数据源类型，DST 是你需要指明的。有几个选择，其中有 4 个是常用的，来说一下：</p><p>COUNTER，<br>GAUGE<br>DERIVE<br>ABSOLUTE<br>举例说明他们之间的不同：</p><p>我在 10:30 和 10:31 分别插入了两个数据：<br>10:30 600<br>10:31 1200</p><p>那么如果你的 DST 是</p><p>COUNTER，(1200-600)/step = 600/300 = 2，这个结果 2 就是最后要往数据库里插入的数据，并且是 10:31 时刻的数值。<br>GAUGE，10:30 的值是600,10:31 的值是1200 。都是原值存储，这个是最常用的。<br>DERIVE，他的原理跟 COUNTER 一样，不同的是 COUNTER 只能递增，但是 DERIVE 可增可减。比如，对于 COUNTER ，10:30 是 600 ， 10:31 是 1200 ， 那么 10:32 的值必须大于 1200 ；但是 DERIVE 在 10:32 的值可以是小于 1200 的。<br>ABSOLUTE，这个是直接做均值，600/step = 1 , 1200/step = 2， 所以 10:30 的值是 1 ， 10:31 的值是 2 。<br>heartbeat ， 心跳。心跳的意思，我自己经过实践和文档，总结出来心跳是跟 step 配合使用的。还是举例：</p><p>比如，我的 step 是 60s 上报一次数据<br>如果我的 heartbeat 是 60s ，那么 10:30 600， 10:31 没上报， 10:32 1200，这时候，图像就会在 10：31 处没有记录，也就是图像断开了；<br>如果我的 heartbeat 是 120s，那么 10:31 也会有数据，图象是不会中断的。但是，是以什么样的值来填充，是有条件的，后面说明。<br>其实说白了，这个 heartbeat 就是一个容错时间，如果在这个时间间隔内没有上传数据，那么我就不能给你绘图。</p><p>min，能接受的最小值，比如上报的数据不能小于 500 ，那你就设置这里。<br>max，同理。<br>一般这两个值都是U，表示无限。</p><p>[RRA:CF:xff:steps:rows]</p><p>这个意思是创建数据表，刚才创建的是数据库，现在创建数据表。<br>RRA：Round Robin Archive<br>CF： Consolidation Function，合成函数、合成方法。<br>rrd 提供的 CF 有下面这么几种：</p><p>Average()<br>Max()<br>Min()<br>Last()<br>这个函数是做什么的？先继续看后面的参数。</p><p>xff，这是一个小于 1 的比例值，表示正常值与异常值的比值，相当于数据的合格率，如果低于这个比例，那么该数据就算废弃。一般设置成 0.5。</p><p>steps，这个参数的意思是，多少个值通过 CF 函数合成一个值，并存入数据表。</p><p>rows，表示你这个环形的数据库有多少个格子，也就是说你这个数据表能存多少数据。</p><p>好了，合起来讲解一下这个 RRA 的命令参数。</p><p>还是举例子吧，不太好解释，举例：</p><table><thead><tr><th align="center">time</th><th align="center">PDP</th></tr></thead><tbody><tr><td align="center">10:30</td><td align="center">1.4</td></tr><tr><td align="center">10:31</td><td align="center">2.8</td></tr><tr><td align="center">10:32</td><td align="center">3.7</td></tr><tr><td align="center">10:33</td><td align="center">4.2</td></tr><tr><td align="center">10:34</td><td align="center">5.1</td></tr><tr><td align="center">10:35</td><td align="center">6.6</td></tr></tbody></table><p>RRA:CF :xff:steps:rows<br>RRA:AVERAGE:0.5:1 :24 — ①<br>RRA:AVERAGE:0.5:6 :10 — ②</p><p>如果按①来说，意思是，我这个数据表能存 24 个值，steps 是 1 ，意思是我每上报一个值就算一个存储值。这样的话， 10:30 到 10:35 上报的什么值，就存什么值：</p><table><thead><tr><th align="center">time</th><th align="center">上报</th><th align="center">存储</th></tr></thead><tbody><tr><td align="center">10:30</td><td align="center">1.4</td><td align="center">1.4</td></tr><tr><td align="center">10:31</td><td align="center">2.8</td><td align="center">2.8</td></tr><tr><td align="center">10:32</td><td align="center">3.7</td><td align="center">3.7</td></tr><tr><td align="center">10:33</td><td align="center">4.2</td><td align="center">4.2</td></tr><tr><td align="center">10:34</td><td align="center">5.1</td><td align="center">5.1</td></tr><tr><td align="center">10:35</td><td align="center">6.6</td><td align="center">6.6</td></tr></tbody></table><p>如果按②来说，意思是，我这个数据表能存10个值，steps 是 6，意思是我每上报 6 个值，求 Average() ，把结果存到数据表里：</p><table><thead><tr><th align="center">time</th><th align="center">上报</th><th align="center">存储</th></tr></thead><tbody><tr><td align="center">10:30</td><td align="center">1.4</td><td align="center"> </td></tr><tr><td align="center">10:31</td><td align="center">2.8</td><td align="center"> </td></tr><tr><td align="center">10:32</td><td align="center">3.7</td><td align="center"> </td></tr><tr><td align="center">10:33</td><td align="center">4.2</td><td align="center"> </td></tr><tr><td align="center">10:34</td><td align="center">5.1</td><td align="center"> </td></tr><tr><td align="center">10:35</td><td align="center">6.6</td><td align="center">(1.4+2.8+3.7+4.2+5.1+6.6)/6 = 3.96</td></tr></tbody></table><p>为什么会有多个 RRA ，采样，采不同时间段的样，然后当你画图的时候，给你提供最适合你要求的时间段的数据给你。</p><p>增<br>命令：</p><pre><code>rrdtool {update | updatev} filename [--template|-t ds-name[:ds-name]...] [--skip-past-updates|-s] [--daemon|-d address] [--] N:value[:value]... timestamp:value[:value]... at-timestamp@value[:value]...</code></pre><p>例子：</p><pre><code>rrdtool update test.rrd \
           1469341292:12420 \
           1469341352:12422 \
           1469341412:12423</code></pre><p>或</p><pre><code>rrdtool updatev test.rrd \
           1469341292:12420 \
           1469341352:12422 \
           1469341412:12423</code></pre><p>update 和 updatev 的区别就是多了一个 v ，罗嗦、详情。<br>没错就是这么简单。</p><p>查<br>命令：</p><p><code>rrdtool fetch filename CF [--resolution|-r resolution] [--start|-s start] [--end|-e end] [--align-start|-a] [--daemon|-d address]</code></p><p>例子：</p><p><code>rrdtool fetch test.rrd AVERAGE --start 1469341292</code></p><p>查看数据库结构的命令：</p><p><code>rrdtool info filename [--daemon|-d address [--noflush|-F]]</code></p><p>例子：<br><code>rrdtool info test.rrd</code><br>绘图<br>rrd 的主要功能分为两块，一个就是存储数据，一个就是根据数据绘图。</p><p>命令：</p><pre><code class="lang-shell">rrdtool graph|graphv filename [option ...] [data definition ...] [data calculation ...] [variable definition ...] [graph element ...] [print element ...]</code></pre><p>例子：</p><pre><code class="lang-shell">rrdtool graph test.png  \
         --start 1469341292 --end 1469341412 \
         DEF:myspeed=test.rrd:speed:AVERAGE \
         LINE2:myspeed#FF0000
</code></pre><p>这里就解释一下 DEF ：</p><p><code>DEF:myspeed=test.rrd:speed:AVERAGE</code></p><p>定义了一个 myspeed 的图，其内容来源来自于 test.rrd ， DS 名为 speed ， CF 是 AVERAGE。</p><p>python 操作<br>通过 pip 安装 rrdtool 模块，该模块可以通过 python 进行 RRD 数据库的创建、绘图等操作。</p><p><code>pip install rrdtool</code></p><p>所有的操作代码：</p><pre><code>import rrdtool

rrdtool.create(&#039;test.rrd&#039;, &#039;--start&#039;, &#039;1469341292&#039;,
&#039;--step&#039;,&#039;60&#039;,&#039;RRA:AVERAGE:0.5:1:3&#039;, &#039;DS:test:GAUGE:120:U:U&#039;)

rrdtool.update(&#039;test.rrd&#039;,&#039;1469341292:300&#039;)
rrdtool.update(&#039;test.rrd&#039;,&#039;1469341352:600&#039;)
rrdtool.update(&#039;test.rrd&#039;,&#039;1469341412:900&#039;)
rrdtool.update(&#039;test.rrd&#039;,&#039;1469341472:1200&#039;)

rrdtool.graph(&#039;test.png&#039;,&#039;--start&#039;,&#039;1469341292&#039;, &#039;--end&#039;,&#039;1469341472&#039;,&#039;DEF:myspeed=test.rrd:test:AVERAGE&#039;,&#039;LINE2:myspeed#FF0000&#039; )</code></pre><p>更过的绘图方法，可以参看<a href="http://oss.oetiker.ch/rrdtool/doc/rrdgraph.en.html">这里</a></p><h1>总结</h1><p>RRD 蛮好用。不用怎么操心，属于一劳永逸的数据库。理解起来比较费劲的是创建时候的 DS 那部分和 RRA 的参数那块。多动手操作，边实践边看本文效果更好。</p>
]]></content:encoded>
<slash:comments>0</slash:comments>
<comments>https://www.dwt.life/archives/13/#comments</comments>
<wfw:commentRss>https://www.dwt.life/feed/tag/RRD/</wfw:commentRss>
</item>
</channel>
</rss>