如何将RRD数据库中数据导入MYSQL中

59次阅读
没有评论

共计 4438 个字符,预计需要花费 12 分钟才能阅读完成。

本篇文章为大家展示了如何将 RRD 数据库中数据导入 MYSQL 中,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。

将 RRD 数据库中数据导入 MYSQL 中
一、RRD 数据库及 RRDTOOL 简介
意为 Round Robin Database。设计理念为按照 round-robin 的方式进行存储,在一个周期之后(可自己定义),新的
数据会覆盖掉原来的数据。所以 RRD 数据库适合用来存储动态数据,并且不需长期存储。因为是周期性的覆盖旧的数据
所以数据库的大小基本上就会固定下来,并不会随着时间而增大。
 
RRDTOOL 是由 Tobias Oetiker 开发的自由软件,使用 RRD 作为存储格式。RRDTOOL 提供了很多工具用来对 RRD 数据库  www.2cto.com  
进行操作,包括创建,更新,查询,以及生成显示图等。RRDTOOL 同时也提供了很多语言的 API 以方便操作。
 
Ganglia 是一个分布式的监控系统,采用 RRD 数据库进行数据存储和可视化。Hadoop 包里即有一个与 ganglia 相关
的配置文件,修改一些参数和对 ganglia 进行一些设置即可对 hadoop 集群进行监控。每个不同的属性的数据都存在一个
RRD 数据库里。
 
二、将数据导入 MYSQL 中
也会存在这样的情况,可能想对 rrdtool 采集到的数据进行长期存储,从而进行一些分析。而 RRD 数据库的数据是不断
更新的,虽然也可以保留长期的数据,但精度不够。比如说一个 RRD 数据库的步长为 15 秒,也就是说,每隔 15 秒,
就会有一个新的值存入(比如内存使用率),同时覆盖一个旧的值。一个 RRD 数据库存储 5761 个这样的数据(一天 +15  www.2cto.com  
秒). 而且随着时间的推移总是存储最近一天的数据。然后在通过这些值不断地计算步长更高的值,比如我们可以通过
这些 15 秒的数据算出 360s 的数据(平均值),然后以 360s 为步长将这些值再存进去,不过这时候可以存储的时间区间就
更长了,同样的行数可以存储 24 天的数据。以此类推,也可以以一天为单位存储一年的数据,不过这时候的精度就只有
一天了,那些旧的 15s 的数据都已经被覆盖掉了。如果想要把这些数据都存储起来,就需要通过脚本定时进行数据导入。
LINUX 上做这些是很方便的,perl,python,lua,ruby 都是不错的选择,shell 也可以。然后用 crond 设置在一定时间
定时执行即可。以下是 python 的示例代码:
(注:python 学的一般,基本上是边看书,边写的代码,问题不少,请各位指正。)
 
首先是初始化,创建数据库及相应的表:
import os
import MySQLdb
import string
 
root= /var/lib/ganglia/rrds/hap-clu
dirs=os.listdir(root)
 
map1=string.maketrans(. , _)
map2=string.maketrans(– , _)
 
conn=MySQLdb.connect(host= localhost , user= root ,passwd= 123456)
cursor=conn.cursor()  www.2cto.com  
 
for onedir in dirs:
    dbname=onedir.translate(map1).translate(map2)
    cursor.execute(create database if not exists +dbname)
    conn.commit()
    conn.select_db(dbname)
    # print onedirname
    print DB: +dbname+ .
    files=os.listdir(root+ / +onedir)
    for onefile in files:
        tablename=onefile[:-4].translate(map1)
        if(dbname== __SummaryInfo__):
            cursor.execute(create table if not exists +tablename+ (time_id int not null primary key,value varchar(30),num varchar(30)) )
        else:
            cursor.execute(create table if not exists +tablename+ (time_id int not null primary key,value varchar(30)) )
        conn.commit()
       # print CREATE TABLE +tablename
    print CREATE DATABASE +dbname+
 
cursor.close();
 
这里面有不少说明的地方:
1. 存储的目录:ganglia 里面默认是这个目录,不过可以修改。其他不同应用也应该不同。最后的那个 hap-clu 是集群  www.2cto.com  
的名字。在这个目录下,每个节点占一个目录,目录名一般为 IP 地址,最后还有一个 summary 的目录。对应着,为每个
目录(节点)创建一个数据库,每个属性一个表。
2.MYSQL 数据库和表的命名规则中不允许有 . 和 –,所以对应的数据库名和表名要做相应的转换。这里使用的是
translate 函数。
 
