在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