如果开发者未曾使用过rrdtool, 会对rrd4j中的接口迷惑, 并且rrd4j的接口说明写的不够详细, 有的参数的说明模棱两可.
rrd4j的下载地址为http://code.google.com/p/rrd4j/downloads/list,   我是翻墙下载下来的. 本文只讲rrd数据库的创建, 插入,
查询的基本操作. 我的项目并没有使用rrd4j的图表功能(不美观,且不易查看), 所以rrd4j作图功能就略掉了


首先讲一下rrdtool中的一些概念, rrd4j中的时间都是以秒为单位. 

    1. sample, 采样, 即采集到的数据, 它包括采样的时间与采样的值

    2. step ,  步长, 两次数据采样之间的时间间隔, 比如, 每1分钟记录一次数据, 步长就是60, 单位秒. 以step间隔记录
的数据点, 称之为基本数据点(英文全称Primary Data Point, 简称PDP). 以下的例子中均以step=60为参考

    3. archive, 存档, 用于存放采样数据的存储空间, 一个rrd文件可以包括多个存档,  例如下图(示意图)

PDP0

PDP1

PDP2

PDP3

PDP4

PDP5

PDP6

PDP7

PDP8

PDP9

CDP0

CDP1

CDP2

CDP3

CDP4

CDP0

CDP1


                                             图1 
上图中所描述的rrd文件包含了三个存档,  第一行是每1分钟的采样记录, 每二行是每2分钟的采样记录, 每三行是每5分钟
的采样记录. 图中CDP是指合并数据点(Consolidation Data Point), 这是由多个PDP按照一定规则计算出来了, CDP的概念可以
使数据查询量大幅度减少, 因为很多时候,图表的最小时间单位是小时或天, 并不需要精确到每分钟.

    4. heartbeat, 表面含义是心跳, 在这里, 我理解为有效时间区域,   看以下图例
rrd4j(rrdtool的java版)使用教程-LMLPHP
                                            图2
图中, 00:00:00记录数据100, 从这个时刻起, 如果在heartbeat时间内, 未记录任何数据, 那么, 00:01:00时刻的值将被标记
为未知(unknonw), 假设heartbeat=120, 那么上图中, 00:01:00时刻的值将会是150, 如果heartbean
    5. xff,   x文档系数, 这个参数的名字取的很难懂, 它的值在0.0到1.0之间.  以图1的第三行为例, 每个合并数据点(CDP)是由5(标记为n)个
PDP计算出来的, 如果这5个PDP中,部分PDP被标记为unknown, CDP则会根据xff的值来决定, 如果 超过xff*n个PDP被标记为unknown,
则CPD也将被标记为unknown. 通常计取0.5即可, 不必过多关注

    6. resolution, 时间粒度. 例如,查询全年的数据记录时, 并不需要把每分钟的数据都取出来, 只需要每天的数据取出来即可, 此时
resolution= 60 * 60 * 24.


下面结合rrd4j的具体接口来说明其使用方法

1. 创建rrd数据库

点击(此处)折叠或打开


  1. long start = System.currentTimeMillis()/1000;
  2. RrdDef rrdDef = new RrdDef("d:\\test.rrd", start, 60);

  3. rrdDef.addDatasource("users", DsType.GAUGE, 60*2, 0, Double.NaN);
  4. rrdDef.addDatasource("devices", DsType.GAUGE, 60*2, 0, Double.NaN);

  5. /** 每分钟一个存档, 两年共计 2*365*24*60 */
  6. rrdDef.addArchive(ConsolFun.AVERAGE, 0.5, 1, 2*365*24*60);
  7.                 
  8. /** 每小时一个存档, 两年共计2*365*24 */
  9. rrdDef.addArchive(ConsolFun.AVERAGE, 0.5, 60, 2*365*24);
  10.         
  11. /** 每天一个存档, 两年共计2*365 */
  12. rrdDef.addArchive(ConsolFun.AVERAGE, 0.5, 60*24, 2*365);
  13. RrdDb rrdDb = new RrdDb(rrdDef);
  14. rrdDb.close();


代码说明:
        1.1定义数据库 
            RrdDef rrdDef = new RrdDef("d:\\test.rrd", start, 60)
        定义新数据库, 每一个参数为数据库文件名, 如果文件名已经存在, 创建可能会失败,  每二个参数是数据的起始时间, 一般定义成创建此数据库时的时间, 
        第三个参数是step(秒), 本例中是每60秒记录一次数据.

        1.2 定义数据源
        rrdDef.addDatasource("users", DsType.GAUGE, 60*2, 0, Double.NaN); 
      
