如果开发者未曾使用过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, 表面含义是心跳, 在这里, 我理解为有效时间区域, 看以下图例
图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数据库
点击(此处)折叠或打开
- long start = System.currentTimeMillis()/1000;
- RrdDef rrdDef = new RrdDef("d:\\test.rrd", start, 60);
- rrdDef.addDatasource("users", DsType.GAUGE, 60*2, 0, Double.NaN);
- rrdDef.addDatasource("devices", DsType.GAUGE, 60*2, 0, Double.NaN);
- /** 每分钟一个存档, 两年共计 2*365*24*60 */
- rrdDef.addArchive(ConsolFun.AVERAGE, 0.5, 1, 2*365*24*60);
-
- /** 每小时一个存档, 两年共计2*365*24 */
- rrdDef.addArchive(ConsolFun.AVERAGE, 0.5, 60, 2*365*24);
-
- /** 每天一个存档, 两年共计2*365 */
- rrdDef.addArchive(ConsolFun.AVERAGE, 0.5, 60*24, 2*365);
- RrdDb rrdDb = new RrdDb(rrdDef);
- 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. 插入数据
下面的代码设定的是每分钟插入一次随机值
点击(此处)折叠或打开
- final RrdDb rrdDb = new RrdDb("d:\\test.rrd");
- final Random random = new Random();
- Timer timer = new Timer();
- timer.schedule(new TimerTask() {
- @Override
- public void run() {
- Sample sample = rrdDb.createSample();
- long time = System.currentTimeMillis() / 1000;
- sample.setTime(time);
- sample.setValue("users", random.nextInt(1000));
- sample.setValue("device", random.nextInt(1000));
- sample.update();
- }
- }, 60 * 1000, 60 * 1000);
3. 查询数据
下面的代码是查询2014.1.1到2015.1.1这段时间之间的users统计数据
点击(此处)折叠或打开
- FetchRequest request = rrdDb.createFetchRequest(
- ConsolFun.AVERAGE, Util.getTimestamp(2014, 0,1), Util.getTimestamp(2015, 0,1), 60*60);
- FetchData fetchData = request.fetchData();
- double[] values = fetchData.getValues("users");
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对齐, 将
在下一篇文章中讲述.