编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

数据库监控系统小实现(监控系统数据库设计)

wxchong 2024-08-24 01:42:42 开源技术 8 ℃ 0 评论

需求:通过java 去调取python 去目标数据库采集信息,然后插入到数据库,由前台UI显示出来,从而达到监控目的。

设计:通过java的Runtime.getRuntime().exec(args1)方法去调用python脚本,java 传递数据库ip地址串给python脚本,python可以通过CX_Oracle或者paramiko都可以连接到目标数据库,cx_Oracle 是Oracle OCI接口;而paramiko 是ssh协议接口,先通过ssh登录服务器,然后调用sqlplus 命令进到oracle 。

流程:java下发任务,python 接受参数,通过循环IP地址链接到主机root,然后su切换到oracle账户 通过slqplus 执行sql指标采集,然后把返回结果格式化之后写到本地sql文件,最后通过执行本地sql文件完成数据库本地持久化。

问题1:流程太过繁琐,由于sqlplus返回结果集不规则,往往需要经过大量处理之后才能正确得到结果

解决方案:所以想通过

insert into tables values as select * from tables;方式来插入数据库,这种方式可以避免sqlplus返回结果不规则的问题,也避免写文件的io支出。

这样就需要在远端数据库有一个本地的tns连接串或者在本地有一个远端数据库的一个dblink;另外还需要一个数据库账户,可以查询底层v_$的权限。

在本地有一个远端数据库的一个dblink比较好实现,但是有一个问题需要注意,采集某一个指标需要构造所有的数据库查询sql语句,应为表名发生变化。

create database link db1_lk connect to ovsee identified by crbc1234 using 'DB1';

由于dblink 会导致数据库scn暴增的bug,所以通过dblink 这个方法不通。

基于以上的考虑,所以这里使用的是cx_oracle方式。

java代码:

package java2python;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.Date;
public class jtp {
 /*
 * java调用python脚本
 */
	static SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	
 public static void main(String[] args) {
 try {
 
 System.out.println("start");
 String ips="[{IPS=10.241.95.250,10.241.95.40}]";
 String[] args1=new String[]{"python","E:\\APP\\eclipse-jee-oxygen-3a-win32\\workspace\\java2python\\src\\java2python\\DGonAddCheck2.py",ips,format.format(new Date())};
 Process pr=Runtime.getRuntime().exec(args1);
 
 BufferedReader in = new BufferedReader(new InputStreamReader(
 pr.getInputStream()));
 String line;
 while ((line = in.readLine()) != null) {
 System.out.println(line);
 }
 in.close();
 pr.waitFor();
 System.out.println("end");
 } catch (Exception e) {
 e.printStackTrace();
 }}
 public void test(){
 System.out.println("我的第一个方法C");
 }
 
}

python代码:由于监控数据库是一个公共的平台,所以数据库监控的sql语句 最好支持客户端上传方式,所以这里就需要python去遍历制定目录下的*.sql文件读取里面的sql语句。还有一个坑 就是在python脚本里面写数据库监控sql 需要转义,特别麻烦,所以直接读取*.sql文件可以避免这个坑。

#encoding:utf-8
#-*- coding: UTF-8 -*-
#!/usr/bin/python
#coding=UTF-8
import paramiko
import os
import time
import sys
import cx_Oracle
"""
功能:巡检数据库指标数据入库
实现方法:
1.ip地址前台传过来的,后台按照ip地址和定义好的指标去查询数据库获取数据
2.数据量比较小,但是需要及时入库,入库要可靠,执行频率高;所以需要根据场景不同设计不同的入库方案。
数据量大的话可以通过sqlplus 执行文件来实现数据入库目的
数据量小的话可以通过cx_oracle来实现数据入库目的
3.使用sqlplus插入有两种方法:(1)采用tns方式连接数据库插入数据
( 2)采用su 切换用户使用os认证执行sqlplus插入数据
"""
"""
写文件
输入参数 list[],
文件名
"""
listinfo=[]
listerr=[]
check_times=str(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
times='' 
def write_result(liststr,filename):
 if len(liststr):
 fileType=filename.split('.')[1]
 if(fileType == 'sql'):
 #定义文件路径
 writeresult=file('/tmp/'+filename,'a+')
 for str in liststr:
 writeresult.write(str+'\n')
 else:
 #定义文件路径
 writeresult=file('/tmp/'+filename,'a+')
 for str in liststr:
 writeresult.write(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())+'['+fileType+']: '+str+'\n')
 writeresult.close()
