修正分頁、Too many connection 問題
This commit is contained in:
166
lib/database-monitor.ts
Normal file
166
lib/database-monitor.ts
Normal file
@@ -0,0 +1,166 @@
|
||||
// =====================================================
|
||||
// 資料庫連線監控工具
|
||||
// =====================================================
|
||||
|
||||
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();
|
Reference in New Issue
Block a user