PHP项目节点在线状态如何实时检测

wen PHP项目 29

本文目录导读:

PHP项目节点在线状态如何实时检测

  1. 方式一:传统 HTTP 轮询(简单、兼容性好、适合低频)
  2. 方式二:WebSocket(真正的实时)
  3. 方式三:只用 PHP + Swoole (不需 Node.js)
  4. 方式四:SSE(Server-Sent Events,单向推送)

在 PHP 项目中实时检测节点在线状态,常见思路分为两类:传统轮询WebSocket,下面分别介绍这两种方式,以及一种使用 Node.js + Socket.IO 作为实时推送中间件的混合方案(这是目前 PHP 项目中最成熟、最流行的做法)。


传统 HTTP 轮询(简单、兼容性好、适合低频)

原理:前端定时(如 5 秒)发送 Ajax 请求到 PHP 后端,PHP 检查节点最后存活时间。

后端 PHP 代码示例

// 更新节点在线状态(节点主动上报)
function nodeHeartbeat($nodeId) {
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);
    // 将节点ID存入有序集合,score为当前时间戳
    $redis->zAdd('online_nodes', time(), $nodeId);
    // 设置过期时间,清理超时节点(比如30秒无心跳视为离线)
    $redis->expire('online_nodes', 30);
}
// 检查节点是否在线
function isNodeOnline($nodeId) {
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);
    $score = $redis->zScore('online_nodes', $nodeId);
    if ($score === false) return false;
    // 判断是否在超时阈值内(30秒)
    return (time() - $score) <= 30;
}
// 前端轮询接口
function getOnlineNodes() {
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);
    $now = time();
    // 获取30秒内有心跳的节点
    $nodes = $redis->zRangeByScore('online_nodes', $now - 30, $now);
    return json_encode(['online' => $nodes]);
}

缺点

  • 延迟取决于轮询间隔(无法做到真正的实时)。
  • 高频轮询对服务器和数据库压力大。

WebSocket(真正的实时)

PHP 本身不擅长长连接,推荐方案
PHP 负责业务逻辑(节点状态判断) + Node.js/Swoole 作为 WebSocket 服务推送状态变化

架构说明

节点 ——(心跳上报)——> PHP API ——> Redis ——> Node.js WebSocket 服务 ——> 前端浏览器
  • 节点:每隔几秒调用 PHP API 上报在线状态。
  • PHP:更新状态到 Redis,并发布一个 Pub/Sub 消息。
  • Node.js:订阅 Redis 频道,收到消息后通过 WebSocket 推送给所有前端。
  • 前端:监听 WebSocket 消息,实时更新 UI。

关键实现

PHP 端(节点心跳 + 发布消息)

// 节点调用此API
function nodeHeartbeat($nodeId) {
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);
    // 更新在线状态
    $redis->zAdd('online_nodes', time(), $nodeId);
    $redis->expire('online_nodes', 30);
    // 发布状态变化事件到Redis频道
    $redis->publish('node_status_channel', json_encode([
        'nodeId' => $nodeId,
        'status' => 'online',
        'timestamp' => time()
    ]));
}
  • 当节点离线(超时)时,需要额外处理:在 Node.js 端也可以通过定时清理过期节点的逻辑主动发送离线通知。

Node.js 服务(WebSocket 服务端 + Redis 订阅)

const WebSocket = require('ws');
const redis = require('redis');
const wss = new WebSocket.Server({ port: 8080 });
const subscriber = redis.createClient();
// 订阅Redis频道
subscriber.subscribe('node_status_channel');
subscriber.on('message', (channel, message) => {
    // 当收到状态变化消息,广播给所有连接的WebSocket客户端
    wss.clients.forEach(client => {
        if (client.readyState === WebSocket.OPEN) {
            client.send(message);
        }
    });
});

前端监听

const ws = new WebSocket('ws://your-server:8080');
ws.onmessage = function(event) {
    const data = JSON.parse(event.data);
    // 更新UI,
    updateNodeStatus(data.nodeId, data.status);
};

只用 PHP + Swoole (不需 Node.js)

如果希望全部用 PHP 实现,可以使用 Swoole 扩展(PHP 的异步框架)。

Swoole 方案简述

// 一个简单的 WebSocket 服务端
$server = new Swoole\WebSocket\Server("0.0.0.0", 9501);
$table = new Swoole\Table(1024);
$table->column('last_time', Swoole\Table::TYPE_INT);
$table->create();
// 节点上报心跳(通过WebSocket发送消息)
$server->on('message', function ($server, $frame) use ($table) {
    $data = json_decode($frame->data, true);
    if (isset($data['action']) && $data['action'] == 'heartbeat') {
        $table->set($data['node_id'], ['last_time' => time()]);
        // 广播在线状态
        $server->push($frame->fd, json_encode([
            'nodeId' => $data['node_id'],
            'status' => 'online'
        ]));
    }
});
// 定时清理离线节点(略)
$server->start();

稳定性不如 Node.js + Redis,但如果你是纯 PHP 栈且不愿引入 Node.js,可以考虑。


SSE(Server-Sent Events,单向推送)

如果只需要服务端主动推送状态到前端(不需要前端发消息到服务端),SSE 比 WebSocket 更简单:

// PHP 端(需要长连接,配合 Nginx 注意配置)
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
while (true) {
    $onlineNodes = $redis->zRangeByScore('online_nodes', time()-30, time());
    echo "data: " . json_encode($onlineNodes) . "\n\n";
    ob_flush();
    flush();
    sleep(2); // 间隔2秒
}

前端用 EventSource 监听即可。
缺点:连接数多时对 PHP-FPM 进程占用大,不适合大量客户端。


方案 实时性 复杂度 适用场景
轮询 简单页面,节点数量少
WebSocket + Node.js + Redis 企业级推荐
Swoole WebSocket 纯 PHP 团队
SSE 只需服务端推送

推荐:如果你的 PHP 项目是基于 Laravel/Symfony 等主流框架,且对实时性要求高,搭配一个 Node.js 或 Go 的小服务做 WebSocket 推送是目前业界最成熟的模式。

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