def readfile(path):
 list=[]
 list=listdir(path,list)
 for file in list:
 f1=open(file,'r')
 values=f1.read()
 sqls=[]
 sqls=values.split(';')
 
# print sqls
 return sqls
 f1.close
 
 
def listdir(path, list_name): #传入存储的list
 for file in os.listdir(path): 
 if(file.endswith('.sql')):
 file_path = os.path.join(path, file) 
 if os.path.isdir(file_path): 
 listdir(file_path, list_name) 
 else: 
 list_name.append(file_path) 
 return list_name
 
def insertBatch(sql,nameParams,imsdb,username,passwd,port,tnsnames):
 conn=getconn(imsdb,username,passwd,port,tnsnames)
 cr=conn.cursor()
 cr.prepare(sql)
 print 'sql '+sql
 print 'para '+str(nameParams)
 cr.executemany(None,nameParams)
 conn.commit()
 cr.execute("SELECT COUNT(*) FROM dgcheck")
 
 print(cr.fetchone())
 cr.close()
 conn.close()
 
 
def getconn(username,passwd,tnsnames):
 #tnsnames命名为ip地址
# tns=cx_Oracle.makedsn(imsdb,port,tnsnames)
 #tns=''
 conn=cx_Oracle.connect(username,passwd,tnsnames)
# connstr=username+'/'+passwd+'@'+tnsnames
# conn=cx_Oracle.connect(connstr)
 return conn
 
def executedql(sql,ip):
 conn=getconn('dbmgr','123456',ip)
 cr=conn.cursor()
 
 #insertBatch(sql,para,conn)
 cr.execute(sql)
 res=cr.fetchall()
# print(res)
 return res
# for data in res:
# print data
 
 
 #print('insert batch ok.') 
 cr.close()
 conn.close()
 
 
