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

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

我正在使用Ajax轮询。

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

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

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

  3. 将其转换为JSON

问题:

  1. 每5秒打开一次新的连接。
  2. 多个AJAX调用。
  3. 请求头( 它们也是数据,因此消耗带宽
  4. 响应标题(^)
  5. 使用PHP每5秒读取一次文件。 即使没有改变。

最后的JSON数据less于5 KB,但是我每5秒发送一次,每次都有标题和新的连接,所以基本上每5秒我就要发送5-10 KB得到5 KB, 10-20 KB。

那些是60 sec / 5 sec = 12每分钟60 sec / 5 sec = 12新的连接和每小时约15 MB的stream量,如果我离开应用程序打开。

可以说,我有100个用户,我让监视器/控制我的服务器,将在一个小时左右1.5GB的传出stream量。

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

我需要在服务器上每5秒读取一次这些日志的最后一行,也许把它们写入一个文件,然后我想把这些数据推送到客户端,只要它改变了。


SSE(服务器发送事件)与PHP

 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); } 

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

也有多个用户多次读取日志(减慢我的旧服务器)我无法控制服务器…我需要使用ajax发送命令…

我需要WebSockets!


node.js和websockets

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

这是我需要你的帮助。

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

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

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


这是我find的第一个例子…..和修改..

 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); } 

上面的脚本将是通知服务器,但我也需要find一个解决scheme来存储这些多个日志的信息,并每次在后台更改一些东西。

你将如何保持低水平的服务器资源。

你会怎么做?

编辑顺便说一句。 有没有办法将这些数据同步传输到所有的镜像?

编辑

关于日志:我也希望能够扩大更新之间的时间膨胀…我的意思是,如果我读了ffmpeg的日志我ned每秒更新如果可能的话……但是当没有转换是积极的..我需要每5分钟获得基本的机器信息…等等…

目标: 1.高性能的方式来读取和存储日志数据的地方(只有当clinets连接… … [MySQL的,文件,这是可能的存储在RAM内的这个信息(与node.js ??)])。 2.将数据stream式传输到各种客户端(同时)。 3.能够发送命令到服务器..(双向)4.使用networking语言(js,php …),lunix命令(在多台机器上容易实现的东西)..如果需要的话免费软件。

最好的办法是:

根据当前活动 ,将日志读取到系统内存和数据stream中,同时连续地使用一个已经打开的连接 ,使用webSocket 连接不同的客户端。

我不知道什么可以加快。

UPDATE

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); 

但atm我使用一个非常糟糕的方式来parsing日志..(nodejs-> httpRequest-> php)..大声笑。 一些谷歌search后,我发现我完全可以stream的Linux软件的输出直接到nodejs应用程序…我没有检查…但也许这将是最好的方式来做到这一点。 node.js也有一个文件系统API可以读取日志。 Linux有它自己的文件系统API。

readLogs() (可以是asynchronous)函数仍然是我不满意的东西。

  1. nodejs文件系统?
  2. linuxSoftware-> nodejs输出实现
  3. Linux文件系统API。

请记住,我需要扫描日志的各种文件夹,然后parsing输出的数据,每2秒钟。

ps .:如果logReading系统是asynchronous的,我将adBusy添加到服务器variables中。

编辑

答案不完整。

失踪:

  1. 一个高性能的方式来读取,parsing和存储日志某处(linux文件系统api或nodejs API,所以我直接存储到系统内存)
  2. 如果可以将数据直接传输给多个用户,则进行说明。 显然nodejs循环通过客户端,所以(我认为)多次发送数据。

btw是否有可能/值得closures节点服务器,如果没有客户端,并重新启动新的连接在Apache端。 (例如:如果我连接到apache托pipe的HTML文件脚本再次启动nodejs服务器)。 这样做会进一步减less内存泄漏吗?

编辑

经过一些Websockets的实验(一些video在评论中),我学到了一些新的东西。 树莓派有可能使用一些CPU的DMA通道来高频的东西,如PWM …我需要以某种方式了解如何工作。

当使用传感器和类似的东西,我应该存储在RAM内的一切,nodejs已经这样做? (在脚本中的一个variables中)

websocket仍然是最好的select,因为它基本上可以轻松地从任何设备访问,只需使用浏览器。

我没有使用nodejs-websocket,但看起来它会接受一个http连接,并进行升级以及创build服务器。 如果你所关心的是接收的是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页面中,就在closuresbody标签之前。

 <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 )。

这也是一个更符合你想要的东西的解决scheme。 使用这个你的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> 

并使用这个作为您的networking套接字服务器代码,最近调整使用“尾”模块(如在这篇文章中find: 如何做`tail -f logfile.txt`在node.js中处理? ),你会必须使用npm安装(注意:尾部使用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); }); 

显然这是非常基本的,你将不得不改变你的需求。

最近我用Munin做了类似的实现。 Munin是一款出色的服务器监控工具,也是开源的,它也提供了一个REST API 。 有几个插件可用于监视服务器的CPU,HDD和RAM使用情况。

你需要build立一个推送通知服务器。 所有正在监听的客户端都会在新数据更新时收到推送通知。 请参阅此答案以获取更多信息: PHP – 推送通知

至于如何更新数据,我build议使用基于OS的工具来触发一个PHP脚本(命令行),它将生成一个“推送”json文件到任何当前正在监听的客户端。 任何login到“listen”的新客户端都将获得当前可用的json,直到它被更新。

这样你就不会受到100个使用100个连接的用户的影响,并且每5秒轮询你的服务器带宽有多less,只有当他们需要知道有更新时才会更新。

如何读取所有日志信息的服务(通过IPMINagios或其他),并按照一定的时间表创build输出文件。 然后,任何想连接的人都可以读取这个输出,而不是敲打服务器日志。 基本上有一个命中的服务器日志,然后其他人只是读取一个网页。

这可以很容易地实现。

BTW:Nagios有一个很好的免费版本

回答你的问题的这些部分:

  1. 将数据stream式传输到各种客户端(同时)。
  2. 能够发送命令到服务器..(双向)
  3. 使用networking语言(js,php …),lunix命令(在多台机器上很容易实现的东西)..如果需要的话免费软件。

我会推荐ComeeD项目简化的Bayeux协议。 有各种语言的实现,它最简单的forms很容易使用。

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

一些build议:

  • 穆宁的图表
  • NetSNMP(由Munin使用,但您也可以使用Bash和Cron构build在警报上发送短信的陷阱)
  • Pingdom提供有关服务器如何响应ping和HTTP检查的远程警报。 它可以短信给你或打电话,也有呼叫升级规则。