通过http实时远程监控/控制服务器的正确方法

时间:2015-03-05 10:17:44

标签: javascript php ajax node.js

在我的客户端(带浏览器的手机)上我想查看服务器CPU,RAM和放大器的统计信息。硬盘和从各种日志中收集信息。

我正在使用ajax民意调查。

在客户端每5秒(setInterval)我调用一个PHP文件:

  1. 扫描包含N个日志的文件夹

  2. 阅读每个日志的最后一行

  3. 将其转换为JSON

  4. 问题:

    1. 每5秒打开一次新连接。
    2. 多个AJAX调用。
    3. 请求标头(它们也是数据,因此消耗带宽
    4. 响应标头(^)
    5. 使用PHP每5秒读取一次文件。即使没有任何改变。
    6. 最终的JSON数据小于5 KB,但我每5秒发送一次,每次都有标题和新连接,所以基本上每5秒,我必须发送5-10 KB才能获得5 KB为10-20 KB。

      如果我让应用程序处于打开状态,那么每分钟60 sec / 5 sec = 12个新连接数和每小时约15 MB流量。

      假设我有100个用户,我可以监控/控制我的服务器,在一小时内传输流量约为1.5 GB。

      更不用说PHP服务器每5秒读取多个文件100次。

      我需要服务器上的内容每隔5秒读取一次这些日志的最后几行并将它们写入文件,然后我想将这些数据推送到客户端,只要它被更改。


      使用PHP的SSE(服务器发送事件)

      header('Content-Type: text/event-stream');
      header('Cache-Control: no-cache');
      while(true){
       echo "id: ".time()."\ndata: ".ReadTheLogs()."\n\n";
       ob_flush();
       flush();
       sleep(1);
      }
      

      在这种情况下,与第一个用户建立连接后 连接保持打开(PHP不是为此而建),因此我节省了一些空间(请求标头,响应标头)。大多数服务器在我的服务器上的这项工作不允许长时间保持连接打开。

      对于多个用户,我多次读取日志。(减慢旧服务器的速度) 我无法控制服务器...我需要使用ajax发送命令......

        

      我需要WebSockets !!!


      node.js 和websockets

      使用node.js,据我所知,我可以做到这一切而不消耗很多 资源和bandwich。连接保持打开,所以没有不必要的标题,我可以接收和发送data.it很好地处理多个用户。

      这就是我需要你帮助的地方。

      1. node.js服务器应该在后台更新,并且如果文件被修改,则每5秒存储一次日志数据。应该用(iwatch,dnotify ...)操作系统

      2. 只有在更改后才能推送数据。

      3. 日志的读取应该在5秒后才发生一次...所以不是每个用户都会触发。


      4. 这是我发现的第一个例子......并且修改过......

        var ws=require("nodejs-websocket");
        var server=ws.createServer(function(conn){
        
            var data=read(whereToStoreTheLogs);
            conn.sendText(data)// send the logs data to the user 
            //on first connection.
        
            setTimeout(checkLogs,5000);
            /*
             here i need to continuosly check if the logs are changed.
             but if i use setInterval(checkLogs,5000) or setTimeout
             every user invokes a new timer and so having lots of timers on the server
             can i do that in background?         
            */
            conn.on("text",function(str){
             doStuff(str); // various commands to control the server.
            })
            conn.on("close",function(code,reason){
             console.log("Connection closed")
            })
        }).listen(8001);
        
        var checkLogs=function(){
         var data=read(whereToStoreTheLogs);
         if(data!=oldData){
          conn.sendText(data)
         }
         setTimeout(checkLogs,5000);
        }
        

        上面的脚本将是通知服务器,但我还需要找到一个解决方案来存储多个日志的信息,并在每次更改内容时在后台执行。

        如何保持bandwich低,还有服务器资源。

        你会怎么做?

        修改 顺便说一句。有没有办法流式这个数据同时到所有的clinets?

        编辑

        关于日志:我还希望能够缩放更新之间的时间扩展......我的意思是,如果我读取ffmpeg的日志,如果可能的话每秒都会更新...但是当没有转换处于活动状态时。我需要每5分钟获得一次基本的机器信息......等等......

        目标: 1.高效的阅读方式将日志数据存储在某处(仅当连接clinets时... [mysql,文件,它可以在ram中存储此信息(使用node.js ??)])。 2.将数据流式传输到各种客户端的高效方式(同时)。 3.能够向服务器发送命令..(双向) 4.使用网络语言(js,php ...),lunix命令(在多台机器上易于实现的东西)..如果需要,可以使用免费软件。

        最好的方法是:

        根据当前活动,将系统内存流同时连续读取,已经打开连接各种客户 webSockets

        我不知道任何可能更快的事情。

        更新

        node.js 服务器已启动并正在运行,使用http://einaros.github.io/ws/ webSocketServer 实施,因为它似乎是最快的服务器。 我在@HeadCode的帮助下编写了以下代码来正确处理客户端情况&保持过程尽可能低。检查广播循环内的各种事物。现在推动&客户处理是个好点。

        var 
        wss=new (require('ws').Server)({port:8080}),
        isBusy,
        logs,
        clients,
        i,
        checkLogs=function(){
         if(wss.clients&&(clients=wss.clients.length)){
          isBusy||(logs=readLogs()/*,isBusy=true*/);
          if(logs){
           i=0;
           while(i<clients){
            wss.clients[i++].send(logs)
           }
          }
         } 
        };
        setInterval(checkLogs,2000);
        

        但是我现在使用一种非常糟糕的方式来解析日志..(nodejs-&gt; httpRequest-&gt; php)..大声笑。经过一些谷歌搜索后,我发现我完全可以直接将linux软件的输出流式传输到nodejs应用程序......我没有检查过......但也许这是最好的方法。 node.js还有一个文件系统api,可以读取日志。 linux拥有它自己的文件系统api。

        readLogs()(可以是异步)功能仍然是我不满意的。

        1. nodejs filesystem?
        2. linuxSoftware-&gt; nodejs输出实现
        3. linux filesystem api。
        4. 请记住,我需要扫描各种文件夹中的日志,然后以某种方式解析输出的数据,这每2秒钟一次。

          ps。:如果logReading系统是异步的,我adde对服务器变量是忙碌的。

          修改

          答案尚未完成。

          缺失:

          1. 一种高效的读取,解析和存储日志的方法(linux filesystem api或nodejs api,所以我直接存储到系统内存中)
          2. 解释是否可以将数据直接传输给多个用户。 显然,nodejs通过客户端循环,所以(我认为)发送多次数据。
          3. 如果没有客户端并且在apache端的新连接上重新启动,那么关闭节点服务器是否可能/值得。 (例如:如果我连接到apache托管的html文件,脚本会再次启动nodejs服务器)。这样做会进一步减少内存泄漏???对吗?

            修改

            在尝试使用websockets(一些视频在评论中)后,我学到了一些新东西。 Raspberry PI有可能使用一些CPU DMA通道来处理像PWM这样的高频事件...我需要以某种方式理解它是如何工作的。

            当使用传感器和类似的东西时,我应该将所有内容存储在RAM中,nodejs已经这样做了? (在脚本内的变量中)

            websocket仍然是最佳选择,因为它现在可以从任何设备轻松访问,只需使用浏览器即可。

6 个答案:

答案 0 :(得分:1)

我没有使用nodejs-websocket,但看起来它会接受http连接并进行升级以及创建服务器。如果您关心接收的是text / json,那么我认为这样会很好,但在我看来,您可能希望与它一起提供网页。

这是一种使用express和socket.io来实现您所要求的方法:

var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);

app.use(express.static(__dirname + '/'));
app.get('/', function(req, res){
    res.sendfile('index.html');
});

io.on('connection', function(socket){

    // This is where we should emit the cached values of everything
    // that has been collected so far so this user doesn't have to
    // wait for a changed value on the monitored host to see
    // what is going on.
    // This code is based on something I wrote for myself so it's not
    // going to do anything for you as is.  You'll have to implement
    // your own caching mechanism.
    for (var stat in cache) {
        if (cache.hasOwnProperty(stat)) {
            socket.emit('data', JSON.stringify(cache[stat]));
        }
    }
});

http.listen(3000, function(){
    console.log('listening on *:3000');
});

(function checkLogs(){
    var data=read(whereToStoreTheLogs);
    if(data!=oldData){
        io.emit(data)
    }
    setTimeout(checkLogs,5000);
})();

当然,checkLogs功能必须由您充实。我只是在这里剪切并粘贴它以供上下文使用。调用io对象的emit函数会将消息发送给所有连接的用户,但checkLogs函数只会触发一次(然后继续调用),而不是每次有人连接时。

在index.html页面中,您可以拥有类似的内容。它应该包含在底部的html页面中,就在关闭正文标记之前。

<script src="/path/to/socket.io.js"></script>
<script>

    // Set up the websocket for receiving updates from the server
    var socket = io();

    socket.on('data', function(msg){
        // Do something with your message here, such as using javascript
        // to display it in an appropriate spot on the page.
        document.getElementById("content").innerHTML = msg;
    });

