唔,前两天想起来以前挖的坑,准备重写一下,让幻想互联节点页面显示服务器真正的实时状态(如负载,网络速率等)。听说这样可以让页面更实用一些?
那么首先要做最基本的实现,嗯,也就是数据的收集。。
在N年前用过NodeQuery,算是比较方便的一个Liunx系统资源监控工具吧。
他是基于客户端Agent主动提交大部分数据(如CPU使用,负载,网络速率,硬盘空间、进程使用等),和服务器定时Ping(仅做延迟检测等)来实现数据收集。
然后存储于它的数据库中,每次只需打开它的页面就能优雅的显示性能信息。
But,这个页面不像UptimeRobot,提供Public页面,也就是非登录用户可以查看的页面。。
(顺带吐槽一下。UptimeRobot那页面用的IIS+PHP-CGI,经常莫名50x boom。而且绑域名的Public的页面已经炸了。。。。)
如果要给用户显示节点信息,更不能使用其页面,因为我们可能只需要知道服务器实时网速,而不需要其他内容,打开额外的一个页面十分不友好。
以前用过某Panel,服务端会统计节点的网速等等信息。
然而部署实现略复杂。。
最近发现NodeQuery提供了API,而且Agent客户端部署,几乎是一键完成的,只需要wget相应脚本就能自动部署,完全不需要关系其安装、自启什么的。。。
废话到这啦。
NodeQuery提供的API十分简单,只需要简易GET就可以获取相应数据,输出为JSON。
先给个简单的实现:
$server_id = 服务器ID;
$nodequery_api_url = 'https://nodequery.com/api/servers/'.$server_id.'?api_key=你的APIKEY';
if($nodequery_api_url){
$nodequery_api_callback_json = file_get_contents($nodequery_api_url);
$nodequery_result_array=json_decode($nodequery_api_callback_json,true);
echo "<pre style=\"font-family: Microsoft YaHei, Microsoft YaHei Light \">";
$rx_speed= round($nodequery_result_array['data']['0']['current_rx'] / 1024 / 180, 2)."KB/s";
$tx_speed= round($nodequery_result_array['data']['0']['current_tx'] / 1024 / 180, 2)."KB/s";
$nodequery_result = $Speed."KB/s";
echo "RESULT:[Rx_Speed:".$rx_speed."][Tx_Speed:".$tx_speed."]";
echo "</pre>\n";
这样可以获取并显示服务器的速率。
先说下这里头有个坑。。
官方API给的current_rx,窝一开始还以为是byte/s或b/s之类的。。拿计算器对照官方页面显示的MB/s换算了半天,也没换算通2333。
比如API的数值为:3485884326,官方页面上显示的就是35.87MB/s。
除了N次1024,感觉很迷,就是得不出来。。
官方版面也有人提到这个问题,但是并没有正确的答复。。。
最后发现!这数值是自上一次Query之后的增值,也就是3分钟之内传输的数据量。
所以就是180秒咯,然后再除个1024,就可以得出KB/s了,稳。
So,现在可以正常显示了。
但,NodeQuery服务器好像是意大利的?全国Ping 300+。。。
连过去贼慢,容易卡线程。
So,如果写到数据库缓存一下,那就比较丝滑了。
因为NodeQuery数据每个节点是180秒才更新一次,所以没必要实时Get,缓存个30秒为佳(不同节点,时间不同步)。
首先是可以写到MySQL,但是要建数据库和表,略麻烦,为了一个小实现去建表www。。
于是乎想起之前有见过用Redis缓存的程式。。印象中是基于内存的数据库,查询快,而且不用写到硬盘(一般情况)。
那就去搜一下Redis的实例咯。。
服务端用Oneinstack配置的,所以默认安装了Redis。
经过几分钟的摸索,想出这么一个模式。
需要记录两个字符串,一个记录最后一次的获取时间,一个记录获取到的记录。
获取时间就直接用Unix时间戳了,最为方便,可以直接减得时间差,设定30秒内读取缓存,极为方便。
获取到的记录就直接把拿到的JSON往里写,要调用的时候再解析,这样保证数据的完整,要什么拿什么(一次请求可以获得多个服务器的性能参数)
(本例获取的是单台服务器的2333,有获取多台的API)
先试一下服务器娘是否工作正常,存一个时间进去,然后读出来。
//NodeQuery数据获取与缓存
$redis_nodequery = new Redis();
$redis_nodequery->connect('127.0.0.1', 6379);
echo "Connection to server sucessfully</br>";
//查看服务是否运行
echo "Server is running: " . $redis_nodequery->ping();
$redis_nodequery->set("redis_nodequery_last_query_time", time());
// 获取存储的数据并输出
echo "</br>Stored string in redis:: " . $redis_nodequery->get("redis_nodequery_last_query_time");
按照窝的时间,结果为:
Connection to server sucessfully Server is running: +PONG Stored string in redis:: 1493387558
写入的时间可以正常读取出来,如果木有,请检查下Redis的配置是否正确。。。
这时候查着查着,发现Redis实际上是有持久化储存的,会定时/定量写入硬盘。。
大部分Redis应用不会强制需要上次的数据,我们可以关闭这个功能,并且把表清空一下。
配置文件中。吧三个默认的save给#,注释掉,然后打个save "",就行。
至于配置文件在哪,不太清楚Oneinstack是yum安装的还是怎么装的。。。窝也找了一好,除了用系统搜索以外,可以直接去查redis的服务文件,可以直接看到conf的位置。
清空数据的方法:先redis-cli进入,然后flushall即可。
配置文件改好记得service redis-server restart一下。
嗯,于是经过短暂滴摸索于研究,顺带解决一些可能请求超时的问题:
<?php
header("Content-Type: text/html; charset=UTF-8");
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
header("Cache-Control: no-cache, must-revalidate");
header("Pramga: no-cache");
ini_set("display_errors", "On");
error_reporting(E_ALL^E_NOTICE^E_WARNING);
//时间环境
ini_set('date.timezone','Asia/Shanghai');
date_default_timezone_set('Asia/Shanghai');
//调试环境
$server_id = 服务器ID数字;
//Redis获取NodeQuery数据与缓存
$redis_nodequery = new Redis();
$redis_nodequery->connect('127.0.0.1', 6379);
//查看服务是否运行
echo "Server is running: " . $redis_nodequery->ping() . '</br>';
//获取Redis存储数据
if ((time() - $redis_nodequery->get("redis_nodequery_last_query_time")) < 30){
//Good,use cache.
echo 'Good,use cache.</br>';
$nodequery_api_callback_json=$redis_nodequery->get("redis_nodequery_last_query_content");
//调试输出
//echo $redis_nodequery->get("redis_nodequery_last_query_content");
}else{
//Cache Timeout.
echo 'Cache Timeout.</br>';
$nodequery_api_url = 'https://nodequery.com/api/servers/'.$server_id.'?api_key=你的APIKEY';
if($nodequery_api_url){
$nodequery_file_get_contents_opts = array(
'http'=>array(
'method'=>"GET",
'timeout'=>1,
),
'https'=>array(
'method'=>"GET",
'timeout'=>1,
)
);
$nodequery_file_get_contents_opts_context = stream_context_create($nodequery_file_get_contents_opts);
$nodequery_content = file_get_contents($nodequery_api_url, false, $nodequery_file_get_contents_opts_context);
if($nodequery_content){
echo 'API Query Request Success.</br>';
$nodequery_api_callback_json=$nodequery_content;
$redis_nodequery->set("redis_nodequery_last_query_content", $nodequery_content);
$redis_nodequery->set("redis_nodequery_last_query_time", time());
}else{
echo 'API Query Request Failed,try to use old cache.</br>';
$nodequery_api_callback_json=$redis_nodequery->get("redis_nodequery_last_query_content");
}
}
//调试输出
//echo $redis_nodequery->get("redis_nodequery_last_query_content");
}
//获取Redis存储数据结束
//获取时间
echo "Query Time:".date("Y-m-d H:i:s",$redis_nodequery->get("redis_nodequery_last_query_time"));
$nodequery_result_array=json_decode($nodequery_api_callback_json,true);
echo "<pre style=\"font-family: Microsoft YaHei, Microsoft YaHei Light \">";
//print_r($nodequery_result_array);
echo "</br>";
$rx_speed= round($nodequery_result_array['data']['0']['current_rx'] / 1024 / 180, 2)."KB/s";
$tx_speed= round($nodequery_result_array['data']['0']['current_tx'] / 1024 / 180, 2)."KB/s";
echo "RESULT:[Rx_Speed:".$rx_speed."][Tx_Speed:".$tx_speed."]";
echo "</pre>\n";
?>
其中$nodequery_file_get_contents_opts来设定获取的超时,窝设置的是1s。
如果因为网络获取失败或超时,会自动调用上一次的结果,避免客户端请求时间过长或显示失败。
通过判断获取成功后再存入和更新获取时间,保持原子性。
唔,那就先这样啦,获取成功妥妥滴。
准备再折腾成Web API给客户中心用,顺便要加个验证免得恶意拉取(反正不会请求源,其实也无所谓了?)
其实这是被动的,还可以做成Cron,用户可以完全避免等待请求时间的问题,或做成触发式。
调了下路由,给获取API指定走国际线路了,应该会快一点w。




Comments | NOTHING