0

0

纯PHP实现系统与PHP进程监控:深入探索/proc文件系统

心靈之曲

心靈之曲

发布时间:2025-12-09 12:39:59

|

741人浏览过

|

来源于php中文网

原创

纯PHP实现系统与PHP进程监控:深入探索/proc文件系统

本文将深入探讨如何利用纯php语言,在不依赖外部shell命令的情况下,监控linux系统资源和php进程的详细信息。我们将重点介绍如何通过php的文件系统函数直接读取和解析`/proc`虚拟文件系统,从而获取系统负载、内存使用、活跃php进程数量及其资源消耗等全局数据,为系统管理员提供强大的php内建监控能力。

引言:纯PHP监控的挑战与机遇

在系统管理和性能优化中,实时了解服务器的运行状态和应用程序的资源消耗至关重要。对于PHP应用程序而言,除了单个脚本自身的内存使用(如通过memory_get_usage()获取)和系统整体负载(如通过sys_getloadavg()获取)外,我们常常需要获取更全面的信息,例如当前所有活跃的PHP进程总数、它们占用的全局内存总量、由哪些用户运行、以及是否存在长时间运行的PHP进程等。

传统的做法可能涉及执行Shell命令(如ps aux | grep php、free -h等),但这在某些安全受限或追求纯PHP解决方案的环境中并不理想。幸运的是,在Linux系统上,PHP可以通过其标准的文件系统函数,直接访问一个名为/proc的特殊虚拟文件系统,从而获取这些详尽的系统和进程信息。

/proc文件系统:Linux上的信息宝库

/proc文件系统是一个独特且强大的虚拟文件系统,它不存储在磁盘上,而是由Linux内核在内存中动态生成。它提供了对内核数据结构、系统配置和当前运行进程的实时视图。每个正在运行的进程都会在/proc目录下创建一个以其PID(进程ID)命名的子目录,例如/proc/1234。这些进程目录中包含了大量关于该进程的信息文件,如进程状态、命令行参数、内存映射等。

PHP与/proc文件系统的交互方式与读取普通文件无异。我们可以使用file_get_contents()读取文件内容,使用scandir()遍历目录,从而以纯PHP代码的方式获取这些系统级和进程级的数据。

立即学习PHP免费学习笔记(深入)”;

获取系统级信息

通过/proc文件系统,我们可以轻松获取系统整体的资源使用情况。

1. 系统负载

PHP内置的sys_getloadavg()函数实际上就是对/proc/loadavg文件的封装。该文件包含三个浮点数,分别表示过去1分钟、5分钟和15分钟的平均系统负载。

Yodayo
Yodayo

一个专为动漫迷和vTuber打造的AI艺术创作平台、交流社区

下载

示例:直接读取/proc/loadavg

<?php
function getSystemLoadAvg() {
    if (file_exists('/proc/loadavg')) {
        $loadavg_content = file_get_contents('/proc/loadavg');
        $parts = explode(' ', $loadavg_content);
        return [
            '1_min' => (float)$parts[0],
            '5_min' => (float)$parts[1],
            '15_min' => (float)$parts[2]
        ];
    }
    return null;
}

// $load = getSystemLoadAvg();
// if ($load) {
//     echo "System Load (1/5/15 min): {$load['1_min']} / {$load['5_min']} / {$load['15_min']}\n";
// }
?>

2. 全局内存使用

/proc/meminfo文件提供了系统内存的详细统计信息,包括总内存、可用内存、空闲内存、缓存、缓冲区等。

示例:读取/proc/meminfo

<?php
function getSystemMemoryInfo() {
    $memoryInfo = [];
    if (file_exists('/proc/meminfo')) {
        $meminfo_content = file_get_contents('/proc/meminfo');
        $lines = explode("\n", $meminfo_content);
        foreach ($lines as $line) {
            if (preg_match('/^(\w+):\s*(\d+)\s*kB$/', $line, $matches)) {
                $key = strtolower($matches[1]);
                $memoryInfo[$key] = (int)$matches[2]; // Value in KB
            }
        }
    }
    return $memoryInfo;
}

// $mem = getSystemMemoryInfo();
// if ($mem) {
//     echo "Total Memory: " . round($mem['memtotal'] / 1024 / 1024, 2) . " GB\n";
//     echo "Available Memory: " . round($mem['memavailable'] / 1024 / 1024, 2) . " GB\n";
// }
?>

监控PHP进程详情

获取单个PHP进程的详细信息是实现全局PHP环境监控的关键。

1. 进程目录结构与关键文件

每个进程在/proc下都有一个以其PID命名的目录,例如/proc/1234。在这个目录中,有几个文件对我们特别有用:

  • /proc/[PID]/status:包含进程的名称、状态、UID、GID以及各种内存使用统计(如VmRSS物理内存、VmSize虚拟内存等)。
  • /proc/[PID]/cmdline:包含进程启动时使用的完整命令行参数。这是识别PHP进程最直接的方式。
  • /proc/[PID]/stat:包含更底层的进程统计信息,包括进程的启动时间(以Jiffies为单位)。

