注:原文地址 psutil and MongoDB for System Monitoringjavascript
這篇入門文章描述了怎樣建立一系列的圖表來監控一臺或多臺服務器的負載。使用 Python(psutil 和 bottle),MongoDB 和 jquery。無論你使用什麼樣的數據庫或 WEB 框架,思路都是同樣的。css
在最後,你將有一個 web 頁面爲每臺服務器展現圖表,圖表中顯示了 cpu, memory, 和 disk usage。html
咱們須要監控兩臺 FreeBSD 服務器來確保它們是正常的,運行期間沒有內存和磁盤使用率問題。 爲了這篇文章的目的,這兩臺服務器的名字是 example01 和 example02。java
注意:這些剛好是相同的機器運行 MongoDB 副本集,它們中的一臺運行 web 服務。沒有理由它們必須是相同的機器 - 你徹底可讓 MongoDB 運行在一臺不一樣的服務器上,而不是你想監控的其中一臺。這對於 web 服務也是同樣的 - 能夠在任何服務器上,不是必須得在你監控的其中一臺服務器上。python
我不想登陸每臺服務器,而後運行 top
或 ds
來找出發生了什麼。我想要一個有最新圖表的 web 頁面能夠看一眼,每臺服務器一個頁面。jquery
整個工做流遵循如下三個步驟:git
psutil
和 cron
)bottle
)jqplot
+ AJAX)你能夠在 GitHub 工程 psmonitor 上獲取全部的代碼。在這篇文章中,我使用一些代碼片斷。github
在第一部分,你在一個 cron
任務中使用 psutil
Python 包每五分鐘寫系統信息到 MongoDB 的一個 capped collection 中。這 5 分鐘是徹底任意的 - 你能夠選擇你喜歡的任意時段。我正在監控的系統,幾分鐘提供足夠細的粒度。這部分把數據存入 MongoDB。web
在第二部分, bottle
應用程序發出一個請求給 MongoDB,而後獲得一個 JSON 數據格式的響應。這是在客戶端的 HTML 頁面和 MongoDB 數據直接建立了一個代理。ajax
在第三部分,你有一個 HTML 文件匹配到你想監控的每臺服務器上。該文件加載 jqplot
併發出一個 AJAX 請求給 bottle
應用程序。這部分是波動的緣由 - 咱們獲取存儲在 MongoDB 中的負載數據的時間序列圖表。
這個咱們建立的其中一個圖表的示例:
你能夠爲你想要的任何數據建立圖表。我爲每臺機器使用的圖表是:
如下的工具須要經過安裝來實現,可是你可使用一個不一樣的數據庫或是 Web 框架,若是你已經有的話。
psutil
是一個很是好用的跨平臺的系統監控工具,若是想了解更多,請移步至其項目主頁,你能夠經過 pip
安裝它。
NoSQL 數據庫 MongoDB 是一個開源的文檔型數據庫。若是你有天然適合 JSON 結構的數據,MongoDB 會是一款很是適合存儲數據的工具。對我來講,它已經成爲了首選的工具,當我隨時發現須要存儲 JSON 格式數據的時候。有趣的是,我越使用它,越能找到新的用途。MongoDB 的文檔型結構是驚人的有用,而且能夠爲許多信息類型提供 map 。
bottle
Web 框架是一個用 Python 寫的沒有任何依賴的小型框架。你能夠經過 pip
安裝它。你可使用包括開發服務器讓事情繼續,稍後把它放在一個不一樣的後端服務器。我把個人放在 Apache 服務器,一旦我獲得我但願他們的。我稍後將寫一篇文章關於這個的設置。
jqplot jquery 插件使得生產圖表更容易,加上它們看起來也不錯,而且它們是統一的很容易的比較圖表。好比,當一個進程波動起來的時候,在圖表中很容易看出來,由於你能夠同時看到 cpu 和 內存飆升,這兩個圖表是一樣的 X 軸位置。你可使用這個插件作不少事情,這個練習僅僅只是皮毛。
當咱們想遵循這樣的模式建立一個數據結構的時候,在這步中你能夠添加和刪除任何 psutil 支持的數據。終點是會看 jqplot
圖表的用戶,所以在你的腦海裏保持數據結構,jqplot
想要的是一個雙元素列表的列表,其中一個是時間,像這樣:
[[datetime1, y-value1], [datetime2, y-value2], and so on.]
那個結構不是收集數據的最有效方式,可是記住你的初心是什麼一直是很重要的。咱們將收集數據而且改變數據結構以便給 jqplot
須要的數據結構。
當第一步我不知道我須要什麼和使用什麼,我有更多一些測量。我認爲,隨着時間的流逝,我看到機器的實際需求將改變,而且它很是容易改變。
{ 'server': servername, 'datetime': datetime.now(), 'disk_root': , 'phymem':, 'cpu': {'user':, 'nice':, 'system':, 'idle':, 'irq':,}, }
下面是 python 代碼從系統獲取數據(使用 psutil )到 MongoDB 數據庫。我在 MongoDB 中爲每一個被檢測到的機器建立了一個集合。
你能夠在 MongoDB 中建立一個單獨的 document,包含了每臺機器的數據;這個依賴於你的需求。由於我想每臺機器有一個單獨的頁面,我用一樣的方式拆分數據。若是你想把全部機器的圖表渲染到一個頁面中的話,你或許想讓全部機器的數據在一個 document 中。
我有一個三個成員的 MongoDB 副本,設置名爲 rs1
。保存數據的機器恰巧是我監控的服務器,example01 和 example02。這第三個是一個仲裁者,不保存數據。這些 mongoDB 服務器不須要監控,它們能夠在任何地方。
我有一個數據庫 reports
,咱們將把新的 collections 放入這個數據庫。對於每臺機器,我將有一個 collection 來包含它的負載數據:1440 分天天,每 5 分組抽樣一次,並保存 2 天的數據,咱們須要 576 條記錄(documents)。
(1440/5)*2 = 576 records per server
我不肯定我最後要使用多少數據,所以我預估了 2k 每一個 document,我爲每一個 document 預估一個比較大的大小, 由於這僅僅是個開始,後面我須要收集更多的數據,結果是 2k 真的是很是慷慨了,每一個記錄的平均大小是 200 bytes 左右,可是我沒有包含任何的網絡數據(而且 disk space 是低耗的)。
576 documents @ 2048 bytes per doc = 1,179,648 bytes
對於每一臺機器須要監控的機器,我建立了一個固定集合的最大大小上限 1179648 和一個最大的數量上限 576 documents:
use reports db.createCollection('example01', {capped:true, size:1179648, max:576}) db.createCollection('example02', {capped:true, size:1179648, max:576})
經過使用一個固定集合,咱們將保證數據是以插入順序保存的,隨着時間流逝,老的 documents 會自動刪除,所以咱們始終有最新的 48 小時數據。
首先,作必須的 imports 而且鏈接到 MongoDB 實例:
from datetime import datetime import psutil import pymongo import socket conn = pymongo.MongoReplicaSetClient( 'example01.com, example02.com', replicaSet='rs1', ) db = conn.reports
如今爲你想要的每個數據調用 psutil
:
def main(): cpu = psutil.cpu_times_percent() disk_root = psutil.disk_usage('/') phymem = psutil.phymem_usage()
建立一個字典包含你須要的時間序列結構數據。
doc = dict() doc['server'] = socket.gethostname() doc['date'] = datetime.now() doc['disk_root'] = disk_root.free, doc['phymem'] = phymem.free doc['cpu'] = { 'user': cpu.user, 'nice': cpu.nice, 'system': cpu.system, 'idle': cpu.idle, 'irq': cpu.irq }
最後,把這個字典做爲一個 document 添加進匹配的 MongoDB 集合中。它將被轉換成一個 BSON document 當它被插入數據庫的時候,可是結構是同樣的。
if doc['server'] == 'example01.com': db.example01.insert(doc) elif doc['server'] == 'example02': db.example02.insert(doc)
這裏你有代碼來獲取數據而且存儲進數據庫集合中。全部剩下的部分是運行代碼自動完成的。
在你想監控的每臺服務器上設置一個定時任務,每 5 分鐘運行一次:
*/5 * * * * /path/to/psutil_script
每一個 MongoDB 集合包含 48 小時的系統性能數據,隨你操弄。
建立一個 bottle
應用程序來查詢 MongoDB集合。
鏈接 MongoDB,在收到每一個請求服務器的數據後,給每一個對應的服務器響應格式化的數據。
from bottle import Bottle import pymongo load = Bottle() conn = pymongo.MongoReplicaSetClient( 'example01.com, example02.com', replicaSet='rs1', ) db = conn.reports
這是一個路由,一個 url 鏈接。當一個請求進來,從 url 中獲取服務器的名字,而後建立並返回一個合適的數據結構(jqplot
須要的)。
@load.get('/<server>') def get_loaddata(server): data_cursor = list() if server == 'example02': data_cursor = db.example02.find() elif server == 'example01': data_cursor = db.example01.find() disk_root_free = list() phymem_free = list() cpu_user = list() cpu_nice = list() cpu_system = list() cpu_idle = list() cpu_irq = list() for data in data_cursor: date = data['date'] disk_root_free.append([date, data['disk_root']) phymem_free.append([date, data['phymem']) cpu_user.append([date, data['cpu']['user']]) cpu_nice.append([date, data['cpu']['nice']]) cpu_system.append([date, data['cpu']['system']]) cpu_idle.append([date, data['cpu']['idle']]) cpu_irq.append([date, data['cpu']['irq']]) return { 'disk_root_free': disk_root_free, 'phymem_free': phymem_free 'cpu_user': cpu_user, 'cpu_irq': cpu_irq, 'cpu_system': cpu_system, 'cpu_nice': cpu_nice, 'cpu_idle': cpu_idle, }
HTML Page
HTML 頁是很是簡單的。
你能夠把 javascript 從 psmonitor.js
中直接放入頁面,或者是以一個文件的形式調用它(如示例那樣):
<!doctype html> <html> <head> <meta charset="utf-8"> <title>Load Monitoring</title> <link rel="stylesheet" type="text/css" href="/css/jquery.jqplot.css" /> <style>div {margin:auto;}</style> </head> <body> <div id="cpu_user" style="height:400px;width:800px; "></div> <script src="http://code.jquery.com/jquery-latest.min.js" ></script> <script type="text/javascript" src="/js/jquery.jqplot.js"></script> <script type="text/javascript" src="/js/jqplot.json2.js"></script> <script type="text/javascript" src="/js/jqplot.dateAxisRenderer.js"></script> <script type="text/javascript" src="/js/jqplot.highlighter.js"></script> <script type="text/javascript" src="/js/jqplot.cursor.js"></script> <!--[if lt IE 9]> <script language="javascript" type="text/javascript" src="excanvas.js"></script> <![endif]--> <script type="text/javascript" src="/js/psmonitor.js" /> </body> </html>
完整的代碼在 GitHub 工程中,可是這有 jqplot
代碼片斷用來設置顯示數據。機器 example01
運行的 web 服務器將返回 json 格式的負載數據。一樣,web 服務器能夠運行在任何機器上,在個人示例中,它發生在被咱們監控的服務器中的一臺。
每一個 plot 的代碼遵循了相同的模式:
代碼中的 url
包含了 example01
字符串:
url: "http://example01/load/example01"
example01
的第一個實例是 web 服務器的地址,由於該機器上運行着 bottle
應用。第二個實例是咱們想要數據的這臺服務器的名字。服務器名字(
bottle
路由(get_loaddata)檢索 MongoDB 記錄(documents):
$(document).ready(function(){ var jsonData = $.ajax({ async: false, url: "http://example01/load/example01", dataType:"json" }); var cpu_user = [jsonData.responseJSON['cpu_user']]; $.jqplot('cpu_user', cpu_user, { title: "CPU User Percent: EXAMPLE01", highlighter: {show: true, sizeAdjust: 7.5}, cursor: {show: false}, axes:{xaxis:{renderer:$.jqplot.DateAxisRenderer, tickOptions:{formatString:"%a %H:%M"}}}, series:[{lineWidth:1, showMarker: false}] }); });
該 javascript 劃分 CPU 用戶百分比;你能夠用相同的方式添加另外的 plots,僅僅須要改變變量的名字和標題。