rrdDef.addDatasource("devices", DsType.GAUGE, 60*2, 0, Double.NaN);
        创建数据源,
        第1个参数, 相当于sql数据库中的列名.  
        第2个参数, 数据源类型, DsType.GAUGE(测量类型)表示直接把采样的值存入rrd中.
        第3个参数, 表示心跳, 一般取step*2即可
        第4, 5个参数, 表示最小值与最大值, 超出范围的值, 将被标记为unknown, 如果不明确, 则填入Double.NaN, 表示可以为任何值
       DsType其它类型介绍如下
        COUNTER,  (当前采样值-上个采样值)/间隔时间,  例如网络流量, 则使用此类型, rrd会自己计算单位时间内的流量
        DERIVE, 与COUNTER类似, 但采样数据可以是递增的,也可以是递减, 或一会递增, 一会递减
        ABSOLUTE, 当前采样的值/时间间隔
        以下面的数据为例
                                    时间点          60                120             180                  240
                                    采样值          10                50               70                   200

       DStype=GAUGE时, rrd存入         10                50                70                  200
                 =COUNTER时, 存入     10/60=1.67,   (50-10)/60     (70-50)/60       (200-70)/60   
                  =DERIVE时, 存入         10/60=1.67,   (50-10)/60     (70-50)/60       (200-70)/60
                 =ABSOLUTE时,存入     10/60=1.67,   50/60             70/60              200/60

        1.3 定义存档
        上面的代码定义了三个存档, 分别保存每分钟, 每小时, 每天的存档, 
        rrdDef.addArchive(ConsolFun.AVERAGE, 0.5, 1, 2*365*24*60);
      
第1个参数,    ConsolFun.AVERAGE表示计算CDP时,使用平均值, 
        第2个参数,   xff, 前面已经讲过了
        第3个参数,   steps, 两个采样点之间的时间间隔, 以step为基本单位, 值为1时, 则表示PDP, 
                            大于1时, 就是CDP了
        第4个参数,   rows, 表示最大存储行数, 本例中设置了两年的存储空间

        1.4 创建数据库
             RrdDb rrdDb = new RrdDb(rrdDef);
            
rrdDb.close();
      

            调用了这一步之后, rrd文件才会真正的创建.     

2. 插入数据
        下面的代码设定的是每分钟插入一次随机值

点击(此处)折叠或打开

  1. final RrdDb rrdDb = new RrdDb("d:\\test.rrd");
  2.         final Random random = new Random();
  3.         Timer timer = new Timer();
  4.         timer.schedule(new TimerTask() {
  5.             @Override
  6.             public void run() {
  7.                 Sample sample = rrdDb.createSample();
  8.                 long time = System.currentTimeMillis() / 1000;
  9.                 sample.setTime(time);
  10.                 sample.setValue("users", random.nextInt(1000));
  11.                 sample.setValue("device", random.nextInt(1000));
  12.                 sample.update();
  13.             }
  14.         }, 60 * 1000, 60 * 1000);

3. 查询数据
        下面的代码是查询2014.1.1到2015.1.1这段时间之间的users统计数据

点击(此处)折叠或打开

  1. FetchRequest request = rrdDb.createFetchRequest(
  2.                     ConsolFun.AVERAGE, Util.getTimestamp(2014, 0,1), Util.getTimestamp(2015, 0,1), 60*60);
  3. FetchData fetchData = request.fetchData();
  4. double[] values = fetchData.getValues("users");
        rrdDb.createFetchRequest(
                    ConsolFun.AVERAGE, Util.getTimestamp(2014, 0,1), Util.getTimestamp(2015, 0,1), 60*60);
    第1个参数, 通常都是AVERAGE, 暂时不清楚其它值会产生什么样的结果
    第2个参数, 查询的起始时间
    第3个参数, 查询的结束时间
    第4个参数, resolution,  这个值的含义已经在前面讲过了.  不过这个值只起到暗示意义, 如果查询的起始和结束时间
                    没有按照resolution对齐, rrd仍会使用最小的step时间作为resolution. 至于时间怎么以resolution对齐, 将
                    在下一篇文章中讲述.






     



09-18 22:27