PHP 怎么PHP 实时监控

wen PHP项目 2

本文目录导读:

PHP 怎么PHP 实时监控

  1. 方式一:文件/日志变化监控(非实时,最基础)
  2. 方式二:使用 inotify(Linux 原生文件监控)
  3. 方式三:WebSocket 实时推送(推荐用于 Web 应用)
  4. 方式四:Server-Sent Events (SSE) —— 单向实时推送
  5. 方式五:使用现代工具配合(生产推荐)
  6. 各方法对比

在 PHP 中实现“实时监控”通常有两种理解:一种是轮询(定期请求)来模拟实时,另一种是通过长连接技术(如 WebSocket)实现真正的实时推送。

PHP 本身是请求-响应模式的脚本语言,并不原生支持常驻内存或长连接,但可以通过以下 3 种主要方式实现:


文件/日志变化监控(非实时,最基础)

适用于监控日志文件、目录变化等。

<?php
$file = '/var/log/nginx/access.log';
$lastSize = filesize($file);
while (true) {
    clearstatcache();
    $currentSize = filesize($file);
    if ($currentSize > $lastSize) {
        $handle = fopen($file, 'r');
        fseek($handle, $lastSize);
        $newData = fread($handle, $currentSize - $lastSize);
        echo "New log: " . $newData;
        $lastSize = $currentSize;
    }
    sleep(1); // 轮询间隔
}

特点:

  • 简单,但会消耗服务器资源
  • 不是真正的“实时”,取决于轮询间隔

使用 inotify(Linux 原生文件监控)

PHP 扩展 inotify 可以监控文件/目录的增删改事件,真正的事件驱动,不用轮询。

安装:

pecl install inotify

示例代码:

<?php
$fd = inotify_init();
$watch_descriptor = inotify_add_watch($fd, '/path/to/dir', IN_CREATE | IN_MODIFY);
while (true) {
    $events = inotify_read($fd); // 阻塞等待事件
    foreach ($events as $event) {
        echo "File: " . $event['name'] . " - Event: " . $event['mask'] . PHP_EOL;
        // 处理事件...
    }
}
inotify_rm_watch($fd, $watch_descriptor);
fclose($fd);

适用场景:

  • 监控配置文件变更(自动重载)
  • 监控文件上传目录
  • 日志实时分析

⚠️ 注意: 需要 PHP CLI 运行,且 inotify 是阻塞的,不能用于 Web 请求。


WebSocket 实时推送(推荐用于 Web 应用)

此方案才是真正的浏览器实时更新,实时数据看板、聊天、推送通知。

安装 Ratchet(PHP WebSocket 库)

composer require cboden/ratchet

服务端代码(WebSocket Server)

<?php
// server.php
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
require __DIR__ . '/vendor/autoload.php';
class MonitorServer implements MessageComponentInterface {
    protected $clients;
    public function __construct() {
        $this->clients = new \SplObjectStorage;
    }
    public function onOpen(ConnectionInterface $conn) {
        $this->clients->attach($conn);
        echo "New connection: {$conn->resourceId}\n";
    }
    public function onMessage(ConnectionInterface $from, $msg) {
        // 收到客户端消息,可以处理
        foreach ($this->clients as $client) {
            if ($from !== $client) {
                $client->send($msg); // 广播
            }
        }
    }
    public function onClose(ConnectionInterface $conn) {
        $this->clients->detach($conn);
        echo "Connection {$conn->resourceId} disconnected\n";
    }
    public function onError(ConnectionInterface $conn, \Exception $e) {
        echo "Error: {$e->getMessage()}\n";
        $conn->close();
    }
}
// 启动 WebSocket 服务
$server = IoServer::factory(
    new HttpServer(
        new WsServer(
            new MonitorServer()
        )
    ),
    8080 // WebSocket 端口
);
$server->run();

启动服务

php server.php

客户端(浏览器 JavaScript)

// 建立 WebSocket 连接
const ws = new WebSocket('ws://localhost:8080');
ws.onopen = function() {
    console.log('连接成功');
    // 可以发送订阅消息
    ws.send(JSON.stringify({action: 'subscribe', channel: 'monitor'}));
};
ws.onmessage = function(event) {
    const data = JSON.parse(event.data);
    // 实时更新页面
    document.getElementById('realtime-data').innerText = data.value;
};

从 PHP 业务代码推送数据

如果有其他 PHP 脚本需要向 WebSocket 推送数据,可以使用 ZeroMQRedis Pub/Sub

// 从业务控制器推送数据
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->publish('monitor_channel', json_encode(['cpu' => 85, 'memory' => 60]));

然后在 WebSocket 服务端订阅 Redis:

// 在 MonitorServer 中增加 Redis 订阅
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->subscribe(['monitor_channel'], function($redis, $channel, $msg) use ($monitorServer) {
    foreach ($monitorServer->clients as $client) {
        $client->send($msg);
    }
});

Server-Sent Events (SSE) —— 单向实时推送

如果只需要服务器向浏览器推送(不需客户端发消息),SSE 比 WebSocket 更轻量。

PHP 服务端:

<?php
// sse.php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
while (true) {
    $data = ['cpu' => rand(0, 100), 'memory' => rand(0, 100)];
    echo "data: " . json_encode($data) . "\n\n";
    ob_flush();
    flush();
    sleep(2); // 2秒推送一次
}

浏览器接收:

const evtSource = new EventSource('sse.php');
evtSource.onmessage = function(event) {
    const data = JSON.parse(event.data);
    document.getElementById('cpu').innerText = data.cpu + '%';
};

适用场景:

  • 实时看板、监控仪表盘
  • 通知提醒
  • 不需要双向通信的场景

使用现代工具配合(生产推荐)

PHP 不适合长时间运行的任务,生产环境建议:

场景 推荐方案
实时数据看板 SSE + 后端用 Go/Node.js 推数据
日志监控 ELK Stack(Elasticsearch, Logstash, Kibana)
系统指标监控 Prometheus + Grafana
文件变化监控 inotify + 将事件写入 Redis/Queue
高并发推送 Node.js + Socket.IOGo + gorilla/websocket

各方法对比

方式 实时性 实现难度 适用场景 备注
轮询 简单监控 资源浪费
inotify 本地文件监控 Linux 专用
WebSocket 最高 双向通信、聊天、推送 需要常驻服务
SSE 服务器→浏览器推送 单向,简单
外部工具 生产环境 推荐用于大规模

如果你的需求是“监控 PHP 进程/代码变化”,推荐配合 Supervisor + inotify 或使用 Laravel Horizon 等专业工具。

抱歉,评论功能暂时关闭!