如何用Node.js实现Redhat CGroup资源统计文件的等效功能
CGroup资源数据说明与Node.js跨平台实现
各CGroup文件的作用
/sys/fs/cgroup/cpu/cpuacct.usage:累计该CGroup下所有进程消耗的CPU总时间,单位为纳秒/sys/fs/cgroup/cpu/cpu.cfs_quota_us:CGroup的CPU配额,单位为微秒,值为-1表示无CPU限制/sys/fs/cgroup/cpu/cpu.cfs_period_us:CPU调度周期,单位为微秒,默认值通常为100000(即100ms)/sys/fs/cgroup/memory/memory.usage_in_bytes:CGroup当前占用的内存总量,单位为字节/sys/fs/cgroup/memory/memory.soft_limit_in_bytes:内存软限制,单位为字节;超过该值时系统会尝试回收内存,但不会直接终止进程/sys/fs/cgroup/memory/memory.limit_in_bytes:内存硬限制,单位为字节;超过该值时进程会被OOM Killer终止/sys/fs/cgroup/memory/memory.stat:内存细分统计文件,其中total_rss是进程实际使用的物理内存,total_cache是页缓存占用的内存大小
Node.js跨平台实现方案
CGroup是Linux专属特性,非Linux系统(Windows/macOS)需要通过系统原生命令或Node.js内置模块获取对应数据,以下实现兼容Linux与非Linux环境,并保证输出格式与原命令完全一致:
const fs = require('fs').promises; const os = require('os'); const path = require('path'); async function getResourceData() { if (os.platform() !== 'linux') { // 非Linux环境:通过系统API模拟对应格式输出 const cpuUsage = BigInt(os.uptime() * 1e9).toString(); const cpuQuota = '-1'; const cpuPeriod = '100000'; const memUsage = os.freemem().toString(); const memSoftLimit = os.totalmem().toString(); const memHardLimit = os.totalmem().toString(); const totalRss = Math.floor(os.freemem() * 0.6).toString(); const totalCache = Math.floor(os.totalmem() - os.freemem()).toString(); return `${cpuUsage}\n${cpuQuota}\n${cpuPeriod}\n${memUsage}\n${memSoftLimit}\n${memHardLimit}\ntotal_rss ${totalRss}\ntotal_cache ${totalCache}`; } // Linux环境:直接读取CGroup文件 const cpuFilePaths = [ '/sys/fs/cgroup/cpu/cpuacct.usage', '/sys/fs/cgroup/cpu/cpu.cfs_quota_us', '/sys/fs/cgroup/cpu/cpu.cfs_period_us' ]; const memFilePaths = [ '/sys/fs/cgroup/memory/memory.usage_in_bytes', '/sys/fs/cgroup/memory/memory.soft_limit_in_bytes', '/sys/fs/cgroup/memory/memory.limit_in_bytes' ]; let output = ''; // 读取CPU相关文件 for (const filePath of cpuFilePaths) { try { const content = await fs.readFile(filePath, 'utf8'); output += content.trim() + '\n'; } catch (err) { // 文件不存在时返回默认值(如宿主机无CGroup限制场景) output += filePath.includes('quota') ? '-1\n' : '0\n'; } } // 读取内存相关文件 for (const filePath of memFilePaths) { try { const content = await fs.readFile(filePath, 'utf8'); output += content.trim() + '\n'; } catch (err) { // 无限制时返回系统总内存 output += os.totalmem().toString() + '\n'; } } // 读取并过滤memory.stat的目标字段 try { const statContent = await fs.readFile('/sys/fs/cgroup/memory/memory.stat', 'utf8'); const targetLines = statContent.split('\n').filter(line => line.startsWith('total_rss ') || line.startsWith('total_cache ') ); output += targetLines.join('\n'); } catch (err) { // 降级使用系统内存数据模拟 output += `total_rss ${os.freemem()}\ntotal_cache ${os.totalmem() - os.freemem()}`; } return output.trim(); } // 调用示例 getResourceData() .then(data => console.log(data)) .catch(err => console.error('获取资源数据失败:', err));
注意事项
- 容器环境适配:Docker等容器的CGroup路径可能不同,可通过读取
/proc/self/cgroup文件获取当前进程所属CGroup路径,动态拼接文件路径 - 权限问题:确保Node.js进程拥有读取
/sys/fs/cgroup下文件的权限 - 非Linux优化:可根据实际需求替换非Linux环境的模拟逻辑,比如Windows用
wmic命令、macOS用ps命令获取更精准的CPU/内存数据
内容的提问来源于stack exchange,提问作者LuisAFK
相关产品推荐
相关产品推荐