2. 实现步骤

  1. 遍历PID目录: 使用scandir('/proc')获取所有目录和文件,然后过滤出纯数字命名的目录,这些就是进程PID。
  2. 识别PHP进程: 对于每个PID,读取/proc/[PID]/cmdline文件的内容。通过检查命令行参数是否包含“php”、“php-fpm”或“php-cgi”等关键字来判断它是否为一个PHP进程。
  3. 提取进程信息: 如果是PHP进程,读取/proc/[PID]/status文件,解析出进程名称、实际物理内存占用(VmRSS)、用户ID(Uid)等。
  4. 计算运行时长: 读取/proc/[PID]/stat文件,获取进程的启动时间(starttime字段),结合系统启动时间(从/proc/stat的btime字段获取)和系统时钟频率(通常为100 Jiffies/秒),可以计算出进程已运行的秒数。
  5. 汇总数据: 统计PHP进程总数、不同用户运行的进程数、总内存占用以及长时间运行的进程数。

示例代码:获取PHP进程概览

以下是一个完整的PHP函数,用于收集并汇总当前系统上所有PHP进程的关键信息:

<?php
/**
 * 获取当前系统上所有PHP进程的概览信息。
 * 仅适用于Linux系统,依赖于/proc文件系统。
 *
 * @return array 包含PHP进程总数、用户数、长时间运行进程数、总内存占用等信息的数组,
 *               或在出错时返回包含'error'键的数组。
 */
function getPhpProcessOverview() {
    $phpProcesses = [];
    $totalPhpMemoryKb = 0; // 所有PHP进程的VmRSS总和,单位KB
    $usersRunningPhp = []; // 存储运行PHP进程的用户UID
    $longRunningProcessesCount = 0; // 运行时间超过5分钟的PHP进程数量

    // 检查/proc文件系统是否存在,此功能为Linux特有
    if (!is_dir('/proc')) {
        return ['error' => '`/proc` filesystem not found. This feature is Linux-specific.'];
    }

    // 获取所有PID目录
    $pids = array_filter(scandir('/proc'), 'is_numeric');

    // 获取系统启动时间 (btime) 和时钟频率 (_SC_CLK_TCK)
    $systemBootTime = 0;
    $clockTicks = 100; // 常见的_SC_CLK_TCK值,通常为100 jiffies/秒
    if (file_exists('/proc/stat')) {
        $statFileContent = file_get_contents('/proc/stat');
        if (preg_match('/^btime\s*(\d+)/m', $statFileContent, $btimeMatches)) {
            $systemBootTime = (int)$btimeMatches[1];
        }
    }

    foreach ($pids as $pid) {
        $cmdlinePath = "/proc/{$pid}/cmdline";
        $statusPath = "/proc/{$pid}/status";
        $statPath = "/proc/{$pid}/stat";

        // 确保文件存在且可读
        if (file_exists($cmdlinePath) && file_exists($statusPath) && file_exists($statPath)) {
            $cmdline = file_get_contents($cmdlinePath);
            // cmdline内容通常以null字节分隔,替换为空格以便解析
            $cmdline = str_replace("\0", " ", $cmdline);

            // 通过命令行判断是否为PHP进程 (php, php-fpm, php-cgi等)
            if (preg_match('/php(?:-fpm|-cgi)?/i', $cmdline)) {
                $statusContent = file_get_contents($statusPath);
                $statContent = file_get_contents($statPath);

                $processInfo = [
                    'pid' => (int)$pid,
                    'name' => '',
                    'memory_rss_kb' => 0, // Resident Set Size (物理内存占用)
                    'uid' => '',
                    'uptime_seconds' => 0,
                    'cmdline' => trim($cmdline)
                ];

                // 解析status文件获取进程名、VmRSS和UID
                if (preg_match('/^Name:\s*(.*)$/m', $statusContent, $matches)) {
                    $processInfo['name'] = trim($matches[1]);
                }
                if (preg_match('/^VmRSS:\s*(\d+)\s*kB$/m', $statusContent, $matches)) {
                    $processInfo['memory_rss_kb'] = (int)$matches[1];
                    $totalPhpMemoryKb += (int)$matches[1];
                }
                if (preg_match('/^Uid:\s*(\d+)/m', $statusContent, $matches)) {
                    $processInfo['uid'] = $matches[1];
                    $usersRunningPhp[$matches[1]] = true; // 记录运行进程的用户
                }

                // 解析stat文件获取进程启动时间并计算运行时长
                // /proc/[PID]/stat 的第22个字段 (0-indexed 21) 是进程启动时间 (starttime)
                $statFields = explode(' ', $statContent);
                if (isset($statFields[21]) && $systemBootTime > 0) {
                    $startTimeJiffies = (int)$statFields[21];
                    // 进程启动时间(秒) = 系统启动时间(秒) + 进程启动时钟节拍 / 每秒时钟节拍
                    $processStartTimeSeconds = $systemBootTime + ($startTimeJiffies / $clockTicks);
                    $processUptimeSeconds = time() - $processStartTimeSeconds;
                    $processInfo['uptime_seconds'] = max(0, round($processUptimeSeconds));

                    // 判断是否为长时间运行进程 (例如,超过5分钟)
                    if ($processInfo['uptime_seconds'] > (5 * 60)) {
                        $longRunningProcessesCount++;
                    }
                }

                $phpProcesses[] = $processInfo;
            }
        }
    }

    return [
        'total_scripts_running' => count($phpProcesses),
        'users_running_process' => count($usersRunningPhp),
        'process_with_more_than_5_minutes' => $longRunningProcessesCount,
        'memory_global_assigned_to_all_php_kb' => $totalPhpMemoryKb,
        'details' => $phpProcesses // 包含每个PHP进程的详细信息
    ];
}

