在grafana+ prometheus+php 监控系统实践文章当中已经实现了咱们的第一个监控图表,如今咱们有了一个新需求,须要对多个节点实现不一样的监控,以及一个汇总的监控;php
按照咱们以前手动建立仪表盘的方法,每新增一个节点都须要手动去修改prometheus配置,而且须要去grafana系统当中建立一个仪表盘,在节点不多的时候这种方式也能知足,但当节点数量多起来的时候,就会增长很大一部分工做量,而且存在每次建立的图表规则不一致的风险,所以咱们的需求是在新增节点以后让grafana自动建立一个仪表盘。node
修改配置文件的目的是把以前直接链接单个节点的地址更改成中间件地址,以前单节点的uri为'==/api/v1/rrd/metrics==',如今则须要将其修改成中间件地址'==/api/v1/rrd/toolSpool==',所以新的配置文件内容以下:mysql
--- global: scrape_interval: 5s scrape_timeout: 3s scrape_configs: - job_name: 'mysql' scrape_interval: 5s static_configs: - targets: ['192.168.43.34:9104'] labels: instance: 192.168.43.34 - job_name: 'media' scrape_interval: 3s metrics_path: "/api/v1/rrd/toolSpool" static_configs: - targets: ['gslb.offcncloud.com:8080']
当修改完配置文件以后,还须要让其配置文件生效,因此须要将prometheus从新启动。web
docker重启sql
docker自己就提供重启命令,因此只须要输入以下命令就能够了,注意后面是容器的名称。docker
docker restart prometheus
mac下重启json
mac下重启比较简单,首先终止以前的任务,而后使用启动命令segmentfault
prometheus --config.file=/tmp/prometheus.yml
中间件的做用是将各个节点的数据进行汇总,而后一次性返回给prometheus,实现这个中间件的方式有不少种,在实现以前咱们也查找了一些资料,好比有网友用 consul-template+consul方式来实现,可参考下方连接;不过我以为这个配置好像也不简单,而这个中间件的功能还挺简单的,因此仍是本身使用PHP写了一个中间件。
参考资料:
http://blog.51cto.com/xujpxm/...api
要得到各个节点的数据,name首先获就得取到全部的节点列表,而后经过节点的IP地址来拼接URL,最终经过curl请求该地址来获得节点数据;数组
在得到数据后,咱们还小须要给每个节点返回的数据加上标示能够用{}包括起来,由于prometheus支持这种格式,伪代码以下:
<?php public function getNodeListAttributesInfo(Request $req) { //1.获取节点列表 $nodelist = RrdToolModel::getNodeListAttributesInfo($req); //2.遍历获取各节点数据 $str = ''; foreach ($nodelist as $name) { $url = "http://{$name->ip}/api/v1/rrd/metrics"; //3. 获取数据 $tmp = file_get_contents($url); //4. 在每一个节点中插入host属性,到时候用来作筛选单个节点 $tmp = str_replace(' ', " {host=\"{$name->ip}\"} ", $tmp); $str .= $tmp; }
咱们的核心需求是须要看到全部节点的汇总情况,因此在得到各个节点的数据后还须要进行累加,prometheus中貌似并直接不支持,因此咱们得在中间件总进线累加汇总。
//限制须要进行汇总统计,首先把字符串分割为数组 $arr = explode(PHP_EOL, $str); $tmpArr = []; //遍历数组 foreach ($arr as $val) { //把每一行再次分割 $valArr = explode(" ", $val); //5. 汇总统计 if (!empty($valArr[0]) && is_string($valArr[0]) && is_numeric($valArr[2])) { $tmpArr[$valArr[0]] = isset($tmpArr[$valArr[0]]) ? ($tmpArr[$valArr[0]] + $valArr[2]) : $valArr[2]; } } //6. 汇总输出 foreach ($tmpArr as $key => $num) { echo "{$key}_total $num" . PHP_EOL; } echo $str; }
当中间件处理完成以后,咱们须要各个节点的数据,并有在数据中须要有节点的标示,另外还须要一个汇总的数据,所以中间件返回数据以下:
media_connectNum_total 0 media_network_total 0 media_on_push_total 2 media_connectNum {host="192.168.43.46:8080"} 0 media_network {host="192.168.43.46:8080"} 0 media_on_push {host="192.168.43.46:8080"} 1 media_connectNum {host="127.0.0.1:8080"} 0 media_network {host="127.0.0.1:8080"} 0 media_on_push {host="127.0.0.1:8080"} 1
如今咱们的prometheus已经启动,而且中间件也正常运行,那么此时prometheus和Grafana应该都有相应变化,咱们能够根据这写变化来肯定咱们前面的处理是否成功。
当咱们的配置文件和中间件发生变化后,最早产生相应变化的应该是数据仓库,因此咱们能够打开打开prometheus的web界面,URL地址(http://192.168.43.34:9090/graph)
在筛选中输入media_network,而后进行筛选,若是能看到多个返回的记录,则说明验证成功,以下图所示。
当prometheus数据仓库的数据发生变化后,grafana的仪表盘也应该会发生变化,最明显的变化以下图所示,标签都变成了双份,好比以前的一份“拥堵拉流数量”变成了双份。
缘由多个节点返回了多份数据,而咱们使用Grafana绘图的时候筛选项只输入了其中的key部分,并无筛选里面的属性,所以有多少个节点就会有出来多少个项,若是数量对上了,说明Grafana也验证成功了。
如今咱们把以前的仪表盘,从新编辑一下,把以前只筛选了key改为筛选key+上属性,设置方式以下图
设置好以后,咱们看到的将是汇总的仪表盘,至此咱们第一个的核心需求已经实现了
在设置汇总图后,咱们还将要实现第二个核心需求,自动化建立单节点的仪表盘,咱们首先须要手动先建立一个单个节点的图,和第一篇文章的建立方法一致,在设置筛选项的时候,咱们填写的内容要带上属性,属性的做用能够筛选节点,以下图:
API官方文档URL:http://docs.grafana.org/http_...
咱们的目标是当新增节点时grafana可以自动建立相应的仪表盘,所以须要使用到grafana的API接口,使用以前须要先建立一个密钥用来受权,建立的流程以下图:
添加一个api,在keyname中随便填写一个名字,而后role选择admin权限,点击添加按钮
当建立成功能看到grafana页面弹框提示,咱们须要把他先复制下来放到一个位置,由于后面是看不见这个key的,以下命令:
使用终端进行访问测试,若是返回结果以下,则表明这个key可使用
如今不要急着取用PHP进行调试,能够先用Postman进行调试,咱们须要调试的并非刚才弹框上面的URL地址,而是建立一个仪表盘的地址,在官方文档中的请求信息以下:
POST /api/dashboards/db HTTP/1.1 Accept: application/json Content-Type: application/json Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk { "dashboard": { "id": null, "uid": null, "title": "Production Overview", "tags": [ "templated" ], "timezone": "browser", "schemaVersion": 16, "version": 0 }, "folderId": 0, "overwrite": false }
使用postman请求截图
{ "id": 23, "slug": "production-overview", "status": "success", "uid": "ID2FFcciz", "url": "/d/ID2FFcciz/production-overview", "version": 1 }
当返回如上结果,则说明已经建立成功了
如今咱们须要导出以前建立的一个节点仪表盘,用来作模板,导出仪表盘的配置方法比较简单,
把上面的json数据保存到 grafana.json文件中,在保存json文件的时候须要注意,导出来的json配置并不能直接使用,由于prometheus建立仪表盘的json格式并非这样的,咱们须要对这份json内容稍微处理一下,在其先后分别加上一些字符,效果以下
{ "dashboard": -------导出json的内容放中间-------- , "overwrite": false }
注意:,既然他是模板文件,里面确定有些东西是变化的,好比说他的title,和host属性,所以咱们得在模板里面作一个标示,好比title部分咱们能够用###title### ,方便后面的文本替换,具体可参考个人配置文件
保存以后,也能够拿这个json的内容用postman进行验证,使用postman可以正常添加后,咱们再使用PHP的curl去实现
如今已经确保咱们的json数据没有问题,因此如今使用PHP的curl来建立仪表盘,伪代码以下:
/** * 经过curl获取数据 * @param $url * @param bool $isHearder * @param bool $post * @return mixed */ function http_request($url, $isHearder = null, $post = 'GET', $data = null, $timeout = 1) { //初始化curl $ch = curl_init($url); //设置URL地址 curl_setopt($ch, CURLOPT_URL, $url); //设置header信息 if (!empty($isHearder)) { curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_HTTPHEADER, $isHearder); } //若是是post,则把data的数据传递过去 if (($post == 'POST') && $data) { #假如data为数组将其转换为json格式 if (is_array($data)) { $data = json_encode($data); } curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); } //若是是删除方法,则是以delete请求 if ($post == 'DELETE') { curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE'); } //设置超时时间,毫秒 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, $timeout*1000); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //执行CURL时间 $result = curl_exec($ch); //若是有异常,记录到日志当中 $curl_errno = curl_errno($ch); if ($curl_errno > 0) { LogModel::addlog('超时'); } //关闭URL,返回数据 curl_close($ch); return $result; }
当上面的操做都完成以后,咱们前期的基本工做已经完成了,如今须要作得事情是建立节点的时候调用PHP来发起请求
经过api来建立仪表盘的部分伪代码,prometheus的仪表盘中有一个uid的key,这个key能够由咱们本身控制,必须是保证他的惟一性(若是把json模板中的uid项设置为null,prometheus会自动为你生成一个);
咱们可使用节点IP地址的hash值做为他的uid,这样咱们未来在变动仪表盘的时候只要有ip就能获得uid,而无需再次存储一份,以下面的伪代码:
/** *建立图表 * @param $str * @param array $params * @return \Illuminate\Http\JsonResponse */ public function replaceNodeInfo($ip) { //接收节点触发事件 $uid = md5($ip); //设置head头,认证信息 $header = array( "Content-Type:application/json", 'Authorization: Bearer eyJrIjoicnhTMklodFMzaDRsUXFoUFFiZ2tSRnQ3TnI4WEVqQlEiLCJuIjoidGFuZ3Fpbmdzb25nIiwiaWQiOjF9' ); //读取json模板 $jsonstr = $this->readJsonData(); //替换模板中须要替换的位置 $jsonstr = str_replace('###node###', $ip, $jsonstr); $jsonstr = str_replace('###uid###', $uid, $jsonstr); //进行curl请求 http_request('http://192.168.43.34:3000/api/dashboards/db', $header, 'POST', $jsonstr); }
当使用PHP的curl请求后,咱们能够在grafana的仪表盘管理界面看到使用PHP建立的图表,当出现下图的效果则表明成功:
删除节点的时候,咱们对应的仪表盘也没用了做用,所以咱们也要删除对应的仪表盘,前面咱们生产的uid是ip地址的hash值,所以咱们删除的时候也能够取ip对应的hash值,经过这个uid来删除仪表盘,以下伪代码:
/** * 删除node节点视图信息 * @param Request $req */ public function delNodeViewInfo(Request $req) { //接收参数 $params = $req->all(); $ip = $params['ip']; $uid = md5($ip); //设置认证信息 $header = array( "Content-Type:application/json", 'Authorization: Bearer eyJrIjoicnhTMklodFMzaDRsUXFoUFFiZ2tSRnQ3TnI4WEVqQlEiLCJuIjoidGFuZ3Fpbmdzb25nIiwiaWQiOjF9' ); //执行删除事件 http_request("http://192.168.43.34:3000/api/dashboards/uid/{$uid}", $header, 'DELETE'); }
做者:汤青松
微信:songboy8888