</script>

顺便说一下,查看Nodejs文档,了解各种用于检查系统资源的内置方法(https://nodejs.org/api/os.html)。

这里也是一个更符合你想要的解决方案。将此用于您的html页面:

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>WS example</title>
</head>
<body>
<script>
var connection;
window.addEventListener("load", function () {
    connection = new WebSocket("ws://"+window.location.hostname+":8001")
    connection.onopen = function () {
        console.log("Connection opened")
    }
    connection.onclose = function () {
        console.log("Connection closed")
    }
    connection.onerror = function () {
        console.error("Connection error")
    }
    connection.onmessage = function (event) {
        var div = document.createElement("div")
        div.textContent = event.data
        document.body.appendChild(div)
    }
});
</script>
</body>
</html>

并将其用作您的Web套接字服务器代码,最近调整为使用'tail'模块(如本文中所示:How to do `tail -f logfile.txt`-like processing in node.js?),您必须使用npm进行安装(注意:tail使用fs.watch,但无法保证在任何地方都能正常工作):

var ws = require("nodejs-websocket")
var os = require('os');
Tail = require('tail').Tail;
tail = new Tail('./testlog.txt');

var server = ws.createServer(function (conn) {
    conn.on("text", function (str) {
        console.log("Received " + str);
    });
    conn.on("close", function (code, reason) {
        console.log("Connection closed");
    });
}).listen(8001);


setInterval(function(){ checkLoad(); }, 5000);


function broadcast(mesg) {
    server.connections.forEach(function (conn) {
        conn.sendText(mesg)
    })
}

var load = '';
function checkLoad(){
    var new_load = os.loadavg().toString();
    if (new_load === 'load'){
        return;
    }
    load = new_load;
    broadcast(load);
}

tail.on("line", function(data) {
    broadcast(data);
});

显然这是非常基本的,您必须根据自己的需要进行更改。

答案 1 :(得分:1)

我最近使用Munin进行了类似的实施。 Munin是一个很棒的服务器监控工具,开源也提供了REST API。有几个插件可用于监控服务器的CPU,HDD和RAM使用情况。

答案 2 :(得分:0)

您需要构建推送通知服务器。所有正在收听的客户端都会在更新新数据时收到推送通知。有关详细信息,请参阅此答案:PHP - Push Notifications

至于如何更新数据,我建议使用基于操作系统的工具来触发PHP脚本(命令行),该脚本将生成“推送”json文件到任何当前正在侦听的客户端。登录到“监听”的任何新客户端都将获得当前可用的json,直到它被更新。

通过这种方式,您不需要使用100个连接的100个用户以及每5秒轮询服务器的带宽,只有在他们需要知道更新时才会更新。

答案 3 :(得分:0)

如何读取所有日志信息的服务(通过 IPMI Nagios 等)并按照某些计划创建输出文件。然后,任何想要连接的人都可以只读取输出而不是锤击服务器日志。基本上只有一个命中服务器日志然后其他人只是读取一个网页。

这很容易实现。

BTW:Nagios有一个很好的免费

答案 4 :(得分:0)

回答你的问题:

  
      
  1. 将数据流式传输到各个客户端的高效方式(同时)。
  2.   
  3. 能够向服务器发送命令..(双向)
  4.   
  5. 使用网络语言(js,php ...),lunix命令(在多台机器上易于实现的东西)..如果需要,可以使用免费软件。
  6.   

我推荐使用CometD项目简化的Bayeux协议。有各种语言的实现,它以最简单的形式使用起来非常简单。

Meteor大致相似。它是一个应用程序开发框架而不是一系列库,但它解决了同样的问题。

答案 5 :(得分:0)

一些建议:

  • Munin for charts
  • NetSNMP(由Munin使用,但您也可以使用Bash和Cron构建在警报上发送短信的陷阱)
  • Ping远程警报,了解服务器响应ping和HTTP检查的情况。它可以通过短信发送短信或拨打电话,还可以使用呼叫升级规则。