/** * 性能监控中间件 * * 功能描述: * - 监控WebSocket事件处理的性能指标 * - 收集响应时间、吞吐量等关键数据 * - 提供实时性能统计和报告 * - 支持性能预警和异常检测 * * 职责分离: * - 性能收集:记录事件处理的时间和资源消耗 * - 数据分析:计算平均值、百分位数等统计指标 * - 监控报警:检测性能异常和瓶颈 * - 报告生成:提供详细的性能分析报告 * * 技术实现: * - 高精度计时:使用process.hrtime进行精确测量 * - 内存优化:循环缓冲区存储历史数据 * - 异步处理:不影响正常业务流程 * - 统计算法:实时计算各种性能指标 * * 最近修改: * - 2026-01-08: 代码重构 - 提取魔法数字为常量,优化代码质量 (修改者: moyin) * * @author moyin * @version 1.1.0 * @since 2026-01-08 * @lastModified 2026-01-08 */ import { Injectable, Logger } from '@nestjs/common'; /** * 扩展的WebSocket接口 */ interface ExtendedWebSocket extends WebSocket { id: string; userId?: string; } /** * 性能指标接口 */ interface PerformanceMetric { /** 事件名称 */ eventName: string; /** 处理时间(毫秒) */ duration: number; /** 时间戳 */ timestamp: number; /** 用户ID */ userId?: string; /** Socket ID */ socketId: string; /** 是否成功 */ success: boolean; /** 错误信息 */ error?: string; } /** * 事件统计信息 */ export interface EventStats { /** 事件名称 */ eventName: string; /** 总请求数 */ totalRequests: number; /** 成功请求数 */ successRequests: number; /** 失败请求数 */ failedRequests: number; /** 平均响应时间 */ avgDuration: number; /** 最小响应时间 */ minDuration: number; /** 最大响应时间 */ maxDuration: number; /** 95百分位响应时间 */ p95Duration: number; /** 99百分位响应时间 */ p99Duration: number; /** 每秒请求数 */ requestsPerSecond: number; /** 成功率 */ successRate: number; } /** * 系统性能概览 */ export interface SystemPerformance { /** 总连接数 */ totalConnections: number; /** 活跃连接数 */ activeConnections: number; /** 总事件数 */ totalEvents: number; /** 平均响应时间 */ avgResponseTime: number; /** 系统吞吐量(事件/秒) */ throughput: number; /** 错误率 */ errorRate: number; /** 内存使用情况 */ memoryUsage: { used: number; total: number; percentage: number; }; /** 统计时间戳 */ timestamp: number; } /** * 性能预警配置 */ interface AlertConfig { /** 响应时间阈值(毫秒) */ responseTimeThreshold: number; /** 错误率阈值(百分比) */ errorRateThreshold: number; /** 吞吐量下限 */ throughputThreshold: number; /** 内存使用率阈值 */ memoryThreshold: number; /** 是否启用预警 */ enabled: boolean; } @Injectable() export class PerformanceMonitorMiddleware { private readonly logger = new Logger(PerformanceMonitorMiddleware.name); /** 性能指标缓存最大数量 */ private static readonly MAX_METRICS = 10000; /** 统计更新间隔(毫秒) */ private static readonly STATS_UPDATE_INTERVAL = 10000; /** 清理间隔(毫秒) */ private static readonly CLEANUP_INTERVAL = 300000; /** 响应时间阈值(毫秒) */ private static readonly RESPONSE_TIME_THRESHOLD = 1000; /** 错误率阈值(百分比) */ private static readonly ERROR_RATE_THRESHOLD = 5; /** 吞吐量阈值(事件/秒) */ private static readonly THROUGHPUT_THRESHOLD = 10; /** 内存使用率阈值(百分比) */ private static readonly MEMORY_THRESHOLD = 80; /** 时间转换常量 */ private static readonly MILLISECONDS_PER_SECOND = 1000; private static readonly SECONDS_PER_MINUTE = 60; private static readonly MINUTES_PER_HOUR = 60; private static readonly HOURS_PER_DAY = 24; /** 百分位数计算常量 */ private static readonly PERCENTILE_95 = 95; private static readonly PERCENTILE_99 = 99; /** 精度计算常量 */ private static readonly PRECISION_MULTIPLIER = 100; private static readonly HIGH_PRECISION_MULTIPLIER = 10000; /** 内存单位转换 */ private static readonly BYTES_PER_KB = 1024; private static readonly KB_PER_MB = 1024; /** 性能趋势间隔(分钟) */ private static readonly TREND_INTERVAL_MINUTES = 5; /** 窗口数据保留倍数 */ private static readonly WINDOW_RETENTION_MULTIPLIER = 10; /** 报告默认时间范围(小时) */ private static readonly DEFAULT_REPORT_HOURS = 1; /** 慢事件默认限制数量 */ private static readonly DEFAULT_SLOW_EVENTS_LIMIT = 10; /** 性能指标缓存(循环缓冲区) */ private readonly metrics: PerformanceMetric[] = []; private readonly maxMetrics = PerformanceMonitorMiddleware.MAX_METRICS; private metricsIndex = 0; /** 事件统计缓存 */ private readonly eventStats = new Map(); /** 连接统计 */ private connectionCount = 0; private activeConnections = new Set(); /** 预警配置 */ private alertConfig: AlertConfig = { responseTimeThreshold: PerformanceMonitorMiddleware.RESPONSE_TIME_THRESHOLD, errorRateThreshold: PerformanceMonitorMiddleware.ERROR_RATE_THRESHOLD, throughputThreshold: PerformanceMonitorMiddleware.THROUGHPUT_THRESHOLD, memoryThreshold: PerformanceMonitorMiddleware.MEMORY_THRESHOLD, enabled: true, }; constructor() { // 定期更新统计信息 setInterval(() => { this.updateEventStats(); this.checkAlerts(); }, PerformanceMonitorMiddleware.STATS_UPDATE_INTERVAL); // 定期清理过期数据 setInterval(() => { this.cleanupOldMetrics(); }, PerformanceMonitorMiddleware.CLEANUP_INTERVAL); } /** * 开始监控事件处理 * * @param eventName 事件名称 * @param client WebSocket客户端 * @returns 监控上下文 */ startMonitoring(eventName: string, client: ExtendedWebSocket): { startTime: [number, number]; eventName: string; client: ExtendedWebSocket } { const startTime = process.hrtime(); // 记录连接 this.activeConnections.add(client.id); return { startTime, eventName, client }; } /** * 结束监控并记录指标 * * @param context 监控上下文 * @param success 是否成功 * @param error 错误信息 */ endMonitoring( context: { startTime: [number, number]; eventName: string; client: ExtendedWebSocket }, success: boolean = true, error?: string, ): void { const endTime = process.hrtime(context.startTime); const duration = endTime[0] * PerformanceMonitorMiddleware.MILLISECONDS_PER_SECOND + endTime[1] / (PerformanceMonitorMiddleware.MILLISECONDS_PER_SECOND * PerformanceMonitorMiddleware.MILLISECONDS_PER_SECOND); const metric: PerformanceMetric = { eventName: context.eventName, duration, timestamp: Date.now(), userId: context.client.userId, socketId: context.client.id, success, error, }; this.recordMetric(metric); } /** * 记录连接事件 * * @param client WebSocket客户端 * @param connected 是否连接 */ recordConnection(client: ExtendedWebSocket, connected: boolean): void { if (connected) { this.connectionCount++; this.activeConnections.add(client.id); } else { this.activeConnections.delete(client.id); } this.logger.debug('连接状态变更', { socketId: client.id, connected, totalConnections: this.connectionCount, activeConnections: this.activeConnections.size, }); } /** * 获取事件统计信息 * * @param eventName 事件名称 * @returns 统计信息 */ getEventStats(eventName?: string): EventStats[] { if (eventName) { const stats = this.eventStats.get(eventName); return stats ? [stats] : []; } return Array.from(this.eventStats.values()); } /** * 获取系统性能概览 * * @returns 系统性能信息 */ getSystemPerformance(): SystemPerformance { const now = Date.now(); const recentMetrics = this.getRecentMetrics(PerformanceMonitorMiddleware.SECONDS_PER_MINUTE * PerformanceMonitorMiddleware.MILLISECONDS_PER_SECOND); // 最近1分钟的数据 const totalEvents = recentMetrics.length; const successfulEvents = recentMetrics.filter(m => m.success).length; const avgResponseTime = totalEvents > 0 ? recentMetrics.reduce((sum, m) => sum + m.duration, 0) / totalEvents : 0; const throughput = totalEvents / PerformanceMonitorMiddleware.SECONDS_PER_MINUTE; // 每秒事件数 const errorRate = totalEvents > 0 ? ((totalEvents - successfulEvents) / totalEvents) * PerformanceMonitorMiddleware.PRECISION_MULTIPLIER : 0; // 获取内存使用情况 const memUsage = process.memoryUsage(); const memoryUsage = { used: Math.round(memUsage.heapUsed / PerformanceMonitorMiddleware.BYTES_PER_KB / PerformanceMonitorMiddleware.KB_PER_MB), // MB total: Math.round(memUsage.heapTotal / PerformanceMonitorMiddleware.BYTES_PER_KB / PerformanceMonitorMiddleware.KB_PER_MB), // MB percentage: Math.round((memUsage.heapUsed / memUsage.heapTotal) * PerformanceMonitorMiddleware.PRECISION_MULTIPLIER), }; return { totalConnections: this.connectionCount, activeConnections: this.activeConnections.size, totalEvents, avgResponseTime: Math.round(avgResponseTime * PerformanceMonitorMiddleware.PRECISION_MULTIPLIER) / PerformanceMonitorMiddleware.PRECISION_MULTIPLIER, throughput: Math.round(throughput * PerformanceMonitorMiddleware.PRECISION_MULTIPLIER) / PerformanceMonitorMiddleware.PRECISION_MULTIPLIER, errorRate: Math.round(errorRate * PerformanceMonitorMiddleware.PRECISION_MULTIPLIER) / PerformanceMonitorMiddleware.PRECISION_MULTIPLIER, memoryUsage, timestamp: now, }; } /** * 获取性能报告 * * @param timeRange 时间范围(毫秒) * @returns 性能报告 */ getPerformanceReport(timeRange: number = PerformanceMonitorMiddleware.DEFAULT_REPORT_HOURS * PerformanceMonitorMiddleware.MINUTES_PER_HOUR * PerformanceMonitorMiddleware.SECONDS_PER_MINUTE * PerformanceMonitorMiddleware.MILLISECONDS_PER_SECOND): any { const metrics = this.getRecentMetrics(timeRange); const eventGroups = this.groupMetricsByEvent(metrics); const report = { timeRange, totalMetrics: metrics.length, systemPerformance: this.getSystemPerformance(), eventStats: this.getEventStats(), topSlowEvents: this.getTopSlowEvents(metrics, PerformanceMonitorMiddleware.DEFAULT_SLOW_EVENTS_LIMIT), errorSummary: this.getErrorSummary(metrics), performanceTrends: this.getPerformanceTrends(metrics), timestamp: Date.now(), }; return report; } /** * 更新预警配置 * * @param config 新配置 */ updateAlertConfig(config: Partial): void { this.alertConfig = { ...this.alertConfig, ...config }; this.logger.log('性能预警配置已更新', { config: this.alertConfig, timestamp: new Date().toISOString(), }); } /** * 清理性能数据 */ clearMetrics(): void { this.metrics.length = 0; this.metricsIndex = 0; this.eventStats.clear(); this.logger.log('性能监控数据已清理', { timestamp: new Date().toISOString(), }); } /** * 记录性能指标 * * @param metric 性能指标 * @private */ private recordMetric(metric: PerformanceMetric): void { // 使用循环缓冲区存储指标 this.metrics[this.metricsIndex] = metric; this.metricsIndex = (this.metricsIndex + 1) % this.maxMetrics; // 记录慢请求 if (metric.duration > this.alertConfig.responseTimeThreshold) { this.logger.warn('检测到慢请求', { eventName: metric.eventName, duration: metric.duration, userId: metric.userId, socketId: metric.socketId, threshold: this.alertConfig.responseTimeThreshold, }); } // 记录错误 if (!metric.success) { this.logger.error('事件处理失败', { eventName: metric.eventName, error: metric.error, userId: metric.userId, socketId: metric.socketId, duration: metric.duration, }); } } /** * 更新事件统计信息 * * @private */ private updateEventStats(): void { const recentMetrics = this.getRecentMetrics(60000); // 最近1分钟 const eventGroups = this.groupMetricsByEvent(recentMetrics); for (const [eventName, metrics] of eventGroups.entries()) { const durations = metrics.map(m => m.duration).sort((a, b) => a - b); const successCount = metrics.filter(m => m.success).length; const stats: EventStats = { eventName, totalRequests: metrics.length, successRequests: successCount, failedRequests: metrics.length - successCount, avgDuration: Math.round((durations.reduce((sum, d) => sum + d, 0) / durations.length) * PerformanceMonitorMiddleware.PRECISION_MULTIPLIER) / PerformanceMonitorMiddleware.PRECISION_MULTIPLIER, minDuration: durations[0] || 0, maxDuration: durations[durations.length - 1] || 0, p95Duration: this.getPercentile(durations, PerformanceMonitorMiddleware.PERCENTILE_95), p99Duration: this.getPercentile(durations, PerformanceMonitorMiddleware.PERCENTILE_99), requestsPerSecond: Math.round((metrics.length / PerformanceMonitorMiddleware.SECONDS_PER_MINUTE) * PerformanceMonitorMiddleware.PRECISION_MULTIPLIER) / PerformanceMonitorMiddleware.PRECISION_MULTIPLIER, successRate: Math.round((successCount / metrics.length) * PerformanceMonitorMiddleware.HIGH_PRECISION_MULTIPLIER) / PerformanceMonitorMiddleware.PRECISION_MULTIPLIER, }; this.eventStats.set(eventName, stats); } } /** * 检查性能预警 * * @private */ private checkAlerts(): void { if (!this.alertConfig.enabled) { return; } const systemPerf = this.getSystemPerformance(); // 检查响应时间 if (systemPerf.avgResponseTime > this.alertConfig.responseTimeThreshold) { this.logger.warn('响应时间过高预警', { current: systemPerf.avgResponseTime, threshold: this.alertConfig.responseTimeThreshold, timestamp: new Date().toISOString(), }); } // 检查错误率 if (systemPerf.errorRate > this.alertConfig.errorRateThreshold) { this.logger.warn('错误率过高预警', { current: systemPerf.errorRate, threshold: this.alertConfig.errorRateThreshold, timestamp: new Date().toISOString(), }); } // 检查吞吐量 if (systemPerf.throughput < this.alertConfig.throughputThreshold) { this.logger.warn('吞吐量过低预警', { current: systemPerf.throughput, threshold: this.alertConfig.throughputThreshold, timestamp: new Date().toISOString(), }); } // 检查内存使用 if (systemPerf.memoryUsage.percentage > this.alertConfig.memoryThreshold) { this.logger.warn('内存使用率过高预警', { current: systemPerf.memoryUsage.percentage, threshold: this.alertConfig.memoryThreshold, used: systemPerf.memoryUsage.used, total: systemPerf.memoryUsage.total, timestamp: new Date().toISOString(), }); } } /** * 获取最近的性能指标 * * @param timeRange 时间范围(毫秒) * @returns 性能指标列表 * @private */ private getRecentMetrics(timeRange: number): PerformanceMetric[] { const now = Date.now(); const cutoff = now - timeRange; return this.metrics.filter(metric => metric && metric.timestamp > cutoff); } /** * 按事件名称分组指标 * * @param metrics 性能指标列表 * @returns 分组后的指标 * @private */ private groupMetricsByEvent(metrics: PerformanceMetric[]): Map { const groups = new Map(); for (const metric of metrics) { if (!groups.has(metric.eventName)) { groups.set(metric.eventName, []); } groups.get(metric.eventName)!.push(metric); } return groups; } /** * 计算百分位数 * * @param values 数值数组(已排序) * @param percentile 百分位数 * @returns 百分位值 * @private */ private getPercentile(values: number[], percentile: number): number { if (values.length === 0) return 0; const index = Math.ceil((percentile / PerformanceMonitorMiddleware.PRECISION_MULTIPLIER) * values.length) - 1; return Math.round(values[Math.max(0, index)] * PerformanceMonitorMiddleware.PRECISION_MULTIPLIER) / PerformanceMonitorMiddleware.PRECISION_MULTIPLIER; } /** * 获取最慢的事件 * * @param metrics 性能指标 * @param limit 限制数量 * @returns 最慢事件列表 * @private */ private getTopSlowEvents(metrics: PerformanceMetric[], limit: number): PerformanceMetric[] { return metrics .sort((a, b) => b.duration - a.duration) .slice(0, limit); } /** * 获取错误摘要 * * @param metrics 性能指标 * @returns 错误摘要 * @private */ private getErrorSummary(metrics: PerformanceMetric[]): any { const errors = metrics.filter(m => !m.success); const errorGroups = new Map(); for (const error of errors) { const key = error.error || 'Unknown Error'; errorGroups.set(key, (errorGroups.get(key) || 0) + 1); } return { totalErrors: errors.length, errorRate: metrics.length > 0 ? (errors.length / metrics.length) * PerformanceMonitorMiddleware.PRECISION_MULTIPLIER : 0, errorTypes: Array.from(errorGroups.entries()).map(([error, count]) => ({ error, count })), }; } /** * 获取性能趋势 * * @param metrics 性能指标 * @returns 性能趋势数据 * @private */ private getPerformanceTrends(metrics: PerformanceMetric[]): any { // 按5分钟间隔分组 const intervals = new Map(); const intervalSize = PerformanceMonitorMiddleware.TREND_INTERVAL_MINUTES * PerformanceMonitorMiddleware.SECONDS_PER_MINUTE * PerformanceMonitorMiddleware.MILLISECONDS_PER_SECOND; for (const metric of metrics) { const interval = Math.floor(metric.timestamp / intervalSize) * intervalSize; if (!intervals.has(interval)) { intervals.set(interval, []); } intervals.get(interval)!.push(metric); } return Array.from(intervals.entries()).map(([interval, intervalMetrics]) => ({ timestamp: interval, avgDuration: intervalMetrics.reduce((sum, m) => sum + m.duration, 0) / intervalMetrics.length, requestCount: intervalMetrics.length, errorCount: intervalMetrics.filter(m => !m.success).length, })); } /** * 清理过期指标 * * @private */ private cleanupOldMetrics(): void { const cutoff = Date.now() - (PerformanceMonitorMiddleware.HOURS_PER_DAY * PerformanceMonitorMiddleware.MINUTES_PER_HOUR * PerformanceMonitorMiddleware.SECONDS_PER_MINUTE * PerformanceMonitorMiddleware.MILLISECONDS_PER_SECOND); let cleanedCount = 0; for (let i = 0; i < this.metrics.length; i++) { if (this.metrics[i] && this.metrics[i].timestamp < cutoff) { delete this.metrics[i]; cleanedCount++; } } if (cleanedCount > 0) { this.logger.debug('清理过期性能指标', { cleanedCount, remainingCount: this.metrics.filter(m => m).length, timestamp: new Date().toISOString(), }); } } } /** * 性能监控装饰器 * * 使用示例: * ```typescript * @PerformanceMonitor('position_update') * @SubscribeMessage('position_update') * async handlePositionUpdate(@ConnectedSocket() client: AuthenticatedSocket, @MessageBody() message: PositionUpdateMessage) { * // 处理位置更新 * } * ``` */ export function PerformanceMonitor(eventName?: string) { return function (_target: any, propertyName: string, descriptor: PropertyDescriptor) { const method = descriptor.value; const finalEventName = eventName || propertyName; descriptor.value = async function (...args: any[]) { const client = args[0] as ExtendedWebSocket; const performanceMonitor = new PerformanceMonitorMiddleware(); const context = performanceMonitor.startMonitoring(finalEventName, client); try { const result = await method.apply(this, args); performanceMonitor.endMonitoring(context, true); return result; } catch (error) { performanceMonitor.endMonitoring(context, false, error instanceof Error ? error.message : String(error)); throw error; } }; }; }