167 lines
4.6 KiB
TypeScript
167 lines
4.6 KiB
TypeScript
// =====================================================
|
|
// 資料庫連線監控工具
|
|
// =====================================================
|
|
|
|
import { db } from './database';
|
|
|
|
export class DatabaseMonitor {
|
|
private static instance: DatabaseMonitor;
|
|
private connectionCount = 0;
|
|
private maxConnections = 0;
|
|
private isMonitoring = false;
|
|
private monitorInterval: NodeJS.Timeout | null = null;
|
|
|
|
private constructor() {}
|
|
|
|
public static getInstance(): DatabaseMonitor {
|
|
if (!DatabaseMonitor.instance) {
|
|
DatabaseMonitor.instance = new DatabaseMonitor();
|
|
}
|
|
return DatabaseMonitor.instance;
|
|
}
|
|
|
|
// 開始監控
|
|
public startMonitoring(intervalMs: number = 30000) {
|
|
if (this.isMonitoring) {
|
|
console.log('⚠️ 資料庫監控已在運行中');
|
|
return;
|
|
}
|
|
|
|
this.isMonitoring = true;
|
|
console.log('🔍 開始監控資料庫連線狀態...');
|
|
|
|
this.monitorInterval = setInterval(async () => {
|
|
await this.checkConnectionStatus();
|
|
}, intervalMs);
|
|
|
|
// 立即執行一次檢查
|
|
this.checkConnectionStatus();
|
|
}
|
|
|
|
// 停止監控
|
|
public stopMonitoring() {
|
|
if (this.monitorInterval) {
|
|
clearInterval(this.monitorInterval);
|
|
this.monitorInterval = null;
|
|
}
|
|
this.isMonitoring = false;
|
|
console.log('⏹️ 資料庫監控已停止');
|
|
}
|
|
|
|
// 檢查連線狀態
|
|
private async checkConnectionStatus() {
|
|
try {
|
|
// 檢查當前連線數
|
|
const statusResult = await db.queryOne(`
|
|
SHOW STATUS LIKE 'Threads_connected'
|
|
`);
|
|
|
|
const currentConnections = statusResult?.Value || 0;
|
|
this.connectionCount = parseInt(currentConnections);
|
|
|
|
// 檢查最大連線數
|
|
const maxConnResult = await db.queryOne(`
|
|
SHOW VARIABLES LIKE 'max_connections'
|
|
`);
|
|
|
|
this.maxConnections = parseInt(maxConnResult?.Value || '100');
|
|
|
|
// 檢查連線使用率
|
|
const usagePercentage = (this.connectionCount / this.maxConnections) * 100;
|
|
|
|
// 記錄狀態
|
|
console.log(`📊 資料庫連線狀態: ${this.connectionCount}/${this.maxConnections} (${usagePercentage.toFixed(1)}%)`);
|
|
|
|
// 警告檢查
|
|
if (usagePercentage > 80) {
|
|
console.warn(`⚠️ 資料庫連線使用率過高: ${usagePercentage.toFixed(1)}%`);
|
|
} else if (usagePercentage > 60) {
|
|
console.log(`⚠️ 資料庫連線使用率較高: ${usagePercentage.toFixed(1)}%`);
|
|
}
|
|
|
|
// 檢查長時間運行的查詢
|
|
await this.checkLongRunningQueries();
|
|
|
|
} catch (error) {
|
|
console.error('❌ 資料庫監控錯誤:', error);
|
|
}
|
|
}
|
|
|
|
// 檢查長時間運行的查詢
|
|
private async checkLongRunningQueries() {
|
|
try {
|
|
const longQueries = await db.query(`
|
|
SELECT
|
|
ID,
|
|
USER,
|
|
HOST,
|
|
DB,
|
|
COMMAND,
|
|
TIME,
|
|
STATE,
|
|
INFO
|
|
FROM information_schema.PROCESSLIST
|
|
WHERE TIME > 30
|
|
AND COMMAND != 'Sleep'
|
|
ORDER BY TIME DESC
|
|
LIMIT 5
|
|
`);
|
|
|
|
if (longQueries.length > 0) {
|
|
console.warn(`⚠️ 發現 ${longQueries.length} 個長時間運行的查詢:`);
|
|
longQueries.forEach((query, index) => {
|
|
console.warn(` ${index + 1}. 用戶: ${query.USER}, 時間: ${query.TIME}s, 狀態: ${query.STATE}`);
|
|
if (query.INFO && query.INFO.length > 100) {
|
|
console.warn(` 查詢: ${query.INFO.substring(0, 100)}...`);
|
|
} else if (query.INFO) {
|
|
console.warn(` 查詢: ${query.INFO}`);
|
|
}
|
|
});
|
|
}
|
|
} catch (error) {
|
|
console.error('❌ 檢查長時間查詢時發生錯誤:', error);
|
|
}
|
|
}
|
|
|
|
// 獲取連線統計
|
|
public getConnectionStats() {
|
|
return {
|
|
currentConnections: this.connectionCount,
|
|
maxConnections: this.maxConnections,
|
|
usagePercentage: (this.connectionCount / this.maxConnections) * 100,
|
|
isMonitoring: this.isMonitoring
|
|
};
|
|
}
|
|
|
|
// 強制釋放空閒連線
|
|
public async releaseIdleConnections() {
|
|
try {
|
|
const result = await db.query(`
|
|
KILL
|
|
(SELECT GROUP_CONCAT(ID)
|
|
FROM information_schema.PROCESSLIST
|
|
WHERE COMMAND = 'Sleep'
|
|
AND TIME > 300)
|
|
`);
|
|
|
|
console.log('🔄 已嘗試釋放空閒連線');
|
|
return true;
|
|
} catch (error) {
|
|
console.error('❌ 釋放空閒連線失敗:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// 獲取連線池狀態
|
|
public getPoolStatus() {
|
|
// 這裡可以添加更多連線池狀態信息
|
|
return {
|
|
isMonitoring: this.isMonitoring,
|
|
lastCheck: new Date().toISOString()
|
|
};
|
|
}
|
|
}
|
|
|
|
// 導出單例實例
|
|
export const dbMonitor = DatabaseMonitor.getInstance();
|