"""
获取ssh2客户端连接服务器ip地址,返回巡检data列表
"""
def sshcmd(ip):
 #listinfo.append('ip '+ip)
 
 execmd1 = "ps -ef|grep smon |grep -v grep|grep ora_|awk '{print $1}'" #判断oracle当前属主
 v="select * from v$version"
 tbs=' SELECT a.tablespace_name ,round(b.maxbytes/1024/1024/1024,2) maxbyes_GB,round(total/1024/1024/1024,2) bytes_GB,round(free/1024/1024/1024,2) free_GB,round((total-free)/1024/1024/1024,2) use_GB, ROUND((total-free)/total,4)*100 "use_%",ROUND((total-free)/b.maxbytes,4)*100 "maxuse_%" FROM (SELECT tablespace_name,SUM(bytes) free FROM DBA_FREE_SPACE GROUP BY tablespace_name ) a, (SELECT tablespace_name,sum(case autoextensible when "YES" then maxbytes else bytes end) maxbytes,SUM(bytes) total FROM DBA_DATA_FILES GROUP BY tablespace_name ) b WHERE a.tablespace_name=b.tablespace_name order by "maxuse_%" desc'
 meminfo_sga="select name,total,round(total-free,2) used, round(free,2) free,round((total-free)/total*100,2) pctused from (select '\"'SGA'\"' name,(select sum(value/1024/1024) from v\$sga) total,(select sum(bytes/1024/1024) from v\$sgastat where name='\"'free memory'\"')free from dual) order by pctused desc;"
 meminfo_pga="select name,total,round(used,2)used,round(total-used,2)free,round(used/total*100,2)pctused from (select '\"'PGA'\"' name,(select value/1024/1024 total from v\$pgastat where name='\"'aggregate PGA target parameter'\"')total,(select value/1024/1024 used from v\$pgastat where name='\"'total PGA allocated'\"')used from dual) order by pctused desc;"
 meminfo_shared_pool="select name,round(total,2) total,round((total-free),2) used,round(free,2) free,round((total-free)/total*100,2) pctused from (select '\"'Shared pool'\"' name,(select sum(bytes/1024/1024) from v\$sgastat where pool='\"'shared pool'\"')total,(select bytes/1024/1024 from v\$sgastat where name='\"'free memory'\"' and pool='\"'shared pool'\"') free from dual) order by pctused desc;"
 meminfo_default_pool="select name,round(total,2)total,round(total-free,2) used,round(free,2) free,round((total-free)/total,2) pctused from (select '\"'Default pool'\"' name,( select a.cnum_repl*(select value from v\$parameter where name='\"'db_block_size'\"')/1024/1024 total from x\$kcbwds a, v\$buffer_pool p where a.set_id=p.LO_SETID and p.name='\"'DEFAULT'\"' and p.block_size=(select value from v\$parameter where name='\"'db_block_size'\"')) total,(select a.anum_repl*(select value from v\$parameter where name='\"'db_block_size'\"')/1024/1024 free from x\$kcbwds a, v\$buffer_pool p where a.set_id=p.LO_SETID and p.name='\"'DEFAULT'\"' and p.block_size=(select value from v\$parameter where name='\"'db_block_size'\"')) free from dual) order by pctused desc;"
 meminfo_keep_pool="select name,nvl(round(total,2),0)total,nvl(round(total-free,2),0) used,nvl(round(free,2),0) free,nvl(round((total-free)/total,2),0) pctused from (select '\"'KEEP pool'\"' name,(select a.cnum_repl*(select value from v\$parameter where name='\"'db_block_size'\"')/1024/1024 total from x\$kcbwds a, v\$buffer_pool p where a.set_id=p.LO_SETID and p.name='\"'KEEP'\"' and p.block_size=(select value from v\$parameter where name='\"'db_block_size'\"')) total,(select a.anum_repl*(select value from v\$parameter where name='\"'db_block_size'\"')/1024/1024 free from x\$kcbwds a, v\$buffer_pool p where a.set_id=p.LO_SETID and p.name='\"'KEEP'\"' and p.block_size=(select value from v$parameter where name='\"'db_block_size'\"')) free from dual) order by pctused desc;"
 meminfo_recycle_pool="select name,nvl(round(total,2),0)total,nvl(round(total-free,2),0) used,nvl(round(free,2),0) free,nvl(round((total-free)/total,2),0) pctused from (select '\"'RECYCLE pool'\"' name,( select a.cnum_repl*(select value from v\$parameter where name='\"'db_block_size'\"')/1024/1024 total from x\$kcbwds a, v\$buffer_pool p where a.set_id=p.LO_SETID and p.name='\"'RECYCLE'\"' and p.block_size=(select value from v$parameter where name='\"'db_block_size'\"')) total,(select a.anum_repl*(select value from v\$parameter where name='\"'db_block_size'\"')/1024/1024 free from x\$kcbwds a, v\$buffer_pool p where a.set_id=p.LO_SETID and p.name='\"'RECYCLE'\"' and p.block_size=(select value from v\$parameter where name='\"'db_block_size'\"')) free from dual) order by pctused desc;"
 meminfo_16k_buffercahce="select name,nvl(round(total,2),0)total,nvl(round(total-free,2),0) used,nvl(round(free,2),0) free,nvl(round((total-free)/total,2),0) pctused from(select '\"'DEFAULT 16K buffer cache\"'' name,(select a.cnum_repl*16/1024 total from x\$kcbwds a, v$buffer_pool p where a.set_id=p.LO_SETID and p.name='\"'DEFAULT'\"' and p.block_size=16384) total, (select a.anum_repl*16/1024 free from x\$kcbwds a, v\$buffer_pool p where a.set_id=p.LO_SETID and p.name='\"'DEFAULT'\"' and p.block_size=16384) free from dual) order by pctused desc;"
 meminfo_java_pool="select name,total,total-free used,free, (total-free)/total*100 pctused from (select '\"'Java Pool\"'' name,(select sum(bytes/1024/1024) total from v\$sgastat where pool='\"'java pool'\"' group by pool)total,( select bytes/1024/1024 free from v\$sgastat where pool='\"'java pool'\"' and name='\"'free memory'\"')free from dual) order by pctused desc;"
 meminfo_large_pool="select name,Round(total,2),round(total-free,2) used,round(free,2) free, round((total-free)/total*100,2) pctused from (select '\"'Large Pool'\"' name,(select sum(bytes/1024/1024) total from v\$sgastat where pool='\"'large pool'\"' group by pool)total,( select bytes/1024/1024 free from v\$sgastat where pool='\"'large pool'\"' and name='\"'free memory'\"')free from dual) order by pctused desc;"
 
 disk_io_undo="select d.username,c.name,b.writes from v\$transaction a,v\$rollstat b,v\$rollname c,v\$session d where d.taddr=a.addr and a.xidusn=b.usn and b.usn=c.usn order by d.username;"
 disk_io_tbs="select ts.name tablespace,fs.phyrds ""\"reads""\",fs.phywrts ""\"writes""\",fs.phyblkrd ,fs.phyblkwrt,fs.readtim ""\"rtime""\",fs.writetim ""\"wtime""\" from v\$tablespace ts,v\$datafile df,v\$filestat fs where ts.ts#=df.ts# and df.file#=fs.file#;"
 disk_io_tmp="select ts.name,ts.phyrds ""\"reads""\",ts.phywrts ""\"writes""\",ts.phyblkrd,ts.phyblkwrt,ts.readtim ""\"rtime""\",ts.writetim ""\"wtime""\" from v\$tablespace ts,v\$tempfile tf ,v\$tempstat ts where ts.ts#=tf.ts# and tf.file#=ts.file#;" 
 disk_io_datafile="select name,phyrds,phywrts,readtim,writetim from v\$filestat a,v\$datafile b where a.file#=b.file# order by readtim desc;"
 
 cpu_busy_usage="select value from v\$osstat where stat_name='\"'BUSY_TIME'\"';"
 cpu_usage="select * from v\$osstat;"
 
 sqls=readfile("E:\APP\eclipse-jee-oxygen-3a-win32\workspace\java2python\src\java2python")
 #print sql
 if(ip <> ""): 
 for sql in sqls:
 if sql =='':
 continue
 else:
 print executedql(sql,ip)
 
 else:
 print "ip is NULL!"
 
 
 
