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



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

我正在使用ajax轮询。

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

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

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

  3. 将其转换为JSON

问题:

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

最终的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秒读取一次这些日志的最后一行,并可能将其写入一个文件,然后我只想在数据更改时将其推送到客户端


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

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

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

此外,对于多个用户,我多次阅读日志。(降低了旧服务器的速度)我无法控制服务器。。。我需要使用ajax来发送命令。。。

我需要WebSockets!!!


node.js和websockets

使用node.js,据我所知,我可以在不消耗大量资源的情况下完成所有这些资源和带宽。连接保持打开,所以没有不必要的头,我可以接收和发送数据。它可以很好地处理多个用户。

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

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

  2. 只有在发生更改时才应推送数据。

  3. 日志的读取应该在5秒后只发生一次。。。因此不由每个用户触发。


这是我发现的第一个例子。。。。。并进行了修改。。

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

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

您将如何保持较低的带宽以及服务器资源。

你会怎么做

编辑Btw。有没有办法这些数据同时流式传输到所有Clinet?

编辑

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

目标:1.高性能的阅读方式&将日志数据存储在某个地方(仅当clinets连接…[mysql,file,可以将此信息存储在ram中(使用node.js??)])。2.将数据流传输到各种客户端(同时)的性能方式。3.能够向服务器发送命令。。(双向)4.使用web语言(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);

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

readLogs()(可以是异步的)函数仍然是我不满意的地方。

  1. nodejs文件系统
  2. linuxSoftware->nodejs输出实现
  3. linux文件系统api

请记住,我需要扫描各种文件夹中的日志,然后以某种方式解析输出的数据,每2秒解析一次。

ps.:如果logReading系统是异步的,我会在服务器变量中添加isBusy。

编辑

答案不完整

缺少:

  1. 一种读取、解析和存储日志的高性能方式(linux文件系统api或nodejs api,因此i直接存储到系统内存中)
  2. 解释是否可以将数据直接流式传输给多个用户。显然nodejs通过客户端循环,因此(我认为)发送了多次数据

btw如果没有客户端,是否可以/值得关闭节点服务器,并在apache端的新连接上重新启动。(例如:如果我连接到apache托管的html文件,脚本将再次启动nodejs服务器)。这样做将进一步减少内存泄漏???正确的

编辑

在尝试了一些websocket之后(一些视频在评论中),我学到了一些新东西。复盆子PI有可能使用一些CPU DMA通道来高频的东西,如PWM。。。我需要弄清楚这是怎么回事。

当使用传感器之类的东西时,我应该把所有东西都存储在RAM中,nodejs已经做到了吗??(在脚本内的变量中)

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

我还没有使用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页面中,就在结束body标记之前。

<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"模块(如本文所示:如何在node.js中进行类似"tail-f logfile.txt"的处理?),您必须使用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);
});

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

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

您需要构建一个推送通知服务器。所有正在侦听的客户端都将在更新新数据时收到推送通知。查看此答案以获取更多信息:PHP-推送通知

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

这样,你就不必受制于100个用户使用100个连接,以及每5秒轮询服务器的带宽,只有当他们需要知道有更新时,你才能得到更新。

让一个服务读取所有日志信息(通过IPMINagios或其他方式)并按计划创建输出文件怎么样。然后,任何想要连接的人都可以读取这个输出,而不是敲打服务器日志。基本上,只要在服务器日志上点击一次,其他人就会阅读一个网页。

这可以很容易地实现。

BTW:Nagios有一个v nice免费

只回答以下问题:

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

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

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

一些建议:

  • Munin用于图表
  • NetSNMP(由Munin使用,但您也可以使用Bash和Cron构建陷阱,在警报中发送短信)
  • Pingdom用于远程警报服务器对ping和HTTP检查的响应情况。它可以给你发短信或打电话,也有呼叫升级规则

最新更新