You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取单个Laravel应用实例的RAM与CPU资源占用情况

问题

我需要获取指定Laravel应用的RAM、CPU资源占用数据,但当前编写的代码仅能展示整个服务器系统的整体资源使用情况,无法定位到单个应用的资源消耗。
需要实现仅统计单个Laravel应用的RAM/CPU资源占用,效果类似Windows任务管理器按程序展示CPU/RAM占用的逻辑,面向Web应用场景,优先Laravel原生方案,通用原生PHP实现方案也可参考。
当前已编写的实现代码如下:

现有实现代码

路由文件 web.php

...
Route::get('/details', function () {
    //RAM usage
    $free = shell_exec('free'); 
    $free = (string) trim($free);
    $free_arr = explode("\n", $free);
    $mem = explode(" ", $free_arr[1]);
    $mem = array_filter($mem);
    $mem = array_merge($mem);
    $usedmem = $mem[2];
    $usedmemInGB = number_format($usedmem / 1048576, 2) . ' GB';
    $memory1 = $mem[2] / $mem[1] * 100;
    $memory = round($memory1) . '%';
    $fh = fopen('/proc/meminfo', 'r');
    $mem = 0;
    while ($line = fgets($fh)) {
        $pieces = array();
        if (preg_match('/^MemTotal:\s+(\d+)\skB$/', $line, $pieces)) {
            $mem = $pieces[1];
            break;
        }
    }
    fclose($fh);
    $totalram = number_format($mem / 1048576, 2) . ' GB';
    
    //cpu usage
    $cpu_load = sys_getloadavg(); 
    $load = $cpu_load[0] . '% / 100%';
    
    return view('details',compact('memory','totalram','usedmemInGB','load'));
});
...

视图文件 details.blade.php

<html>
<head>
  <link href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
  <div class="col-sm-6 col-md-3">
    <h2 class="no-margin text-semibold">Current RAM Usage</h2>
    <div class="progress progress-micro mb-10">
      <div class="progress-bar bg-indigo-400" style="width: {{$memory}}">
        <span class="sr-only">{{$memory}}</span>
      </div>
    </div>
    <span class="pull-right">{{$usedmemInGB}} / {{$totalram}} ({{$memory}})</span>  

  </div>

  <div class="col-sm-6 col-md-3">
    <h2 class="no-margin text-semibold">Current CPU Usage</h2>
    <div class="progress progress-micro mb-10">
      <div class="progress-bar bg-indigo-400" style="width: {{$load}}">
        <span class="sr-only">{{$load}}</span>
      </div>
    </div>
    <span class="pull-right">{{$load}}</span>   
  </div>

</body>
</html>

解决方案

Laravel没有内置直接统计单应用资源占用的API,本质上单个Web应用的资源占用,是所有归属该应用的PHP进程(FPM工作进程、CLI队列/定时任务进程)的资源总和,用原生PHP读取Linux系统/proc目录下的进程数据就能实现,不需要安装额外扩展。
首先要修正原有代码的逻辑错误:sys_getloadavg()返回的是系统1/5/15分钟的平均负载,不是实时CPU占用率,计算逻辑本身不成立。

实现逻辑

  • 确定应用进程匹配规则:优先匹配PHP-FPM专属进程池(推荐给每个Laravel应用单独配置FPM池,识别准确率最高),也可以通过进程命令行是否包含当前应用根路径匹配,覆盖FPM+CLI所有进程
  • 读取系统总内存、CPU核心数,用于后续占比换算
  • 遍历系统所有运行中的进程,筛选出属于当前应用的进程,累加每个进程的物理内存占用(VmRSS值,即实际占用的物理内存,不含交换分区)
  • 间隔100ms两次读取目标进程的CPU时间片,计算实时CPU占用率,避免平均负载的延迟问题

可直接复用的代码

资源统计方法

可以把这个方法放到路由文件、控制器公共文件或者自定义辅助函数里:

function getAppResourceUsage(string $appIdentify, bool $matchFpmPool = false): array
{
    $totalMemoryKb = 0;
    $totalCpuTickDiff = 0;
    $processCount = 0;

    // 获取系统总内存
    $totalMemKb = 0;
    if (is_file('/proc/meminfo')) {
        foreach (file('/proc/meminfo') as $line) {
            if (str_starts_with(trim($line), 'MemTotal:')) {
                preg_match('/(\d+)\skB/', $line, $match);
                $totalMemKb = (int)$match[1];
                break;
            }
        }
    }

    // 获取CPU核心数
    $cpuCores = 1;
    if (is_file('/proc/cpuinfo')) {
        $cpuCores = count(array_filter(
            file('/proc/cpuinfo'),
            fn($line) => str_starts_with(trim($line), 'processor')
        ));
    }

    // 第一次遍历进程,匹配目标进程、记录内存和第一次CPU时间
    $pidCpuTickMap = [];
    foreach (glob('/proc/[0-9]*') as $procPath) {
        $pid = basename($procPath);
        // 跳过无效进程目录
        if (!is_file("$procPath/cmdline") || !is_file("$procPath/stat") || !is_file("$procPath/status")) {
            continue;
        }

        // 读取进程命令行做匹配
        $cmdline = str_replace("\0", ' ', trim(file_get_contents("$procPath/cmdline")));
        $isMatch = $matchFpmPool
            ? str_contains($cmdline, "php-fpm: pool $appIdentify")
            : (str_contains($cmdline, 'php') && str_contains($cmdline, $appIdentify));
        if (!$isMatch) {
            continue;
        }

        $processCount++;
        // 累加物理内存占用
        foreach (file("$procPath/status") as $statusLine) {
            if (str_starts_with(trim($statusLine), 'VmRSS:')) {
                preg_match('/(\d+)\skB/', $statusLine, $memMatch);
                $totalMemoryKb += (int)$memMatch[1];
                break;
            }
        }

        // 记录第一次CPU时间(用户态+内核态)
        $statArr = explode(' ', trim(file_get_contents("$procPath/stat")));
        $pidCpuTickMap[$pid] = (int)$statArr[13] + (int)$statArr[14];
    }

    // 间隔100ms取第二次CPU快照
    usleep(100000);
    // Linux默认时钟频率为100Hz,即每10ms一个时钟滴答,100ms对应10个滴答
    $intervalTick = 10;
    foreach ($pidCpuTickMap as $pid => $firstTick) {
        $procStatPath = "/proc/$pid/stat";
        if (!is_file($procStatPath)) {
            continue;
        }
        $statArr = explode(' ', trim(file_get_contents($procStatPath)));
        $secondTick = (int)$statArr[13] + (int)$statArr[14];
        $totalCpuTickDiff += $secondTick - $firstTick;
    }

    // 换算成百分比
    $cpuPercent = round(($totalCpuTickDiff / $intervalTick / $cpuCores) * 100, 2);
    $memPercent = $totalMemKb ? round($totalMemoryKb / $totalMemKb * 100, 2) : 0;

    return [
        'process_count' => $processCount,
        'memory_percent' => $memPercent . '%',
        'memory_used' => number_format($totalMemoryKb / 1024 / 1024, 2) . ' GB',
        'memory_total' => number_format($totalMemKb / 1024 / 1024, 2) . ' GB',
        'cpu_percent' => min($cpuPercent, 100) . '%'
    ];
}

替换原有路由逻辑

Route::get('/details', function () {
    // 用应用根路径做匹配标识,自动覆盖FPM+CLI进程
    // 如果配置了专属FPM池,第二个参数传true,第一个参数传FPM池名即可
    $resource = getAppResourceUsage(base_path());
    return view('details', [
        'memory' => $resource['memory_percent'],
        'usedmemInGB' => $resource['memory_used'],
        'totalram' => $resource['memory_total'],
        'load' => $resource['cpu_percent']
    ]);
});

视图文件不需要做任何修改,就能直接展示单应用的资源占用数据。

注意事项

  • 以上代码仅支持Linux环境,Windows环境需要改用tasklist命令做进程匹配
  • 读取/proc目录需要PHP进程有对应目录的读取权限,如果开启了open_basedir限制需要先放开
  • 两次CPU快照的间隔建议控制在100-200ms,太长会拖慢页面响应速度,太短会导致计算误差大
  • 用FPM池匹配的准确率高于路径匹配,可以避免统计到其他同名路径下的PHP进程
  • 统计结果会自动包含当前应用下运行的队列进程、定时任务进程,不需要额外配置

内容的提问来源于stack exchange,提问作者DistantDigit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 01:36:27