mirror of
https://github.com/ets-cfuhrman-pfe/EvalueTonSavoir.git
synced 2025-08-11 21:23:54 -04:00
new approach using cgroup
This commit is contained in:
parent
b3d65e0a1e
commit
bb4ef54db9
3 changed files with 148 additions and 19 deletions
|
|
@ -1,5 +1,6 @@
|
|||
import { Server, Socket } from "socket.io";
|
||||
import os from "os";
|
||||
import fs from 'fs';
|
||||
|
||||
const MAX_USERS_PER_ROOM = 60;
|
||||
const MAX_TOTAL_CONNECTIONS = 2000;
|
||||
|
|
@ -114,30 +115,159 @@ export const setupWebsocket = (io: Server): void => {
|
|||
|
||||
class ContainerMetrics {
|
||||
private totalSystemMemory = os.totalmem();
|
||||
|
||||
getMetrics() {
|
||||
private cgroupv2 = this.isCgroupV2();
|
||||
private lastCPUUsage = 0;
|
||||
private lastCPUTime = Date.now();
|
||||
|
||||
private isCgroupV2(): boolean {
|
||||
return fs.existsSync('/sys/fs/cgroup/cgroup.controllers');
|
||||
}
|
||||
|
||||
private readCgroupFile(filepath: string): string {
|
||||
try {
|
||||
return fs.readFileSync(filepath, 'utf-8').trim();
|
||||
} catch (error) {
|
||||
console.debug(`Could not read ${filepath}`);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
private getCgroupCPUUsage(): number {
|
||||
try {
|
||||
if (this.cgroupv2) {
|
||||
const usage = this.readCgroupFile('/sys/fs/cgroup/cpu.stat');
|
||||
const usageMatch = usage.match(/usage_usec\s+(\d+)/);
|
||||
if (usageMatch) {
|
||||
const currentUsage = Number(usageMatch[1]) / 1000000;
|
||||
const currentTime = Date.now();
|
||||
const cpuDelta = currentUsage - this.lastCPUUsage;
|
||||
const timeDelta = (currentTime - this.lastCPUTime) / 1000;
|
||||
|
||||
this.lastCPUUsage = currentUsage;
|
||||
this.lastCPUTime = currentTime;
|
||||
|
||||
return (cpuDelta / timeDelta) * 100;
|
||||
}
|
||||
}
|
||||
|
||||
const cgroupV1Paths = [
|
||||
'/sys/fs/cgroup/cpu/cpuacct.usage',
|
||||
'/sys/fs/cgroup/cpuacct/cpuacct.usage',
|
||||
'/sys/fs/cgroup/cpu,cpuacct/cpuacct.usage'
|
||||
];
|
||||
|
||||
for (const path of cgroupV1Paths) {
|
||||
const usage = this.readCgroupFile(path);
|
||||
if (usage) {
|
||||
const currentUsage = Number(usage) / 1000000000;
|
||||
const currentTime = Date.now();
|
||||
const cpuDelta = currentUsage - this.lastCPUUsage;
|
||||
const timeDelta = (currentTime - this.lastCPUTime) / 1000;
|
||||
|
||||
this.lastCPUUsage = currentUsage;
|
||||
this.lastCPUTime = currentTime;
|
||||
|
||||
return (cpuDelta / timeDelta) * 100;
|
||||
}
|
||||
}
|
||||
|
||||
return this.getFallbackCPUUsage();
|
||||
} catch (error) {
|
||||
return this.getFallbackCPUUsage();
|
||||
}
|
||||
}
|
||||
|
||||
private getFallbackCPUUsage(): number {
|
||||
try {
|
||||
// Get CPU usage percentage directly from system
|
||||
const cpus = os.cpus();
|
||||
const cpuUsage = cpus.reduce((acc, cpu) => {
|
||||
return cpus.reduce((acc, cpu) => {
|
||||
const total = Object.values(cpu.times).reduce((a, b) => a + b);
|
||||
const idle = cpu.times.idle;
|
||||
return acc + ((total - idle) / total) * 100;
|
||||
}, 0) / cpus.length;
|
||||
|
||||
const memoryUsage = process.memoryUsage();
|
||||
const mbFactor = 1024 * 1024;
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error getting fallback CPU usage:', error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private getCgroupMemoryUsage(): { used: number; limit: number } | null {
|
||||
try {
|
||||
// First get process memory as baseline
|
||||
const processMemory = process.memoryUsage();
|
||||
const baselineMemory = processMemory.rss;
|
||||
|
||||
if (this.cgroupv2) {
|
||||
const memUsage = Number(this.readCgroupFile('/sys/fs/cgroup/memory.current'));
|
||||
if (!isNaN(memUsage) && memUsage > 0) {
|
||||
return {
|
||||
used: Math.max(baselineMemory, memUsage),
|
||||
limit: this.totalSystemMemory
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Try cgroup v1
|
||||
const v1Paths = {
|
||||
usage: '/sys/fs/cgroup/memory/memory.usage_in_bytes',
|
||||
limit: '/sys/fs/cgroup/memory/memory.limit_in_bytes'
|
||||
};
|
||||
|
||||
const memoryUsage = Number(this.readCgroupFile(v1Paths.usage));
|
||||
if (!isNaN(memoryUsage) && memoryUsage > 0) {
|
||||
return {
|
||||
used: Math.max(baselineMemory, memoryUsage),
|
||||
limit: this.totalSystemMemory
|
||||
};
|
||||
}
|
||||
|
||||
// Fallback to process memory
|
||||
return {
|
||||
memoryUsedMB: (memoryUsage.rss / mbFactor).toFixed(2),
|
||||
memoryUsedPercentage: (
|
||||
(memoryUsage.rss / this.totalSystemMemory) * 100
|
||||
).toFixed(2),
|
||||
cpuUsedPercentage: cpuUsage.toFixed(2)
|
||||
used: baselineMemory,
|
||||
limit: this.totalSystemMemory
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
console.debug('Error reading cgroup memory:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public getMetrics() {
|
||||
try {
|
||||
const mbFactor = 1024 * 1024;
|
||||
let memoryData = this.getCgroupMemoryUsage();
|
||||
|
||||
if (!memoryData) {
|
||||
const processMemory = process.memoryUsage();
|
||||
memoryData = {
|
||||
used: processMemory.rss,
|
||||
limit: this.totalSystemMemory
|
||||
};
|
||||
}
|
||||
|
||||
const memoryUsedMB = memoryData.used / mbFactor;
|
||||
const memoryTotalMB = memoryData.limit / mbFactor;
|
||||
const memoryPercentage = (memoryData.used / memoryData.limit) * 100;
|
||||
|
||||
console.debug(`
|
||||
Memory Usage: ${memoryUsedMB.toFixed(2)} MB
|
||||
Memory Total: ${memoryTotalMB.toFixed(2)} MB
|
||||
Memory %: ${memoryPercentage.toFixed(2)}%
|
||||
`);
|
||||
|
||||
return {
|
||||
memoryUsedMB: memoryUsedMB.toFixed(2),
|
||||
memoryUsedPercentage: memoryPercentage.toFixed(2),
|
||||
cpuUsedPercentage: this.getCgroupCPUUsage().toFixed(2)
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error getting container metrics:", error);
|
||||
throw error;
|
||||
console.error("Error getting metrics:", error);
|
||||
return {
|
||||
memoryUsedMB: "0",
|
||||
memoryUsedPercentage: "0",
|
||||
cpuUsedPercentage: "0"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ export class Watcher extends RoomParticipant {
|
|||
try {
|
||||
this.socket.emit("get-usage");
|
||||
this.socket.once("usage-data", (data) => {
|
||||
//console.log(`Watcher ${this.username} received data:`, data);
|
||||
this.roomRessourcesData.push({ timestamp: Date.now(), ...data });
|
||||
});
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -9,13 +9,13 @@ import generateMetricsReport from './utility/metrics_generator.js';
|
|||
dotenv.config();
|
||||
|
||||
const config = {
|
||||
baseUrl: process.env.BASE_URL || 'http://msevignyl.duckdns.org',
|
||||
baseUrl: process.env.BASE_URL || 'http://localhost',
|
||||
auth: {
|
||||
username: process.env.USER_EMAIL || 'admin@admin.com',
|
||||
password: process.env.USER_PASSWORD || 'admin'
|
||||
},
|
||||
rooms: {
|
||||
count: parseInt(process.env.NUMBER_ROOMS || '5'),
|
||||
count: parseInt(process.env.NUMBER_ROOMS || '2'),
|
||||
usersPerRoom: parseInt(process.env.USERS_PER_ROOM || '60'),
|
||||
batchSize: 5,
|
||||
batchDelay: 250
|
||||
|
|
@ -178,8 +178,6 @@ async function main() {
|
|||
} catch (error) {
|
||||
metrics.logError('main', error);
|
||||
console.error('Error:', error.message);
|
||||
} finally {
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue