程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> MYSQL數據庫 >> MySQL綜合教程 >> 將RRD數據庫中數據導入MYSQL中

將RRD數據庫中數據導入MYSQL中

編輯: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的模塊,相應的命令都已經可以通過模塊內的函數直接調用,並且結果是Python的列表或者元組 ,很容易遍歷。另外有一種方法就是通過調用外部命令將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萬行數據,插入速度並沒有明顯的減慢,想接著再 運行一段時間觀察一下。如果太慢就得換一個方法。     作者 西城

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved