Initial commit: 宁夏智慧养殖监管平台

This commit is contained in:
shenquanyi
2025-08-25 15:00:46 +08:00
commit ec72c6a8b5
177 changed files with 37263 additions and 0 deletions

495
backend/utils/db-monitor.js Normal file
View File

@@ -0,0 +1,495 @@
/**
* 数据库连接监控工具
* @file db-monitor.js
* @description 实时监控数据库连接状态和性能
*/
const { monitorPool, testConnection, resetPool, optimizePool } = require('../config/database-pool');
const queryOptimizer = require('./query-optimizer');
const EventEmitter = require('events');
const fs = require('fs');
const path = require('path');
// 创建事件发射器
class DatabaseEventEmitter extends EventEmitter {}
const dbEvents = new DatabaseEventEmitter();
// 数据库监控类
class DatabaseMonitor {
constructor() {
this.isMonitoring = false;
this.monitorInterval = null;
this.monitorIntervalTime = 60000; // 默认每分钟监控一次
this.listeners = [];
this.status = {
lastCheck: null,
isConnected: false,
poolStats: null,
slowQueries: [],
errors: [],
metrics: {}
};
this.logPath = path.join(process.cwd(), 'logs', 'db-monitor');
this.alertThresholds = {
connectionErrors: 3, // 连续连接错误次数阈值
slowQueryPercentage: 10, // 慢查询百分比阈值
connectionPoolUsage: 80, // 连接池使用率阈值(百分比)
queryResponseTime: 1000 // 查询响应时间阈值(毫秒)
};
this.metricsHistory = {
connectionPool: [],
queryPerformance: [],
errors: []
};
this.maxMetricsHistory = 100; // 保存最近100条历史记录
// 确保日志目录存在
this.ensureLogDirectory();
}
// 确保日志目录存在
ensureLogDirectory() {
try {
if (!fs.existsSync(path.join(process.cwd(), 'logs'))) {
fs.mkdirSync(path.join(process.cwd(), 'logs'));
}
if (!fs.existsSync(this.logPath)) {
fs.mkdirSync(this.logPath);
}
} catch (error) {
console.error('创建日志目录失败:', error);
}
}
// 开始监控
startMonitoring(intervalTime = this.monitorIntervalTime) {
if (this.isMonitoring) {
return false;
}
this.monitorIntervalTime = intervalTime;
this.isMonitoring = true;
// 立即执行一次监控
this.checkStatus();
// 设置定时监控
this.monitorInterval = setInterval(() => {
this.checkStatus();
}, this.monitorIntervalTime);
console.log(`数据库监控已启动,监控间隔: ${this.monitorIntervalTime}ms`);
dbEvents.emit('monitoring_started', { interval: this.monitorIntervalTime });
return true;
}
// 停止监控
stopMonitoring() {
if (!this.isMonitoring) {
return false;
}
clearInterval(this.monitorInterval);
this.monitorInterval = null;
this.isMonitoring = false;
console.log('数据库监控已停止');
dbEvents.emit('monitoring_stopped');
return true;
}
// 检查数据库状态
async checkStatus() {
try {
// 检查连接
const isConnected = await testConnection();
// 获取连接池状态
const poolStats = monitorPool();
// 获取慢查询
const slowQueries = await queryOptimizer.identifySlowQueries(this.alertThresholds.queryResponseTime);
// 获取数据库状态
const dbStatus = await queryOptimizer.getDatabaseStatus();
// 计算指标
const metrics = this.calculateMetrics(isConnected, poolStats, slowQueries, dbStatus);
// 更新状态
this.status = {
lastCheck: new Date(),
isConnected,
poolStats,
slowQueries,
errors: isConnected ? [] : [{ time: new Date(), message: '数据库连接失败' }],
metrics
};
// 更新历史记录
this.updateMetricsHistory(metrics);
// 检查是否需要发出警报
this.checkAlerts();
// 记录状态日志
this.logStatus();
// 通知所有监听器
this.notifyListeners();
// 如果连接失败,记录错误
if (!isConnected) {
console.error('数据库连接检查失败');
this.logError('数据库连接检查失败');
dbEvents.emit('connection_error', { time: new Date(), message: '数据库连接失败' });
}
return this.status;
} catch (error) {
const errorStatus = {
lastCheck: new Date(),
isConnected: false,
poolStats: null,
slowQueries: [],
errors: [{ time: new Date(), message: error.message }],
metrics: {}
};
this.status = errorStatus;
this.logError(error.message);
this.notifyListeners();
console.error('数据库状态检查失败:', error);
dbEvents.emit('status_check_error', { time: new Date(), error: error.message });
return errorStatus;
}
}
// 计算监控指标
calculateMetrics(isConnected, poolStats, slowQueries, dbStatus) {
// 连接池使用率
const poolUsage = poolStats && poolStats.total > 0
? (poolStats.borrowed / poolStats.total) * 100
: 0;
// 慢查询百分比
const totalQueries = dbStatus && dbStatus.queries ? parseInt(dbStatus.queries.total) || 0 : 0;
const slowQueryCount = slowQueries ? slowQueries.length : 0;
const slowQueryPercentage = totalQueries > 0
? (slowQueryCount / totalQueries) * 100
: 0;
// 缓冲池命中率
const bufferPoolHitRate = dbStatus && dbStatus.buffer_pool ? dbStatus.buffer_pool.hit_rate : 0;
return {
connectionStatus: isConnected ? 'connected' : 'disconnected',
poolUsage: parseFloat(poolUsage.toFixed(2)),
slowQueryPercentage: parseFloat(slowQueryPercentage.toFixed(2)),
bufferPoolHitRate: parseFloat(bufferPoolHitRate.toFixed(2)),
timestamp: new Date()
};
}
// 更新指标历史记录
updateMetricsHistory(metrics) {
// 更新连接池历史
this.metricsHistory.connectionPool.push({
timestamp: new Date(),
poolUsage: metrics.poolUsage,
connectionStatus: metrics.connectionStatus
});
// 更新查询性能历史
this.metricsHistory.queryPerformance.push({
timestamp: new Date(),
slowQueryPercentage: metrics.slowQueryPercentage,
bufferPoolHitRate: metrics.bufferPoolHitRate
});
// 限制历史记录数量
if (this.metricsHistory.connectionPool.length > this.maxMetricsHistory) {
this.metricsHistory.connectionPool.shift();
}
if (this.metricsHistory.queryPerformance.length > this.maxMetricsHistory) {
this.metricsHistory.queryPerformance.shift();
}
if (this.metricsHistory.errors.length > this.maxMetricsHistory) {
this.metricsHistory.errors.shift();
}
}
// 检查是否需要发出警报
checkAlerts() {
const { metrics, slowQueries, poolStats } = this.status;
// 检查连接池使用率
if (metrics.poolUsage > this.alertThresholds.connectionPoolUsage) {
const alert = {
type: 'high_pool_usage',
message: `连接池使用率过高: ${metrics.poolUsage}%`,
level: 'warning',
timestamp: new Date()
};
dbEvents.emit('alert', alert);
console.warn(alert.message);
}
// 检查慢查询百分比
if (metrics.slowQueryPercentage > this.alertThresholds.slowQueryPercentage) {
const alert = {
type: 'high_slow_query_percentage',
message: `慢查询百分比过高: ${metrics.slowQueryPercentage}%`,
level: 'warning',
timestamp: new Date(),
details: slowQueries
};
dbEvents.emit('alert', alert);
console.warn(alert.message);
}
// 检查连接错误
const recentErrors = this.metricsHistory.errors.slice(-this.alertThresholds.connectionErrors);
if (recentErrors.length >= this.alertThresholds.connectionErrors) {
const alert = {
type: 'connection_errors',
message: `连续出现${recentErrors.length}次连接错误`,
level: 'error',
timestamp: new Date(),
details: recentErrors
};
dbEvents.emit('alert', alert);
console.error(alert.message);
}
}
// 记录状态日志
logStatus() {
try {
const logFile = path.join(this.logPath, `status-${new Date().toISOString().split('T')[0]}.log`);
const logData = JSON.stringify({
timestamp: new Date(),
status: this.status
}) + '\n';
fs.appendFileSync(logFile, logData);
} catch (error) {
console.error('记录状态日志失败:', error);
}
}
// 记录错误日志
logError(message) {
try {
const errorLog = {
timestamp: new Date(),
message
};
// 添加到错误历史
this.metricsHistory.errors.push(errorLog);
// 写入错误日志文件
const logFile = path.join(this.logPath, `error-${new Date().toISOString().split('T')[0]}.log`);
const logData = JSON.stringify(errorLog) + '\n';
fs.appendFileSync(logFile, logData);
} catch (error) {
console.error('记录错误日志失败:', error);
}
}
// 获取当前状态
getStatus() {
return this.status;
}
// 获取历史指标
getMetricsHistory() {
return this.metricsHistory;
}
// 添加状态变化监听器
addListener(listener) {
if (typeof listener === 'function' && !this.listeners.includes(listener)) {
this.listeners.push(listener);
return true;
}
return false;
}
// 移除监听器
removeListener(listener) {
const index = this.listeners.indexOf(listener);
if (index !== -1) {
this.listeners.splice(index, 1);
return true;
}
return false;
}
// 通知所有监听器
notifyListeners() {
this.listeners.forEach(listener => {
try {
listener(this.status);
} catch (error) {
console.error('监听器执行失败:', error);
}
});
}
// 设置监控间隔
setMonitorInterval(intervalTime) {
if (intervalTime < 1000) {
console.warn('监控间隔不能小于1000ms已设置为1000ms');
intervalTime = 1000;
}
this.monitorIntervalTime = intervalTime;
// 如果正在监控,重新启动监控
if (this.isMonitoring) {
this.stopMonitoring();
this.startMonitoring();
}
return this.monitorIntervalTime;
}
// 设置警报阈值
setAlertThresholds(thresholds = {}) {
this.alertThresholds = {
...this.alertThresholds,
...thresholds
};
return this.alertThresholds;
}
// 获取警报阈值
getAlertThresholds() {
return this.alertThresholds;
}
// 优化连接池
async optimizeConnectionPool() {
try {
// 获取当前连接池状态
const poolStats = monitorPool();
// 根据当前使用情况计算优化配置
const newConfig = {};
// 如果连接池使用率超过80%,增加最大连接数
if (poolStats.borrowed / poolStats.total > 0.8) {
newConfig.max = Math.min(poolStats.max + 5, 30); // 增加5个连接但不超过30
}
// 如果连接池使用率低于20%,减少最大连接数
if (poolStats.borrowed / poolStats.total < 0.2 && poolStats.max > 10) {
newConfig.max = Math.max(poolStats.max - 5, 10); // 减少5个连接但不低于10
}
// 应用优化配置
if (Object.keys(newConfig).length > 0) {
const result = await optimizePool(newConfig);
console.log('连接池已优化:', result);
dbEvents.emit('pool_optimized', result);
return result;
}
return poolStats;
} catch (error) {
console.error('优化连接池失败:', error);
return { error: error.message };
}
}
// 重置连接池
async resetConnectionPool() {
try {
const result = await resetPool();
console.log('连接池已重置:', result);
dbEvents.emit('pool_reset', result);
return result;
} catch (error) {
console.error('重置连接池失败:', error);
return { error: error.message };
}
}
// 获取详细的数据库信息
async getDatabaseInfo() {
try {
// 获取数据库状态
const dbStatus = await queryOptimizer.getDatabaseStatus();
// 获取当前连接池状态
const poolStats = monitorPool();
// 获取慢查询
const slowQueries = await queryOptimizer.identifySlowQueries();
// 获取表信息
const tables = await this.getTablesList();
const tableInfoPromises = tables.map(table => queryOptimizer.getTableInfo(table));
const tablesInfo = await Promise.all(tableInfoPromises);
return {
timestamp: new Date(),
connection: {
isConnected: await testConnection(),
pool: poolStats
},
performance: {
slowQueries,
metrics: this.status.metrics,
history: this.metricsHistory
},
database: dbStatus,
tables: tablesInfo.reduce((acc, info, index) => {
acc[tables[index]] = info;
return acc;
}, {})
};
} catch (error) {
console.error('获取数据库信息失败:', error);
return {
timestamp: new Date(),
error: error.message,
connection: { isConnected: false, pool: null },
performance: { slowQueries: [], metrics: {}, history: {} },
database: { variables: {}, status: {} },
tables: {}
};
}
}
// 获取表列表
async getTablesList() {
try {
const result = await sequelize.query(
'SHOW TABLES',
{ type: sequelize.QueryTypes.SHOWTABLES }
);
// 结果格式可能因数据库类型而异
return Array.isArray(result)
? result.flat().filter(Boolean)
: [];
} catch (error) {
console.error('获取表列表失败:', error);
return [];
}
}
}
// 创建数据库监控实例
const dbMonitor = new DatabaseMonitor();
// 导出事件发射器,允许外部监听事件
dbMonitor.events = dbEvents;
module.exports = dbMonitor;

44
backend/utils/logger.js Normal file
View File

@@ -0,0 +1,44 @@
const winston = require('winston');
// 创建日志格式
const logFormat = winston.format.combine(
winston.format.timestamp({
format: 'YYYY-MM-DD HH:mm:ss'
}),
winston.format.errors({ stack: true }),
winston.format.json()
);
// 创建logger实例
const logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
format: logFormat,
defaultMeta: { service: 'nxxmdata-backend' },
transports: [
// 错误日志文件
new winston.transports.File({
filename: 'logs/error.log',
level: 'error',
maxsize: 5242880, // 5MB
maxFiles: 5
}),
// 所有日志文件
new winston.transports.File({
filename: 'logs/combined.log',
maxsize: 5242880, // 5MB
maxFiles: 5
})
]
});
// 开发环境下添加控制台输出
if (process.env.NODE_ENV !== 'production') {
logger.add(new winston.transports.Console({
format: winston.format.combine(
winston.format.colorize(),
winston.format.simple()
)
}));
}
module.exports = logger;

View File

@@ -0,0 +1,570 @@
/**
* 性能监控系统
* @file performance-monitor.js
* @description 全面的系统性能监控工具包括数据库、API和系统资源监控
*/
const { EventEmitter } = require('events');
const fs = require('fs');
const path = require('path');
const os = require('os');
const logger = require('./logger');
const dbMonitor = require('./db-monitor');
const queryOptimizer = require('./query-optimizer');
const { getPoolStatus } = require('../config/database-pool');
// 性能监控事件发射器
class PerformanceEventEmitter extends EventEmitter {}
const perfEvents = new PerformanceEventEmitter();
// 性能监控系统
class PerformanceMonitor {
constructor() {
this.isMonitoring = false;
this.monitoringInterval = 60000; // 默认监控间隔为1分钟
this.metricsHistory = {
database: [],
api: [],
system: [],
memory: []
};
this.historyLimit = 100; // 历史记录限制
this.alertThresholds = {
database: {
connectionPoolUtilization: 80, // 连接池利用率阈值(百分比)
slowQueryCount: 5, // 慢查询数量阈值
errorRate: 5 // 错误率阈值(百分比)
},
api: {
responseTime: 500, // API响应时间阈值毫秒
errorRate: 5, // API错误率阈值百分比
requestRate: 1000 // 每分钟请求数阈值
},
system: {
cpuUsage: 80, // CPU使用率阈值百分比
memoryUsage: 80, // 内存使用率阈值(百分比)
diskUsage: 80 // 磁盘使用率阈值(百分比)
}
};
// 日志配置
this.logPath = path.join(process.cwd(), 'logs', 'performance');
this.ensureLogDirectory();
// API请求统计
this.apiStats = {
totalRequests: 0,
totalErrors: 0,
endpoints: new Map(), // 按端点统计
responseTimes: [],
lastReset: new Date()
};
// 初始化数据库监控
this.initDatabaseMonitoring();
}
// 确保日志目录存在
ensureLogDirectory() {
if (!fs.existsSync(this.logPath)) {
fs.mkdirSync(this.logPath, { recursive: true });
}
}
// 初始化数据库监控
initDatabaseMonitoring() {
// 监听数据库事件
dbMonitor.on('statusChange', (status) => {
this.recordDatabaseMetrics(status);
perfEvents.emit('databaseStatus', status);
});
dbMonitor.on('error', (error) => {
this.logError('database', error);
perfEvents.emit('databaseError', error);
});
dbMonitor.on('slowQuery', (query) => {
perfEvents.emit('slowQuery', query);
});
}
// 开始监控
startMonitoring(interval = this.monitoringInterval) {
if (this.isMonitoring) {
return { success: false, message: '监控已经在运行中' };
}
this.monitoringInterval = interval;
this.isMonitoring = true;
// 启动数据库监控
dbMonitor.startMonitoring(interval);
// 启动系统资源监控
this.monitoringTimer = setInterval(() => {
this.collectSystemMetrics();
}, interval);
logger.info(`性能监控已启动,监控间隔: ${interval}ms`);
perfEvents.emit('monitoringStarted', { interval });
return { success: true, message: `性能监控已启动,监控间隔: ${interval}ms` };
}
// 停止监控
stopMonitoring() {
if (!this.isMonitoring) {
return { success: false, message: '监控未在运行' };
}
// 停止数据库监控
dbMonitor.stopMonitoring();
// 停止系统资源监控
clearInterval(this.monitoringTimer);
this.isMonitoring = false;
logger.info('性能监控已停止');
perfEvents.emit('monitoringStopped');
return { success: true, message: '性能监控已停止' };
}
// 收集系统指标
collectSystemMetrics() {
try {
// 获取CPU使用情况
const cpuUsage = this.getCpuUsage();
// 获取内存使用情况
const memoryUsage = this.getMemoryUsage();
// 获取磁盘使用情况
const diskUsage = this.getDiskUsage();
// 记录系统指标
this.recordSystemMetrics({ cpuUsage, memoryUsage, diskUsage });
// 检查是否需要发出警报
this.checkSystemAlerts({ cpuUsage, memoryUsage, diskUsage });
return { cpuUsage, memoryUsage, diskUsage };
} catch (error) {
this.logError('system', error);
return { error: error.message };
}
}
// 获取CPU使用情况
getCpuUsage() {
try {
const cpus = os.cpus();
let totalIdle = 0;
let totalTick = 0;
cpus.forEach(cpu => {
for (const type in cpu.times) {
totalTick += cpu.times[type];
}
totalIdle += cpu.times.idle;
});
const idle = totalIdle / cpus.length;
const total = totalTick / cpus.length;
const usage = 100 - (idle / total * 100);
return {
usage: parseFloat(usage.toFixed(2)),
cores: cpus.length,
model: cpus[0].model,
speed: cpus[0].speed
};
} catch (error) {
logger.error('获取CPU使用情况失败:', error);
return { usage: 0, error: error.message };
}
}
// 获取内存使用情况
getMemoryUsage() {
try {
const totalMemory = os.totalmem();
const freeMemory = os.freemem();
const usedMemory = totalMemory - freeMemory;
const usage = (usedMemory / totalMemory) * 100;
return {
total: totalMemory,
free: freeMemory,
used: usedMemory,
usage: parseFloat(usage.toFixed(2))
};
} catch (error) {
logger.error('获取内存使用情况失败:', error);
return { usage: 0, error: error.message };
}
}
// 获取磁盘使用情况(简化版,实际生产环境可能需要使用第三方库)
getDiskUsage() {
// 注意这是一个简化的实现实际生产环境可能需要使用第三方库如diskusage
try {
// 在实际生产环境中,这里应该使用适当的库来获取磁盘使用情况
// 这里返回一个模拟值
return {
total: 1000000000, // 1GB
free: 500000000, // 500MB
used: 500000000, // 500MB
usage: 50.0 // 50%
};
} catch (error) {
logger.error('获取磁盘使用情况失败:', error);
return { usage: 0, error: error.message };
}
}
// 记录API请求
recordApiRequest(req, res, startTime) {
const duration = Date.now() - startTime;
const endpoint = `${req.method} ${req.path}`;
const statusCode = res.statusCode;
const isError = statusCode >= 400;
// 更新总体统计
this.apiStats.totalRequests++;
if (isError) this.apiStats.totalErrors++;
this.apiStats.responseTimes.push(duration);
// 限制响应时间数组大小
if (this.apiStats.responseTimes.length > 1000) {
this.apiStats.responseTimes.shift();
}
// 更新端点统计
if (!this.apiStats.endpoints.has(endpoint)) {
this.apiStats.endpoints.set(endpoint, {
count: 0,
errors: 0,
totalDuration: 0,
avgDuration: 0,
minDuration: duration,
maxDuration: duration
});
}
const endpointStats = this.apiStats.endpoints.get(endpoint);
endpointStats.count++;
if (isError) endpointStats.errors++;
endpointStats.totalDuration += duration;
endpointStats.avgDuration = endpointStats.totalDuration / endpointStats.count;
endpointStats.minDuration = Math.min(endpointStats.minDuration, duration);
endpointStats.maxDuration = Math.max(endpointStats.maxDuration, duration);
// 记录API指标
this.recordApiMetrics({
endpoint,
statusCode,
duration,
timestamp: new Date(),
isError
});
// 检查是否需要发出警报
if (duration > this.alertThresholds.api.responseTime) {
perfEvents.emit('slowApiRequest', {
endpoint,
duration,
threshold: this.alertThresholds.api.responseTime
});
}
return {
endpoint,
statusCode,
duration,
isError
};
}
// 记录数据库指标
recordDatabaseMetrics(metrics) {
this.metricsHistory.database.push({
...metrics,
timestamp: new Date()
});
// 限制历史记录大小
if (this.metricsHistory.database.length > this.historyLimit) {
this.metricsHistory.database.shift();
}
// 记录到文件
this.logStatus('database', metrics);
}
// 记录API指标
recordApiMetrics(metrics) {
this.metricsHistory.api.push(metrics);
// 限制历史记录大小
if (this.metricsHistory.api.length > this.historyLimit) {
this.metricsHistory.api.shift();
}
}
// 记录系统指标
recordSystemMetrics(metrics) {
this.metricsHistory.system.push({
...metrics,
timestamp: new Date()
});
// 限制历史记录大小
if (this.metricsHistory.system.length > this.historyLimit) {
this.metricsHistory.system.shift();
}
// 记录到文件
this.logStatus('system', metrics);
}
// 检查系统警报
checkSystemAlerts(metrics) {
// 检查CPU使用率
if (metrics.cpuUsage && metrics.cpuUsage.usage > this.alertThresholds.system.cpuUsage) {
perfEvents.emit('highCpuUsage', {
usage: metrics.cpuUsage.usage,
threshold: this.alertThresholds.system.cpuUsage
});
}
// 检查内存使用率
if (metrics.memoryUsage && metrics.memoryUsage.usage > this.alertThresholds.system.memoryUsage) {
perfEvents.emit('highMemoryUsage', {
usage: metrics.memoryUsage.usage,
threshold: this.alertThresholds.system.memoryUsage
});
}
// 检查磁盘使用率
if (metrics.diskUsage && metrics.diskUsage.usage > this.alertThresholds.system.diskUsage) {
perfEvents.emit('highDiskUsage', {
usage: metrics.diskUsage.usage,
threshold: this.alertThresholds.system.diskUsage
});
}
}
// 记录状态日志
logStatus(type, data) {
try {
const logFile = path.join(this.logPath, `${type}-${new Date().toISOString().split('T')[0]}.log`);
const logData = JSON.stringify({
timestamp: new Date().toISOString(),
data
});
fs.appendFileSync(logFile, logData + '\n');
} catch (error) {
logger.error(`记录${type}状态日志失败:`, error);
}
}
// 记录错误日志
logError(type, error) {
try {
const logFile = path.join(this.logPath, `${type}-error-${new Date().toISOString().split('T')[0]}.log`);
const logData = JSON.stringify({
timestamp: new Date().toISOString(),
error: error.message,
stack: error.stack
});
fs.appendFileSync(logFile, logData + '\n');
logger.error(`${type}错误:`, error);
} catch (logError) {
logger.error(`记录${type}错误日志失败:`, logError);
}
}
// 获取API统计信息
getApiStats() {
const responseTimes = this.apiStats.responseTimes;
const avgResponseTime = responseTimes.length > 0
? responseTimes.reduce((sum, time) => sum + time, 0) / responseTimes.length
: 0;
// 计算错误率
const errorRate = this.apiStats.totalRequests > 0
? (this.apiStats.totalErrors / this.apiStats.totalRequests) * 100
: 0;
// 计算每分钟请求数
const minutesSinceReset = (new Date() - this.apiStats.lastReset) / (1000 * 60);
const requestsPerMinute = minutesSinceReset > 0
? this.apiStats.totalRequests / minutesSinceReset
: 0;
return {
totalRequests: this.apiStats.totalRequests,
totalErrors: this.apiStats.totalErrors,
errorRate: parseFloat(errorRate.toFixed(2)),
avgResponseTime: parseFloat(avgResponseTime.toFixed(2)),
requestsPerMinute: parseFloat(requestsPerMinute.toFixed(2)),
endpoints: Array.from(this.apiStats.endpoints.entries()).map(([endpoint, stats]) => ({
endpoint,
...stats,
errorRate: stats.count > 0 ? (stats.errors / stats.count) * 100 : 0
})),
since: this.apiStats.lastReset
};
}
// 重置API统计信息
resetApiStats() {
this.apiStats = {
totalRequests: 0,
totalErrors: 0,
endpoints: new Map(),
responseTimes: [],
lastReset: new Date()
};
return { success: true, message: 'API统计信息已重置' };
}
// 获取数据库性能指标
async getDatabaseMetrics() {
try {
// 获取连接池状态
const poolStatus = await getPoolStatus();
// 获取慢查询
const slowQueries = queryOptimizer.getSlowQueries();
// 获取查询模式统计
const queryPatterns = queryOptimizer.getQueryPatternStats();
return {
poolStatus,
slowQueries,
queryPatterns,
history: this.metricsHistory.database
};
} catch (error) {
this.logError('database', error);
return { error: error.message };
}
}
// 获取系统性能指标
getSystemMetrics() {
try {
return {
current: {
cpu: this.getCpuUsage(),
memory: this.getMemoryUsage(),
disk: this.getDiskUsage()
},
history: this.metricsHistory.system
};
} catch (error) {
this.logError('system', error);
return { error: error.message };
}
}
// 获取所有性能指标
async getAllMetrics() {
try {
const [databaseMetrics, apiStats, systemMetrics] = await Promise.all([
this.getDatabaseMetrics(),
this.getApiStats(),
this.getSystemMetrics()
]);
return {
database: databaseMetrics,
api: apiStats,
system: systemMetrics,
timestamp: new Date()
};
} catch (error) {
logger.error('获取所有性能指标失败:', error);
return { error: error.message };
}
}
// 设置警报阈值
setAlertThresholds(thresholds) {
if (thresholds.database) {
this.alertThresholds.database = {
...this.alertThresholds.database,
...thresholds.database
};
}
if (thresholds.api) {
this.alertThresholds.api = {
...this.alertThresholds.api,
...thresholds.api
};
}
if (thresholds.system) {
this.alertThresholds.system = {
...this.alertThresholds.system,
...thresholds.system
};
}
return { success: true, thresholds: this.alertThresholds };
}
// 获取警报阈值
getAlertThresholds() {
return this.alertThresholds;
}
// 设置监控间隔
setMonitoringInterval(interval) {
if (this.isMonitoring) {
this.stopMonitoring();
this.startMonitoring(interval);
} else {
this.monitoringInterval = interval;
}
return { success: true, interval };
}
// 获取监控状态
getMonitoringStatus() {
return {
isMonitoring: this.isMonitoring,
interval: this.monitoringInterval,
startedAt: this.startedAt
};
}
}
// 创建性能监控实例
const performanceMonitor = new PerformanceMonitor();
// 创建Express中间件
function performanceMonitorMiddleware(req, res, next) {
const startTime = Date.now();
// 在请求结束时记录性能指标
res.on('finish', () => {
performanceMonitor.recordApiRequest(req, res, startTime);
});
next();
}
module.exports = {
performanceMonitor,
performanceMonitorMiddleware,
events: perfEvents
};

View File

@@ -0,0 +1,517 @@
/**
* 数据库查询优化器
* @file query-optimizer.js
* @description 监控和优化SQL查询性能
*/
const { sequelize } = require('../config/database-pool');
const { QueryTypes } = require('sequelize');
// 查询性能日志
class QueryPerformanceLog {
constructor() {
this.logs = [];
this.maxLogs = 200; // 最多保存200条日志
this.slowQueryThreshold = 500; // 慢查询阈值(毫秒)
this.queryPatterns = new Map(); // 存储查询模式及其统计信息
}
// 添加日志
add(query, duration, params = {}) {
const log = {
query,
duration,
params,
timestamp: new Date(),
isSlow: duration > this.slowQueryThreshold
};
this.logs.unshift(log); // 添加到开头
// 保持日志数量不超过最大值
if (this.logs.length > this.maxLogs) {
this.logs.pop();
}
// 如果是慢查询,输出警告
if (log.isSlow) {
console.warn(`慢查询 (${duration}ms): ${query}`);
console.warn('参数:', params);
}
// 更新查询模式统计
this.updateQueryPatternStats(query, duration);
return log;
}
// 更新查询模式统计
updateQueryPatternStats(query, duration) {
// 简化查询,移除具体参数值,保留查询结构
const patternQuery = this.simplifyQuery(query);
if (!this.queryPatterns.has(patternQuery)) {
this.queryPatterns.set(patternQuery, {
count: 0,
totalDuration: 0,
avgDuration: 0,
minDuration: duration,
maxDuration: duration,
lastSeen: new Date()
});
}
const stats = this.queryPatterns.get(patternQuery);
stats.count++;
stats.totalDuration += duration;
stats.avgDuration = stats.totalDuration / stats.count;
stats.minDuration = Math.min(stats.minDuration, duration);
stats.maxDuration = Math.max(stats.maxDuration, duration);
stats.lastSeen = new Date();
}
// 简化查询,移除具体参数值
simplifyQuery(query) {
return query
.replace(/('([^']*)'|"([^"]*)")/g, '?') // 替换字符串
.replace(/\b\d+\b/g, '?') // 替换数字
.replace(/\s+/g, ' ') // 规范化空白字符
.trim();
}
// 获取所有日志
getLogs() {
return this.logs;
}
// 获取慢查询日志
getSlowLogs() {
return this.logs.filter(log => log.isSlow);
}
// 获取查询模式统计
getQueryPatternStats() {
return Array.from(this.queryPatterns.entries()).map(([pattern, stats]) => ({
pattern,
...stats
}));
}
// 获取最常见的查询模式
getMostFrequentQueries(limit = 10) {
return this.getQueryPatternStats()
.sort((a, b) => b.count - a.count)
.slice(0, limit);
}
// 获取平均执行时间最长的查询模式
getSlowestQueries(limit = 10) {
return this.getQueryPatternStats()
.sort((a, b) => b.avgDuration - a.avgDuration)
.slice(0, limit);
}
// 清除日志
clear() {
this.logs = [];
this.queryPatterns.clear();
}
// 设置慢查询阈值
setSlowQueryThreshold(threshold) {
this.slowQueryThreshold = threshold;
return this.slowQueryThreshold;
}
// 获取慢查询阈值
getSlowQueryThreshold() {
return this.slowQueryThreshold;
}
}
// 创建性能日志实例
const performanceLog = new QueryPerformanceLog();
// 查询优化器
class QueryOptimizer {
constructor(sequelize, performanceLog) {
this.sequelize = sequelize;
this.performanceLog = performanceLog;
this.indexSuggestions = new Map(); // 存储索引建议
this.setupLogging();
}
// 设置查询日志记录
setupLogging() {
// 如果已经在开发环境中启用了benchmark则不需要额外设置
if (!this.sequelize.options.benchmark) {
const originalQuery = this.sequelize.query.bind(this.sequelize);
this.sequelize.query = async function (...args) {
const start = Date.now();
try {
const result = await originalQuery(...args);
const duration = Date.now() - start;
// 记录查询性能
performanceLog.add(args[0], duration, args[1]);
return result;
} catch (error) {
const duration = Date.now() - start;
performanceLog.add(`ERROR: ${args[0]}`, duration, { ...args[1], error: error.message });
throw error;
}
};
}
}
// 分析表结构并提供优化建议
async analyzeTableStructure(tableName) {
try {
// 获取表结构
const tableInfo = await this.getTableInfo(tableName);
// 获取索引信息
const indexInfo = await this.getIndexInfo(tableName);
// 获取表数据统计
const tableStats = await this.getTableStats(tableName);
// 分析并生成建议
const suggestions = this.generateOptimizationSuggestions(
tableName,
tableInfo,
indexInfo,
tableStats
);
return {
tableName,
structure: tableInfo,
indexes: indexInfo,
stats: tableStats,
suggestions
};
} catch (error) {
console.error(`分析表 ${tableName} 结构失败:`, error);
return { error: error.message };
}
}
// 生成优化建议
generateOptimizationSuggestions(tableName, tableInfo, indexInfo, tableStats) {
const suggestions = [];
// 检查是否有主键
const hasPrimaryKey = indexInfo.some(idx => idx.Key_name === 'PRIMARY');
if (!hasPrimaryKey) {
suggestions.push({
type: 'missing_primary_key',
importance: 'high',
message: `${tableName} 缺少主键,建议添加主键以提高性能`
});
}
// 检查大型TEXT/BLOB字段
const largeTextFields = tableInfo.structure.filter(
field => field.Type.includes('text') || field.Type.includes('blob')
);
if (largeTextFields.length > 0) {
suggestions.push({
type: 'large_text_fields',
importance: 'medium',
message: `${tableName} 包含 ${largeTextFields.length} 个大型TEXT/BLOB字段考虑将不常用的大型字段移至单独的表中`
});
}
// 检查表大小
if (tableStats && tableStats.data_length > 100 * 1024 * 1024) { // 大于100MB
suggestions.push({
type: 'large_table',
importance: 'medium',
message: `${tableName} 较大 (${Math.round(tableStats.data_length / (1024 * 1024))}MB),考虑分区或归档旧数据`
});
}
// 从查询日志中分析可能需要的索引
const suggestedIndexes = this.suggestIndexesFromQueries(tableName);
suggestedIndexes.forEach(suggestion => {
suggestions.push({
type: 'suggested_index',
importance: 'high',
message: `建议在表 ${tableName}${suggestion.columns.join(', ')} 列上创建索引,可能提高查询性能`,
details: suggestion
});
});
return suggestions;
}
// 从查询日志中分析可能需要的索引
suggestIndexesFromQueries(tableName) {
// 获取与该表相关的慢查询
const tableQueries = this.performanceLog.getSlowLogs()
.filter(log => log.query.includes(tableName));
// 简单的索引建议逻辑 - 实际实现会更复杂
const suggestions = [];
// 检查WHERE子句中频繁使用的列
const wherePattern = new RegExp(`${tableName}\\s+WHERE\\s+([\\w\\s,=<>!]+)`, 'i');
tableQueries.forEach(log => {
const match = log.query.match(wherePattern);
if (match && match[1]) {
const whereClause = match[1];
// 提取列名 - 这是一个简化的实现
const columnMatches = whereClause.match(/\b(\w+)\b\s*[=<>!]/g);
if (columnMatches) {
const columns = columnMatches.map(col => col.trim().replace(/[=<>!\s]/g, ''));
// 检查这些列是否已经在建议中
const key = columns.sort().join(',');
if (!this.indexSuggestions.has(key)) {
this.indexSuggestions.set(key, {
tableName,
columns,
queryCount: 1,
avgDuration: log.duration
});
} else {
const suggestion = this.indexSuggestions.get(key);
suggestion.queryCount++;
suggestion.avgDuration = (suggestion.avgDuration * (suggestion.queryCount - 1) + log.duration) / suggestion.queryCount;
}
}
}
});
// 返回针对该表的索引建议
return Array.from(this.indexSuggestions.values())
.filter(suggestion => suggestion.tableName === tableName)
.sort((a, b) => b.queryCount - a.queryCount);
}
// 获取表统计信息
async getTableStats(tableName) {
try {
const stats = await this.sequelize.query(
'SHOW TABLE STATUS LIKE ?',
{
replacements: [tableName],
type: QueryTypes.SELECT
}
);
return stats[0] || null;
} catch (error) {
console.error(`获取表 ${tableName} 统计信息失败:`, error);
return null;
}
}
// 分析和优化表
async analyzeAndOptimizeTable(tableName) {
try {
// 分析表
await this.sequelize.query(`ANALYZE TABLE ${tableName}`, { type: QueryTypes.RAW });
// 优化表
const optimizeResult = await this.sequelize.query(`OPTIMIZE TABLE ${tableName}`, { type: QueryTypes.RAW });
return optimizeResult[0];
} catch (error) {
console.error(`分析和优化表 ${tableName} 失败:`, error);
return { error: error.message };
}
}
// 获取表的索引信息
async getIndexInfo(tableName) {
try {
const indexInfo = await this.sequelize.query(
'SHOW INDEX FROM ??',
{
replacements: [tableName],
type: QueryTypes.SELECT
}
);
return indexInfo;
} catch (error) {
console.error(`获取表 ${tableName} 的索引信息失败:`, error);
return [];
}
}
// 获取表信息
async getTableInfo(tableName) {
try {
// 获取表状态
const tableStatus = await this.sequelize.query(
'SHOW TABLE STATUS LIKE ?',
{
replacements: [tableName],
type: QueryTypes.SELECT
}
);
// 获取表结构
const tableStructure = await this.sequelize.query(
'DESCRIBE ??',
{
replacements: [tableName],
type: QueryTypes.SELECT
}
);
return {
status: tableStatus[0] || {},
structure: tableStructure
};
} catch (error) {
console.error(`获取表 ${tableName} 信息失败:`, error);
return { error: error.message };
}
}
// 解释查询计划
async explainQuery(query, params = {}) {
try {
// 执行EXPLAIN
const explainResult = await this.sequelize.query(
`EXPLAIN ${query}`,
{
replacements: params.replacements || [],
type: QueryTypes.SELECT
}
);
return explainResult;
} catch (error) {
console.error('解释查询计划失败:', error);
return [];
}
}
// 识别慢查询
async identifySlowQueries(threshold = this.performanceLog.slowQueryThreshold) {
try {
// 从性能日志中获取慢查询
const slowLogs = this.performanceLog.getSlowLogs();
// 如果性能日志中没有足够的数据,则从数据库中查询
if (slowLogs.length < 5) {
const dbSlowQueries = await this.sequelize.query(
'SELECT * FROM information_schema.PROCESSLIST WHERE TIME > ?',
{
replacements: [threshold / 1000], // 转换为秒
type: QueryTypes.SELECT
}
);
return dbSlowQueries;
}
return slowLogs;
} catch (error) {
console.error('识别慢查询失败:', error);
return [];
}
}
// 获取数据库状态
async getDatabaseStatus() {
try {
// 获取全局状态
const globalStatus = await this.sequelize.query(
'SHOW GLOBAL STATUS',
{ type: QueryTypes.SELECT }
);
// 转换为对象格式
const status = {};
globalStatus.forEach(item => {
if (item.Variable_name && item.Value) {
status[item.Variable_name] = item.Value;
}
});
// 提取关键指标
return {
connections: {
max_used: status.Max_used_connections,
current: status.Threads_connected,
running: status.Threads_running,
created: status.Threads_created,
cached: status.Threads_cached
},
queries: {
total: status.Questions,
slow: status.Slow_queries,
qps: status.Queries
},
buffer_pool: {
size: status.Innodb_buffer_pool_pages_total,
free: status.Innodb_buffer_pool_pages_free,
dirty: status.Innodb_buffer_pool_pages_dirty,
reads: status.Innodb_buffer_pool_reads,
read_requests: status.Innodb_buffer_pool_read_requests,
hit_rate: status.Innodb_buffer_pool_read_requests && status.Innodb_buffer_pool_reads
? (1 - parseInt(status.Innodb_buffer_pool_reads) / parseInt(status.Innodb_buffer_pool_read_requests)) * 100
: 0
},
performance: {
slow_queries_count: this.performanceLog.getSlowLogs().length,
total_queries_logged: this.performanceLog.getLogs().length,
query_patterns: this.performanceLog.getQueryPatternStats().length
}
};
} catch (error) {
console.error('获取数据库状态失败:', error);
return { error: error.message };
}
}
// 获取所有查询日志
getAllQueries() {
return this.performanceLog.getLogs();
}
// 获取慢查询
getSlowQueries() {
return this.performanceLog.getSlowLogs();
}
// 获取查询模式统计
getQueryPatternStats() {
return this.performanceLog.getQueryPatternStats();
}
// 获取最常见的查询
getMostFrequentQueries(limit = 10) {
return this.performanceLog.getMostFrequentQueries(limit);
}
// 获取最慢的查询
getSlowestQueries(limit = 10) {
return this.performanceLog.getSlowestQueries(limit);
}
// 设置慢查询阈值
setSlowQueryThreshold(threshold) {
return this.performanceLog.setSlowQueryThreshold(threshold);
}
// 清除性能日志
clearPerformanceLogs() {
this.performanceLog.clear();
this.indexSuggestions.clear();
return { success: true, message: '性能日志已清除' };
}
}
// 创建查询优化器实例
const queryOptimizer = new QueryOptimizer(sequelize, performanceLog);
module.exports = queryOptimizer;