"""
前台传输ip地址列表,考虑到数据有可能会非常大,所以需要批量入库
使用cx_oracle模块,可以使用绑定变量方式入库,效率会比较高;但是多了一层cx_oracle驱动包连接数据库。
如果使用sqlplus 可以直接入库,但是无法绑定变量插入数据。
""" 
def getValues(ips):
 print 'ips:'+str(ips)
 
 for ip in ips:
 try:
 sshcmd(ip)
 except Exception:
 print ip+'获取信息失败'
 continue
 
#获取java 传参 
def main():
 args1=''
 args2=''
 for i in range(1,len(sys.argv)):
 args1 = str(sys.argv[1])
 args2 = str(sys.argv[2])
 print ' args1 '+args1
 print ' args2 '+args2
 #listinfo.append('input args1 '+args1)
 #listinfo.append('input args2 '+args2)
 ips=args1.replace('[{', '').replace('IPS=','').replace('}]','').replace(' ','').split(',')
 global times
 times=args2
 filename=args2.replace(" ","")+'_dgAddoncheck.sql'
 print 'filename '+filename
 print 'ips ' +str(ips)
 #write_result(listinfo,'/dataguard_Addoncheck.info')
 #write_result(listerr,'/dataguard_Addoncheck.error') 
 getValues(ips) 
 
main()

返回结果:

[(0, 'SYSTEM', 'YES', 'NO', 'YES', None), (1, 'SYSAUX', 'YES', 'NO', 'YES', None), (2, 'UNDOTBS1', 'YES', 'NO', 'YES', None), (3, 'TEMP', 'NO', 'NO', 'YES', None), (4, 'USERS', 'YES', 'NO', 'YES', None)]

可以通过拼接sql 插入到数据库,也可以使用db link 直接插入到数据库。

dblink 方式类似 :

create database link db1_lk connect to user1 identified by crbc1234 using 'ORCL';

insert into db_info values as select name form v$tablespace@db1_lk ,

这样的好处是 不需要对结果集单独处理而直接插入到数据库。

这个是我成品的监控系统界面,后面我会把系统贴上来供大家免费使用。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表