// 示例用法:
$overview = getPhpProcessOverview();

if (isset($overview['error'])) {
    echo "Error: " . $overview['error'] . "\n";
} else {
    echo "--- PHP 进程概览 ---\n";
    echo "总计运行中的PHP进程数: " . $overview['total_scripts_running'] . "\n";
    echo "运行PHP进程的用户数: " . $overview['users_running_process'] . "\n";
    echo "运行时间超过5分钟的PHP进程数: " . $overview['process_with_more_than_5_minutes'] . "\n";
    echo "所有PHP进程占用的总物理内存 (RSS): " . round($overview['memory_global_assigned_to_all_php_kb'] / 1024, 2) . " MB\n";
    echo "\n--- 

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
treenode的用法
treenode的用法

​在计算机编程领域,TreeNode是一种常见的数据结构,通常用于构建树形结构。在不同的编程语言中,TreeNode可能有不同的实现方式和用法,通常用于表示树的节点信息。更多关于treenode相关问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

549

2023.12.01

C++ 高效算法与数据结构
C++ 高效算法与数据结构

本专题讲解 C++ 中常用算法与数据结构的实现与优化,涵盖排序算法(快速排序、归并排序)、查找算法、图算法、动态规划、贪心算法等,并结合实际案例分析如何选择最优算法来提高程序效率。通过深入理解数据结构(链表、树、堆、哈希表等),帮助开发者提升 在复杂应用中的算法设计与性能优化能力。

30

2025.12.22

深入理解算法:高效算法与数据结构专题
深入理解算法:高效算法与数据结构专题

本专题专注于算法与数据结构的核心概念,适合想深入理解并提升编程能力的开发者。专题内容包括常见数据结构的实现与应用,如数组、链表、栈、队列、哈希表、树、图等;以及高效的排序算法、搜索算法、动态规划等经典算法。通过详细的讲解与复杂度分析,帮助开发者不仅能熟练运用这些基础知识,还能在实际编程中优化性能,提高代码的执行效率。本专题适合准备面试的开发者,也适合希望提高算法思维的编程爱好者。

44

2026.01.06

磁盘配额是什么
磁盘配额是什么

磁盘配额是计算机中指定磁盘的储存限制,就是管理员可以为用户所能使用的磁盘空间进行配额限制,每一用户只能使用最大配额范围内的磁盘空间。php中文网为大家提供各种磁盘配额相关的内容,教程,供大家免费下载安装。

1564

2023.06.21

如何安装LINUX
如何安装LINUX

本站专题提供如何安装LINUX的相关教程文章,还有相关的下载、课程,大家可以免费体验。

716

2023.06.29

linux find
linux find

find是linux命令,它将档案系统内符合 expression 的档案列出来。可以指要档案的名称、类别、时间、大小、权限等不同资讯的组合,只有完全相符的才会被列出来。find根据下列规则判断 path 和 expression,在命令列上第一个 - ( ) , ! 之前的部分为 path,之后的是 expression。还有指DOS 命令 find,Excel 函数 find等。本站专题提供linux find相关教程文章,还有相关

300

2023.06.30

linux修改文件名
linux修改文件名

本专题为大家提供linux修改文件名相关的文章,这些文章可以帮助用户快速轻松地完成文件名的修改工作,大家可以免费体验。

800

2023.07.05

linux系统安装教程
linux系统安装教程

linux系统是一种可以免费使用,自由传播,多用户、多任务、多线程、多CPU的操作系统。本专题提供linux系统安装教程相关的文章,大家可以免费体验。

588

2023.07.06

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

76

2026.03.11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PHP课程
PHP课程

共137课时 | 13.4万人学习

JavaScript ES5基础线上课程教学
JavaScript ES5基础线上课程教学

共6课时 | 11.3万人学习

PHP新手语法线上课程教学
PHP新手语法线上课程教学

共13课时 | 1.0万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号