3. 原本以为这个脚本只需执行一次,不过在实际应用过程中,发现表的数量和数据库的数量可能会增加。比如有新添加的
节点,就需要及时为它创建数据库。对于一些已存在的节点,有可能有些属性的数据是后来才检测到的。比如我碰到的情况
就是运行了一段时间之后关于 swap 的统计信息才出来,RRD 数据库也才创建。我不知道这是配置的问题还是常态。但为了
顺利运行,这个脚本也要每天和插入数据的脚本一样定时运行,并且在后者之前。
 
插入数据的脚本:
import os
import commands
import MySQLdb
import string
import rrdtool
#from xml.etree.ElementTree import ElementTree
  www.2cto.com  
 
#working directory
root= /var/lib/ganglia/rrds/hap-clu
dirs=os.listdir(root)
 
#mysql table name limit
map1=string.maketrans(. , _)
map2=string.maketrans(– , _)
 
conn=MySQLdb.connect(host= localhost , user= root ,passwd= 123456)
cursor=conn.cursor()
 
for onedir in dirs:
    dbname=onedir.translate(map1).translate(map2)
    conn.select_db(dbname)
 
    print DB: +dbname+ .
    files=os.listdir(root+ / +onedir)
    os.chdir(root+ / +onedir)
    for onefile in files:
        # it seems that all is AVERAGE
        tablename=onefile[:-4].translate(map1) 
        data=rrdtool.fetch(onefile, AVERAGE)
        firsttime=data[0][0]  www.2cto.com  
        count=0
        while count 5761:
            time=firsttime+15*count
            value=data[2][count][0]
            if value==None:
                count+=1
                continue
            if dbname== __SummaryInfo__ :
                num=data[2][count][1]
                fvalue=[time,str(value),str(num)]
                try:
                    cursor.execute(insert into +tablename+ values(%s,%s,%s) ,fvalue)
                except MySQLdb.IntegrityError:
                    pass
            else:  www.2cto.com  
                fvalue=[time,str(value)]
                try:
                    cursor.execute(insert into +tablename+ values(%s,%s) ,fvalue)
                   # print OK +str(count)
                except MySQLdb.IntegrityError:
                    pass  www.2cto.com  
 
            count+=1
        conn.commit()
        print UPDATING TABLE +tablename
cursor.close();
 
说明:
 
1.python 有 RRDTOOL 的模块,相应的命令都已经可以通过模块内的函数直接调用,并且结果是的列表或者元组
,很容易遍历。另外有一种方法就是通过调用外部命令将 rrd 导出到 XML 中(RRDTOOL 内置有此功能),好处是 XML
里面的数据极其相近,缺点是太繁琐,效率也不高,还要解析 XML。
2.count 是 RRD 里存储的数据的行数,这里为了省事直接设置成了默认的值。严谨的话应该是先通过 RRDTOOL INFO 取得
想关的结构信息,得到这个值,然后再调用。rrdtool.fetch 即可取得所存储的所有值。
3. 关于 commit。刚开时对 API 不熟悉,没有加这一句,结果数据都没导进去。第一次加在每次 insert 之后,结果插入  www.2cto.com  
速度奇慢,更新一次要差不多一天,根本没有用。放到后面之后就很快了。
 
4. 因为插入的频率和 RRD 更新的频率不一样,为了保证数据的连续性(不丢失),插入的频率要比更新的频率高。这样会有
很多重复的数据,这里用主键(时间戳,为 UNIX 秒数)和 IntegrityError 来跳过那些已经插入的数据。当初这样做的时候
已经考虑到一个问题,就是当表里原有行数很多时,到后面插入的速度有多慢?(单个表每天更新的数据为 5700 行左右,一个
月为 17 万行左右,一年就会超过 200 万行)。现在我运行的结果是表中已有 5 万行数据,插入速度并没有明显的减慢,想接着再
运行一段时间观察一下。如果太慢就得换一个方法。

上述内容就是如何将 RRD 数据库中数据导入 MYSQL 中,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注丸趣 TV 行业资讯频道。

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-28发表,共计4438字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)