唔,前两天想起来以前挖的坑,准备重写一下,让幻想互联节点页面显示服务器真正的实时状态(如负载,网络速率等)。听说这样可以让页面更实用一些?
那么首先要做最基本的实现,嗯,也就是数据的收集。。
在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