feat:Database 各项统计信息采集

This commit is contained in:
nieziyan 2023-12-01 20:49:59 +08:00
parent 312aebbc99
commit 723c5a1706
12 changed files with 343 additions and 1 deletions

View File

@ -12,6 +12,13 @@ public interface DBSQL {
"0.0 AS used, 0.0 AS dataSize, 0.0 AS indexSize " + "0.0 AS used, 0.0 AS dataSize, 0.0 AS indexSize " +
"FROM pg_class WHERE relkind = 'r' AND relname NOT LIKE 'pg_%' AND relname NOT LIKE 'sql_%'"; "FROM pg_class WHERE relkind = 'r' AND relname NOT LIKE 'pg_%' AND relname NOT LIKE 'sql_%'";
String DBSTATUS_PG = "SELECT *, 0 AS logResidue FROM " +
"(SELECT COUNT(*) AS loginNum FROM pg_stat_activity WHERE query_start >= now() - interval '1 minute') AS loginNum," +
"(SELECT COUNT(*) AS connNum FROM pg_stat_activity WHERE query_start >= now() - interval '1 minute') AS connNum," +
"(SELECT ROUND(SUM(pg_database_size(datname)) / 1024 / 1024, 0) AS dataSize FROM pg_database) AS dataSize";
String DBSTATUS_CONN_PG = "SELECT COUNT(*) FROM pg_stat_activity WHERE query_start >= now() - interval '1 minute'";
/* Oracle */ /* Oracle */
String DBNAMES_OR = "SELECT username FROM all_users"; String DBNAMES_OR = "SELECT username FROM all_users";
String DBINFO_OR = "SELECT a.table_name AS tableName, a.num_rows AS numRow," + String DBINFO_OR = "SELECT a.table_name AS tableName, a.num_rows AS numRow," +
@ -39,6 +46,14 @@ public interface DBSQL {
"AND d.segment_type = 'INDEX' WHERE a.owner = '%s' " + "AND d.segment_type = 'INDEX' WHERE a.owner = '%s' " +
"ORDER BY a.table_name"; "ORDER BY a.table_name";
String DBSTATUS_OR = "SELECT * FROM " +
"(SELECT COUNT(*) AS loginNum FROM V$SESSION WHERE LOGON_TIME >= SYSDATE - 1 / 24 / 60 AND TYPE = 'USER')," +
"(SELECT COUNT(*) AS connNum FROM V$SESSION WHERE LOGON_TIME >= SYSDATE - 1 / 24 / 60)," +
"(SELECT SUM(BYTES) / 1024 / 1024 AS logResidue FROM V$log WHERE ARCHIVED = 'NO')," +
"(SELECT SUM(BYTES) / 1024 / 1024 AS dataSize FROM dba_data_files)";
String DBSTATUS_CONN_OR = "SELECT COUNT(*) FROM V$SESSION WHERE LOGON_TIME >= SYSDATE - 1 / 24 / 60";
/* MySQL */ /* MySQL */
String DBNAMES_MY = "SHOW DATABASES"; String DBNAMES_MY = "SHOW DATABASES";
String DBINFO_MY = "SELECT TABLE_NAME AS tableName, TABLE_ROWS AS numRow," + String DBINFO_MY = "SELECT TABLE_NAME AS tableName, TABLE_ROWS AS numRow," +

View File

@ -0,0 +1,28 @@
package org.jeecg.modules.base.dto;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import org.jeecg.common.system.base.entity.JeecgEntity;
import java.time.LocalDateTime;
@Data
@TableName("database_status_conn")
public class DatabaseStatusConn extends JeecgEntity {
// private Double memory;
//
// private Integer loginNum;
private Integer connNum;
// private Double respTime; // 单位: (S)
//
// private Double logResidue; // 单位 MB
//
// private Double dataSize; // 单位 MB
private String databaseId;
private LocalDateTime collectTime;
}

View File

@ -0,0 +1,38 @@
package org.jeecg.modules;
import org.jeecg.common.constant.DBSQL;
import org.jeecg.common.util.JDBCUtil;
import org.jeecg.modules.base.entity.postgre.SysDatabase;
import org.jeecg.modules.databaseStatus.ConnFetcher;
import org.jeecg.modules.service.ISysDatabaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class DatabaseStatusFetcher {
@Autowired
private ISysDatabaseService databaseService;
public void start(){
List<SysDatabase> databases = databaseService.list();
// 采集数据库连接数
Thread connFetcher = new Thread(new ConnFetcher(databases));
connFetcher.setName("Thread-connFetcher");
connFetcher.start();
// ...
}
public static void main(String[] args) {
String url = "jdbc:oracle:thin:@82.157.234.81:1521:XE";
String driver = "oracle.jdbc.OracleDriver";
String user = "configuration";
String pass = "123456";
JdbcTemplate template = JDBCUtil.template(url, driver, user, pass);
System.out.println(template.queryForObject(DBSQL.DBSTATUS_CONN_OR, Integer.class));
}
}

View File

@ -0,0 +1,17 @@
package org.jeecg.modules.controller;
import io.swagger.annotations.Api;
import org.jeecg.modules.service.IDatabaseStatusConnService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("sysDatabaseStatus")
@Api(value = "数据库状态信息管理", tags = "数据库状态信息管理")
public class SysDatabaseStatusController {
@Autowired
private IDatabaseStatusConnService databaseStatusService;
}

View File

@ -0,0 +1,101 @@
package org.jeecg.modules.databaseStatus;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.constant.DBSQL;
import org.jeecg.common.constant.enums.DbType;
import org.jeecg.common.util.JDBCUtil;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.modules.base.dto.DatabaseStatusConn;
import org.jeecg.modules.base.entity.postgre.SysDatabase;
import org.jeecg.modules.service.IDatabaseStatusConnService;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import static org.jeecg.common.constant.enums.DbType.typeOf;
/*
* 收集数据源的连接数信息 入库
* */
@Slf4j
public class ConnFetcher implements Runnable{
private List<SysDatabase> databases;
private IDatabaseStatusConnService connService;
public ConnFetcher(List<SysDatabase> databases) {
this.databases = databases;
connService = SpringContextUtils.getBean(IDatabaseStatusConnService.class);
}
@Override
public void run() {
if (CollUtil.isEmpty(databases)) return;
List<DatabaseStatusConn> statusList = new ArrayList<>();
Iterator<SysDatabase> iterator = databases.iterator();
while (true){
LocalDateTime now = LocalDateTime.now();
while (iterator.hasNext()) {
try {
SysDatabase database= iterator.next();
String databaseId = database.getId();
String dbType = database.getDbType();
String dbUrl = database.getDbUrl();
String dbDriver = database.getDbDriver();
String dbUsername = database.getDbUsername();
String dbPassword = database.getDbPassword();
JdbcTemplate template = JDBCUtil.template(dbUrl, dbDriver, dbUsername, dbPassword);
if (ObjectUtil.isNull(template)) {
iterator.remove();
continue;
}
Integer conn = null;
// 根据数据库类型选择执行哪种数据库的状态查询SQL
DbType dbTypeE = typeOf(dbType);
if (ObjectUtil.isNotNull(dbTypeE)){
switch (dbTypeE){
case POSTGRESQL:
conn = template.queryForObject(DBSQL.DBSTATUS_CONN_PG, Integer.class);
break;
case ORACLE:
conn = template.queryForObject(DBSQL.DBSTATUS_CONN_OR, Integer.class);
break;
case MYSQL55:
// ...
break;
case MYSQL57:
// ...
break;
default:
break;
}
}
// 如果conn == null 说明数据源类型不确定
if (ObjectUtil.isNull(conn)) {
iterator.remove();
continue;
}
DatabaseStatusConn databaseStatus = new DatabaseStatusConn();
databaseStatus.setConnNum(conn);
databaseStatus.setDatabaseId(databaseId);
databaseStatus.setCollectTime(now);
// 数据达到一定数量,进行批量保存
statusList.add(databaseStatus);
if (statusList.size() == 5){
connService.saveBatch(statusList);
statusList = new ArrayList<>();
}
}catch (Exception e){
log.error("ConnFetcher采集数据库连接数异常: {}", e.getMessage());
}
}
}
}
}

View File

@ -0,0 +1,104 @@
package org.jeecg.modules.databaseStatus;
import cn.hutool.core.util.ObjectUtil;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.constant.DBSQL;
import org.jeecg.common.constant.enums.DbType;
import org.jeecg.common.util.JDBCUtil;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.modules.base.dto.DatabaseStatusConn;
import org.jeecg.modules.base.entity.postgre.SysDatabase;
import org.jeecg.modules.service.IDatabaseStatusConnService;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static org.jeecg.common.constant.enums.DbType.typeOf;
/*
* 收集数据源的状态信息 入库
* */
@Slf4j
public class StatusFetcher implements Runnable{
private final long sleepTime = 30 * 60 * 1000;
private final SysDatabase database;
private IDatabaseStatusConnService statusService;
public StatusFetcher(SysDatabase database) {
this.database = database;
statusService = SpringContextUtils.getBean(IDatabaseStatusConnService.class);
}
@Override
public void run() {
if (ObjectUtil.isNull(database)) return;
String databaseId = database.getId();
String dbType = database.getDbType();
String dbUrl = database.getDbUrl();
String dbDriver = database.getDbDriver();
String dbUsername = database.getDbUsername();
String dbPassword = database.getDbPassword();
List<DatabaseStatusConn> statusList = new ArrayList<>();
while (true){
try {
long start = System.currentTimeMillis();
JdbcTemplate template = JDBCUtil.template(dbUrl, dbDriver, dbUsername, dbPassword);
long end = System.currentTimeMillis();
/*
如果template == null 表示数据源连接失败,睡眠30min后重试
如果template != null 则表示连接成功,同时记录数据源连接响应时间
*/
if (ObjectUtil.isNull(template)){
TimeUnit.MILLISECONDS.sleep(sleepTime);
log.warn("数据源");
continue;
}
log.info("11111111111111111111111111111111111111111111111");
DatabaseStatusConn databaseStatus = null;
// 根据数据库类型选择执行哪种数据库的状态查询SQL
DbType dbTypeE = typeOf(dbType);
if (ObjectUtil.isNotNull(dbTypeE)){
switch (dbTypeE){
case POSTGRESQL:
// databaseStatus = template.queryForObject(DBSQL.DBSTATUS_PG, mapper);
break;
case ORACLE:
// databaseStatus = template.queryForObject(DBSQL.DBSTATUS_OR, mapper);
break;
case MYSQL55:
// ...
break;
case MYSQL57:
// ...
break;
default:
break;
}
}
// 如果databaseStatus == null 说明数据源类型不确定
if (ObjectUtil.isNull(databaseStatus)) return;
databaseStatus.setDatabaseId(databaseId);
// 设置数据的响应时间
BigDecimal decimal = new BigDecimal((end - start));
double respTime = decimal.divide(new BigDecimal(1000), 2, RoundingMode.HALF_UP).doubleValue();
//databaseStatus.setRespTime(respTime);
// 数据达到一定数量,进行批量保存
statusList.add(databaseStatus);
if (statusList.size() == 300){
statusService.saveBatch(statusList);
}
}catch (Exception e){
}
}
}
}

View File

@ -0,0 +1,8 @@
package org.jeecg.modules.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.jeecg.modules.base.dto.DatabaseStatusConn;
public interface DatabaseStatusConnMapper extends BaseMapper<DatabaseStatusConn> {
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.jeecg.modules.mapper.DatabaseStatusConnMapper">
</mapper>

View File

@ -0,0 +1,9 @@
package org.jeecg.modules.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.jeecg.modules.base.dto.DatabaseStatusConn;
public interface IDatabaseStatusConnService extends IService<DatabaseStatusConn> {
}

View File

@ -0,0 +1,12 @@
package org.jeecg.modules.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.jeecg.modules.base.dto.*;
import org.jeecg.modules.mapper.DatabaseStatusConnMapper;
import org.jeecg.modules.service.IDatabaseStatusConnService;
import org.springframework.stereotype.Service;
@Service("databaseStatusConnService")
public class DatabaseStatusConnServiceImpl extends ServiceImpl<DatabaseStatusConnMapper, DatabaseStatusConn> implements IDatabaseStatusConnService {
}

View File

@ -3,6 +3,7 @@ package org.jeecg;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.util.oConvertUtils; import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.DatabaseStatusFetcher;
import org.jeecg.modules.DatabaseStatusManager; import org.jeecg.modules.DatabaseStatusManager;
import org.jeecg.modules.EmailStatusManager; import org.jeecg.modules.EmailStatusManager;
import org.jeecg.modules.ServerStatusManager; import org.jeecg.modules.ServerStatusManager;
@ -32,6 +33,8 @@ public class JeecgAbnormalAlarmApplication extends SpringBootServletInitializer
private final DatabaseStatusManager databaseStatusManager; private final DatabaseStatusManager databaseStatusManager;
private final DatabaseStatusFetcher databaseStatusFetcher;
@Override @Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(JeecgAbnormalAlarmApplication.class); return application.sources(JeecgAbnormalAlarmApplication.class);
@ -59,6 +62,8 @@ public class JeecgAbnormalAlarmApplication extends SpringBootServletInitializer
emailStatusManager.start(); emailStatusManager.start();
// 启动监测服务器连接状态的线程 // 启动监测服务器连接状态的线程
serverStatusManager.start(); serverStatusManager.start();
// 启动采集数据库状态信息线程组
databaseStatusFetcher.start();
} }
} }

View File

@ -15,5 +15,5 @@ spring:
config: config:
import: import:
- optional:nacos:armd.yaml - optional:nacos:armd.yaml
- optional:nacos:armd-@profile.name@.yaml - optional:nacos:armd-@profile.name@1.yaml
- optional:nacos:armd-analysis-@profile.name@.yaml - optional:nacos:armd-analysis-@profile.name@.yaml