/**
* 性能监控工具类
* 提供性能指标收集、分析和报告功能
*/
const os = require('os');
const process = require('process');
const { performance, PerformanceObserver } = require('perf_hooks');
const Logger = require('./logger');
const config = require('../config/config');
const { ErrorHandler } = require('./error-handler');
/**
* 性能指标收集器
*/
class PerformanceCollector {
constructor() {
this.logger = new Logger();
this.errorHandler = new ErrorHandler();
this.metrics = new Map();
this.timers = new Map();
this.counters = new Map();
this.histograms = new Map();
this.startTime = Date.now();
this.isMonitoring = false;
// 性能观察器
this.observers = new Map();
this.setupPerformanceObservers();
}
/**
* 设置性能观察器
*/
setupPerformanceObservers() {
try {
// 观察函数调用性能
const functionObserver = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
this.recordMetric('function_duration', entry.name, entry.duration);
}
});
functionObserver.observe({ entryTypes: ['function'] });
this.observers.set('function', functionObserver);
// 观察HTTP请求性能
const httpObserver = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
this.recordMetric('http_duration', entry.name, entry.duration);
}
});
httpObserver.observe({ entryTypes: ['http'] });
this.observers.set('http', httpObserver);
} catch (error) {
this.logger.warn('性能观察器设置失败', { error: error.message });
}
}
/**
* 开始监控
*/
startMonitoring() {
if (this.isMonitoring) return;
this.isMonitoring = true;
const interval = config.get('performance.monitoring.metricsInterval') || 60000;
this.monitoringInterval = setInterval(() => {
this.collectSystemMetrics();
this.collectProcessMetrics();
this.collectCustomMetrics();
}, interval);
this.logger.info('性能监控已启动', { interval });
}
/**
* 停止监控
*/
stopMonitoring() {
if (!this.isMonitoring) return;
this.isMonitoring = false;
if (this.monitoringInterval) {
clearInterval(this.monitoringInterval);
}
this.logger.info('性能监控已停止');
}
/**
* 收集系统指标
*/
collectSystemMetrics() {
try {
const cpus = os.cpus();
const loadAvg = os.loadavg();
const totalMem = os.totalmem();
const freeMem = os.freemem();
const usedMem = totalMem - freeMem;
this.recordMetric('system', 'cpu_count', cpus.length);
this.recordMetric('system', 'load_avg_1m', loadAvg[0]);
this.recordMetric('system', 'load_avg_5m', loadAvg[1]);
this.recordMetric('system', 'load_avg_15m', loadAvg[2]);
this.recordMetric('system', 'memory_total', totalMem);
this.recordMetric('system', 'memory_free', freeMem);
this.recordMetric('system', 'memory_used', usedMem);
this.recordMetric('system', 'memory_usage_percent', (usedMem / totalMem) * 100);
// CPU使用率(需要计算差值)
this.calculateCPUUsage();
} catch (error) {
this.logger.error('系统指标收集错误', { error: error.message });
}
}
/**
* 收集进程指标
*/
collectProcessMetrics() {
try {
const memUsage = process.memoryUsage();
const cpuUsage = process.cpuUsage();
const uptime = process.uptime();
this.recordMetric('process', 'memory_rss', memUsage.rss);
this.recordMetric('process', 'memory_heap_total', memUsage.heapTotal);
this.recordMetric('process', 'memory_heap_used', memUsage.heapUsed);
this.recordMetric('process', 'memory_external', memUsage.external);
this.recordMetric('process', 'memory_array_buffers', memUsage.arrayBuffers || 0);
this.recordMetric('process', 'cpu_user', cpuUsage.user);
this.recordMetric('process', 'cpu_system', cpuUsage.system);
this.recordMetric('process', 'uptime', uptime);
this.recordMetric('process', 'pid', process.pid);
// 堆使用率
const heapUsagePercent = (memUsage.heapUsed / memUsage.heapTotal) * 100;
this.recordMetric('process', 'heap_usage_percent', heapUsagePercent);
} catch (error) {
this.logger.error('进程指标收集错误', { error: error.message });
}
}
/**
* 收集自定义指标
*/
collectCustomMetrics() {
try {
// 收集计数器指标
for (const [name, value] of this.counters.entries()) {
this.recordMetric('custom_counter', name, value);
}
// 收集直方图指标
for (const [name, histogram] of this.histograms.entries()) {
const stats = this.calculateHistogramStats(histogram);
this.recordMetric('custom_histogram', `${name}_count`, stats.count);
this.recordMetric('custom_histogram', `${name}_sum`, stats.sum);
this.recordMetric('custom_histogram', `${name}_avg`, stats.avg);
this.recordMetric('custom_histogram', `${name}_min`, stats.min);
this.recordMetric('custom_histogram', `${name}_max`, stats.max);
this.recordMetric('custom_histogram', `${name}_p50`, stats.p50);
this.recordMetric('custom_histogram', `${name}_p95`, stats.p95);
this.recordMetric('custom_histogram', `${name}_p99`, stats.p99);
}
} catch (error) {
this.logger.error('自定义指标收集错误', { error: error.message });
}
}
/**
* 计算CPU使用率
*/
calculateCPUUsage() {
const cpus = os.cpus();
let totalIdle = 0;
let totalTick = 0;
for (const cpu of cpus) {
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 - ~~(100 * idle / total);
this.recordMetric('system', 'cpu_usage_percent', usage);
}
/**
* 计算直方图统计信息
* @param {Array<number>} values - 数值数组
* @returns {Object} 统计信息
*/
calculateHistogramStats(values) {
if (values.length === 0) {
return {
count: 0,
sum: 0,
avg: 0,
min: 0,
max: 0,
p50: 0,
p95: 0,
p99: 0
};
}
const sorted = [...values].sort((a, b) => a - b);
const sum = values.reduce((a, b) => a + b, 0);
return {
count: values.length,
sum,
avg: sum / values.length,
min: sorted[0],
max: sorted[sorted.length - 1],
p50: this.percentile(sorted, 0.5),
p95: this.percentile(sorted, 0.95),
p99: this.percentile(sorted, 0.99)
};
}
/**
* 计算百分位数
* @param {Array<number>} sortedValues - 已排序的数值数组
* @param {number} percentile - 百分位数(0-1)
* @returns {number} 百分位数值
*/
percentile(sortedValues, percentile) {
const index = percentile * (sortedValues.length - 1);
const lower = Math.floor(index);
const upper = Math.ceil(index);
const weight = index % 1;
if (upper >= sortedValues.length) {
return sortedValues[sortedValues.length - 1];
}
return sortedValues[lower] * (1 - weight) + sortedValues[upper] * weight;
}
/**
* 记录指标
* @param {string} category - 指标分类
* @param {string} name - 指标名称
* @param {number} value - 指标值
* @param {Object} tags - 标签
*/
recordMetric(category, name, value, tags = {}) {
const key = `${category}.${name}`;
const timestamp = Date.now();
if (!this.metrics.has(key)) {
this.metrics.set(key, []);
}
const metric = {
value,
timestamp,
tags
};
this.metrics.get(key).push(metric);
// 限制历史数据量
const maxHistory = 1000;
const history = this.metrics.get(key);
if (history.length > maxHistory) {
history.splice(0, history.length - maxHistory);
}
}
/**
* 开始计时
* @param {string} name - 计时器名称
* @param {Object} tags - 标签
*/
startTimer(name, tags = {}) {
const timer = {
name,
startTime: performance.now(),
tags
};
this.timers.set(name, timer);
return timer;
}
/**
* 结束计时
* @param {string} name - 计时器名称
* @returns {number} 耗时(毫秒)
*/
endTimer(name) {
const timer = this.timers.get(name);
if (!timer) {
this.logger.warn('计时器不存在', { name });
return 0;
}
const duration = performance.now() - timer.startTime;
this.timers.delete(name);
// 记录到直方图
this.addToHistogram(`timer_${name}`, duration);
this.recordMetric('timer', name, duration, timer.tags);
return duration;
}
/**
* 增加计数器
* @param {string} name - 计数器名称
* @param {number} value - 增加值
*/
incrementCounter(name, value = 1) {
const current = this.counters.get(name) || 0;
this.counters.set(name, current + value);
}
/**
* 设置计数器值
* @param {string} name - 计数器名称
* @param {number} value - 计数器值
*/
setCounter(name, value) {
this.counters.set(name, value);
}
/**
* 获取计数器值
* @param {string} name - 计数器名称
* @returns {number} 计数器值
*/
getCounter(name) {
return this.counters.get(name) || 0;
}
/**
* 添加值到直方图
* @param {string} name - 直方图名称
* @param {number} value - 值
*/
addToHistogram(name, value) {
if (!this.histograms.has(name)) {
this.histograms.set(name, []);
}
const histogram = this.histograms.get(name);
histogram.push(value);
// 限制直方图大小
const maxSize = 10000;
if (histogram.length > maxSize) {
histogram.splice(0, histogram.length - maxSize);
}
}
/**
* 获取指标数据
* @param {string} key - 指标键
* @param {number} since - 起始时间戳
* @returns {Array} 指标数据
*/
getMetrics(key, since = 0) {
const metrics = this.metrics.get(key) || [];
return metrics.filter(m => m.timestamp >= since);
}
/**
* 获取所有指标键
* @returns {Array<string>} 指标键数组
*/
getMetricKeys() {
return Array.from(this.metrics.keys());
}
/**
* 获取性能摘要
* @returns {Object} 性能摘要
*/
getPerformanceSummary() {
const now = Date.now();
const uptime = now - this.startTime;
// 获取最新的系统指标
const getLatestMetric = (key) => {
const metrics = this.getMetrics(key);
return metrics.length > 0 ? metrics[metrics.length - 1].value : 0;
};
return {
uptime,
timestamp: now,
system: {
cpuUsage: getLatestMetric('system.cpu_usage_percent'),
memoryUsage: getLatestMetric('system.memory_usage_percent'),
loadAverage: {
'1m': getLatestMetric('system.load_avg_1m'),
'5m': getLatestMetric('system.load_avg_5m'),
'15m': getLatestMetric('system.load_avg_15m')
}
},
process: {
memoryUsage: {
rss: getLatestMetric('process.memory_rss'),
heapTotal: getLatestMetric('process.memory_heap_total'),
heapUsed: getLatestMetric('process.memory_heap_used'),
heapUsagePercent: getLatestMetric('process.heap_usage_percent')
},
cpuUsage: {
user: getLatestMetric('process.cpu_user'),
system: getLatestMetric('process.cpu_system')
},
uptime: getLatestMetric('process.uptime')
},
counters: Object.fromEntries(this.counters),
activeTimers: this.timers.size,
totalMetrics: this.metrics.size
};
}
/**
* 获取详细性能报告
* @param {number} timeRange - 时间范围(毫秒)
* @returns {Object} 详细报告
*/
getDetailedReport(timeRange = 3600000) { // 默认1小时
const since = Date.now() - timeRange;
const report = {
summary: this.getPerformanceSummary(),
metrics: {},
histograms: {},
analysis: {}
};
// 收集指标数据
for (const key of this.getMetricKeys()) {
const metrics = this.getMetrics(key, since);
if (metrics.length > 0) {
const values = metrics.map(m => m.value);
report.metrics[key] = {
count: values.length,
latest: values[values.length - 1],
stats: this.calculateHistogramStats(values)
};
}
}
// 收集直方图数据
for (const [name, values] of this.histograms.entries()) {
report.histograms[name] = this.calculateHistogramStats(values);
}
// 性能分析
report.analysis = this.analyzePerformance(report);
return report;
}
/**
* 分析性能数据
* @param {Object} report - 性能报告
* @returns {Object} 分析结果
*/
analyzePerformance(report) {
const analysis = {
alerts: [],
recommendations: [],
trends: {},
health: 'good'
};
const { system, process } = report.summary;
// CPU使用率分析
if (system.cpuUsage > 80) {
analysis.alerts.push({
type: 'high_cpu',
severity: 'warning',
message: `CPU使用率过高: ${system.cpuUsage.toFixed(2)}%`
});
analysis.health = 'warning';
}
// 内存使用率分析
if (system.memoryUsage > 85) {
analysis.alerts.push({
type: 'high_memory',
severity: 'warning',
message: `内存使用率过高: ${system.memoryUsage.toFixed(2)}%`
});
analysis.health = 'warning';
}
// 堆内存使用率分析
if (process.memoryUsage.heapUsagePercent > 90) {
analysis.alerts.push({
type: 'high_heap',
severity: 'critical',
message: `堆内存使用率过高: ${process.memoryUsage.heapUsagePercent.toFixed(2)}%`
});
analysis.health = 'critical';
}
// 负载平均值分析
const cpuCount = os.cpus().length;
if (system.loadAverage['5m'] > cpuCount * 0.8) {
analysis.alerts.push({
type: 'high_load',
severity: 'warning',
message: `系统负载过高: ${system.loadAverage['5m'].toFixed(2)}`
});
}
// 生成建议
if (analysis.alerts.length > 0) {
analysis.recommendations.push('考虑优化代码性能或增加系统资源');
}
if (process.memoryUsage.heapUsagePercent > 70) {
analysis.recommendations.push('建议进行垃圾回收优化或内存泄漏检查');
}
return analysis;
}
/**
* 清理历史数据
* @param {number} maxAge - 最大保留时间(毫秒)
*/
cleanup(maxAge = 86400000) { // 默认24小时
const cutoff = Date.now() - maxAge;
let cleanedCount = 0;
for (const [key, metrics] of this.metrics.entries()) {
const originalLength = metrics.length;
const filtered = metrics.filter(m => m.timestamp >= cutoff);
if (filtered.length !== originalLength) {
this.metrics.set(key, filtered);
cleanedCount += originalLength - filtered.length;
}
}
if (cleanedCount > 0) {
this.logger.debug('性能数据清理完成', { cleanedCount });
}
return cleanedCount;
}
/**
* 重置所有指标
*/
reset() {
this.metrics.clear();
this.timers.clear();
this.counters.clear();
this.histograms.clear();
this.startTime = Date.now();
}
/**
* 销毁性能收集器
*/
destroy() {
this.stopMonitoring();
// 断开性能观察器
for (const observer of this.observers.values()) {
observer.disconnect();
}
this.observers.clear();
this.reset();
}
}
/**
* 性能装饰器
* 用于自动测量函数执行时间
*/
function performanceDecorator(name, collector) {
return function (target, propertyKey, descriptor) {
const originalMethod = descriptor.value;
descriptor.value = async function (...args) {
const timerName = name || `${target.constructor.name}.${propertyKey}`;
collector.startTimer(timerName);
try {
const result = await originalMethod.apply(this, args);
collector.incrementCounter(`${timerName}_success`);
return result;
} catch (error) {
collector.incrementCounter(`${timerName}_error`);
throw error;
} finally {
collector.endTimer(timerName);
}
};
return descriptor;
};
}
/**
* 性能监控中间件
*/
function createPerformanceMiddleware(collector) {
return (req, res, next) => {
const startTime = performance.now();
const timerName = `http_${req.method}_${req.path}`;
collector.startTimer(timerName);
collector.incrementCounter('http_requests_total');
// 监听响应结束
res.on('finish', () => {
const duration = collector.endTimer(timerName);
collector.incrementCounter(`http_responses_${res.statusCode}`);
collector.addToHistogram('http_request_duration', duration);
// 记录慢请求
if (duration > 1000) {
collector.incrementCounter('http_slow_requests');
}
});
next();
};
}
module.exports = {
PerformanceCollector,
performanceDecorator,
createPerformanceMiddleware
};