feat: 初始化项目结构并添加核心功能模块
- 新增文档模板和导航结构 - 实现服务器基础API路由和控制器 - 添加扩展插件配置和前端框架 - 引入多租户和权限管理模块 - 集成日志和数据库配置 - 添加核心业务模型和类型定义
This commit is contained in:
169
server/src/services/telemetry/PredictiveHealthService.ts
Normal file
169
server/src/services/telemetry/PredictiveHealthService.ts
Normal file
@@ -0,0 +1,169 @@
|
||||
import { logger } from '../../utils/logger';
|
||||
import { FeatureGovernanceService } from '../../core/governance/FeatureGovernanceService';
|
||||
import { RedisService } from '../../utils/RedisService';
|
||||
import db from '../../config/database';
|
||||
import os from 'os';
|
||||
|
||||
export interface HealthPrediction {
|
||||
metric: string;
|
||||
currentValue: number;
|
||||
predictedValue: number;
|
||||
threshold: number;
|
||||
probabilityOfFailure: number; // 0-1
|
||||
estimatedTimeUntilBreach: number; // minutes
|
||||
suggestedAction: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* [CORE_TELE_02] 预测性系统健康度看板 (Predictive Health)
|
||||
* @description 利用 AI 预测未来 24h 潜在瓶颈(如数据库连接耗尽、Redis 内存溢出、API 延迟激增)。
|
||||
* 遵循 V30.0 Zero-Mock 规范,基于真实遥测数据进行趋势分析。
|
||||
*/
|
||||
export class PredictiveHealthService {
|
||||
private static readonly PREDICTION_TABLE = 'cf_telemetry_predictions';
|
||||
|
||||
/**
|
||||
* 初始化数据库表
|
||||
*/
|
||||
static async initTable() {
|
||||
const hasTable = await db.schema.hasTable(this.PREDICTION_TABLE);
|
||||
if (!hasTable) {
|
||||
logger.info(`📦 Creating ${this.PREDICTION_TABLE} table...`);
|
||||
await db.schema.createTable(this.PREDICTION_TABLE, (table) => {
|
||||
table.increments('id').primary();
|
||||
table.string('metric', 64).notNullable();
|
||||
table.float('current_value').notNullable();
|
||||
table.float('predicted_value').notNullable();
|
||||
table.float('threshold').notNullable();
|
||||
table.float('probability_of_failure').notNullable();
|
||||
table.integer('estimated_time_until_breach').notNullable();
|
||||
table.text('suggested_action').notNullable();
|
||||
table.timestamp('created_at').defaultTo(db.fn.now());
|
||||
table.index(['metric', 'created_at']);
|
||||
});
|
||||
logger.info(`✅ Table ${this.PREDICTION_TABLE} created`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统健康度预测结果
|
||||
*/
|
||||
static async getHealthPredictions(tenantId?: string): Promise<HealthPrediction[]> {
|
||||
// Feature Flag Check
|
||||
if (!(await FeatureGovernanceService.isEnabled('CORE_TELE_PREDICTIVE_HEALTH', tenantId))) {
|
||||
return [];
|
||||
}
|
||||
|
||||
logger.info('[PredictiveHealth] Analyzing real-time system metrics for future bottlenecks...');
|
||||
|
||||
const predictions: HealthPrediction[] = [];
|
||||
|
||||
try {
|
||||
// 1. 数据库连接池分析
|
||||
const dbPool = (db.client as any).pool;
|
||||
const usedConns = dbPool?.used?.length || 0;
|
||||
const maxConns = dbPool?.max || 10;
|
||||
const dbUsage = (usedConns / maxConns) * 100;
|
||||
|
||||
// 简单线性外推预测 (基于历史 1 小时趋势)
|
||||
const dbTrend = await this.calculateTrend('DB_CONNECTION_POOL');
|
||||
const predictedDbUsage = Math.min(100, dbUsage + (dbTrend * 24)); // 预测 24h 后
|
||||
|
||||
predictions.push({
|
||||
metric: 'DB_CONNECTION_POOL',
|
||||
currentValue: Number(dbUsage.toFixed(2)),
|
||||
predictedValue: Number(predictedDbUsage.toFixed(2)),
|
||||
threshold: 90,
|
||||
probabilityOfFailure: predictedDbUsage > 90 ? 0.8 : 0.1,
|
||||
estimatedTimeUntilBreach: dbTrend > 0 ? Math.round((90 - dbUsage) / dbTrend) : -1,
|
||||
suggestedAction: predictedDbUsage > 90 ? 'Increase DB Pool Size or optimize long transactions.' : 'Healthy'
|
||||
});
|
||||
|
||||
// 2. Redis 内存分析
|
||||
const redis = RedisService.getClient();
|
||||
const info = await redis.info('memory');
|
||||
const usedMemoryMatch = info.match(/used_memory:(\d+)/);
|
||||
const maxMemoryMatch = info.match(/maxmemory:(\d+)/);
|
||||
|
||||
const usedMem = usedMemoryMatch ? parseInt(usedMemoryMatch[1]) / 1024 / 1024 : 0; // MB
|
||||
const maxMem = maxMemoryMatch && parseInt(maxMemoryMatch[1]) > 0
|
||||
? parseInt(maxMemoryMatch[1]) / 1024 / 1024
|
||||
: (os.totalmem() / 1024 / 1024) * 0.1; // 默认取系统内存 10%
|
||||
|
||||
const memUsage = (usedMem / maxMem) * 100;
|
||||
const memTrend = await this.calculateTrend('REDIS_MEMORY_USAGE');
|
||||
const predictedMemUsage = Math.min(100, memUsage + (memTrend * 24));
|
||||
|
||||
predictions.push({
|
||||
metric: 'REDIS_MEMORY_USAGE',
|
||||
currentValue: Number(memUsage.toFixed(2)),
|
||||
predictedValue: Number(predictedMemUsage.toFixed(2)),
|
||||
threshold: 85,
|
||||
probabilityOfFailure: predictedMemUsage > 85 ? 0.7 : 0.05,
|
||||
estimatedTimeUntilBreach: memTrend > 0 ? Math.round((85 - memUsage) / memTrend) : -1,
|
||||
suggestedAction: predictedMemUsage > 85 ? 'Enable Redis key eviction or upgrade memory quota.' : 'Healthy'
|
||||
});
|
||||
|
||||
// 3. 系统负载分析
|
||||
const load = os.loadavg()[0];
|
||||
const cpuCores = os.cpus().length;
|
||||
const loadUsage = (load / cpuCores) * 100;
|
||||
const loadTrend = await this.calculateTrend('SYSTEM_LOAD');
|
||||
const predictedLoad = loadUsage + (loadTrend * 24);
|
||||
|
||||
predictions.push({
|
||||
metric: 'SYSTEM_LOAD',
|
||||
currentValue: Number(loadUsage.toFixed(2)),
|
||||
predictedValue: Number(predictedLoad.toFixed(2)),
|
||||
threshold: 80,
|
||||
probabilityOfFailure: predictedLoad > 80 ? 0.6 : 0.1,
|
||||
estimatedTimeUntilBreach: loadTrend > 0 ? Math.round((80 - loadUsage) / loadTrend) : -1,
|
||||
suggestedAction: predictedLoad > 80 ? 'Scale out application nodes or check for CPU-intensive tasks.' : 'Healthy'
|
||||
});
|
||||
|
||||
// 持久化预测结果 (Zero-Mock 落地)
|
||||
for (const p of predictions) {
|
||||
await this.logPrediction(p);
|
||||
}
|
||||
|
||||
} catch (err: any) {
|
||||
logger.error(`[PredictiveHealth] Metric analysis failed: ${err.message}`);
|
||||
}
|
||||
|
||||
return predictions;
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于历史数据计算指标变化趋势 (每小时变化率)
|
||||
*/
|
||||
private static async calculateTrend(metric: string): Promise<number> {
|
||||
const history = await db(this.PREDICTION_TABLE)
|
||||
.where({ metric })
|
||||
.orderBy('created_at', 'desc')
|
||||
.limit(10);
|
||||
|
||||
if (history.length < 2) return 0;
|
||||
|
||||
const latest = history[0].current_value;
|
||||
const oldest = history[history.length - 1].current_value;
|
||||
const timeDiff = (new Date(history[0].created_at).getTime() - new Date(history[history.length - 1].created_at).getTime()) / 3600000; // hours
|
||||
|
||||
return timeDiff > 0 ? (latest - oldest) / timeDiff : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录预测结果用于回溯
|
||||
*/
|
||||
static async logPrediction(prediction: HealthPrediction) {
|
||||
await db(this.PREDICTION_TABLE).insert({
|
||||
metric: prediction.metric,
|
||||
current_value: prediction.currentValue,
|
||||
predicted_value: prediction.predictedValue,
|
||||
threshold: prediction.threshold,
|
||||
probability_of_failure: prediction.probabilityOfFailure,
|
||||
estimated_time_until_breach: prediction.estimatedTimeUntilBreach,
|
||||
suggested_action: prediction.suggestedAction,
|
||||
created_at: new Date()
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user