10min手寫(一):伺服器內存監控系統
本文作者shengxinjing (woniuppp) · GitHub ,授權發布
本文需要有一定的Python和前端基礎,如果沒基礎的,請關注我後續的基礎教程系列博客
項目地址,可以看到具體的代碼,喜歡請加個星星
視頻鏈接
錄製中間網出問題了,重啟了一下,所以有兩部分
- 視頻1
- 視頻2
本文的目的在於,儘可能用簡單的代碼,讓大家了解內存監控的原理
主題思路
- 獲取內存信息
- 存儲信息
- 展現
- 擴展
- 加主機名,moitor部署在多台機器,不直接插資料庫
- 通過http請求的方式,一台機器起flask專門存數據monitor
思路圖
第一步,我們需要獲取內存信息
其實所有的監控項,包括內存數據,都是從文件中讀取的,大家執行以下 cat /proc/meminfo就可以看到關於內存的信息,我們關注的是前四行,總內存,空閑內存,緩衝和緩存大小
計算內存佔用量公式:
(總內存-空閑內存-緩衝-緩存)/1024Mb
代碼呼之欲出 monitor.py
用with打開文件,可以自動關閉,比直接open優雅那麼一丟丟
def getMem(): with open(/proc/meminfo) as f: total = int(f.readline().split()[1]) free = int(f.readline().split()[1]) buffers = int(f.readline().split()[1]) cache = int(f.readline().split()[1]) mem_use = total-free-buffers-cache print mem_use/1024while True: time.sleep(1) getMem()
執行文件 python monitor.py,每一秒列印一條內存信息
[woniu@teach memory]$ python mointor.py 29202919291929192919
我們可以寫個很搓的測試代碼,佔用一點內存,看看數據會不會變
執行下面代碼,能看到內存使用量明顯多了幾M
# test.pys = akdsakjhdjkashdjkhasjkdhasjkdhkjashdaskjhfoopnnm,ioqouiew*100000for i in s: for j in s: s.count(j)~
獲取內存數據done!
第二部存儲資料庫
###我們選用mysql
新建表格,我們需要兩個欄位,內存和時間 sql呼之欲出,簡單粗暴
create memory(memory int,time int)
我們的 monitor.py就不能只列印內存信息了,要存儲資料庫啦,引入mysql模塊,代碼如下
import timeimport MySQLdb as mysqldb = mysql.connect(user="reboot",passwd="reboot123",db="memory",host="localhost")db.autocommit(True)cur = db.cursor()def getMem(): with open(/proc/meminfo) as f: total = int(f.readline().split()[1]) free = int(f.readline().split()[1]) buffers = int(f.readline().split()[1]) cache = int(f.readline().split()[1]) mem_use = total-free-buffers-cache t = int(time.time()) sql = insert into memory (memory,time) value (%s,%s)%(mem_use/1024,t) cur.execute(sql) print mem_use/1024 #print okwhile True: time.sleep(1) getMem()
比之前的多了拼接sql和執行的步驟,具體過程見視頻,大家到資料庫里執行一下下面的sql,就能看到我們辛辛苦苦獲取的內存數據啦
select * from memory
我們的資料庫里數據越來越多,怎麼展示呢
我們需要flask
我們看下文件結構.├── flask_web.py web後端代碼├── mointor.py 監控數據獲取├── static 靜態文件,第三方圖表庫│ ├── exporting.js│ ├── highstock.js│ └── jquery.js├── templates│ └── index.html 展示前端頁面└── test.py 佔用內存的測試代碼
flask_web就是我們的web服務代碼,template下面的html,就是前端展示的文件,static下面是第三方庫
flask_web的代碼如下
- 提供兩個路由
- 根目錄渲染文件index.html
- /data路由去資料庫插數據,返回json,供畫圖使用
from flask import Flask,render_template,requestimport MySQLdb as mysqlcon = mysql.connect(user=reboot,passwd=reboot123,host=localhost,db=memory)con.autocommit(True)cur = con.cursor()app = Flask(__name__)import json@app.route(/)def index(): return render_template(index.html)@app.route(/data)def data(): sql = select * from memory cur.execute(sql) arr = [] for i in cur.fetchall(): arr.append([i[1]*1000,i[0]]) return json.dumps(arr)if __name__==__main__: app.run(host=0.0.0.0,port=9092,debug=True)
前端index.html
highstock的demo頁面,copy過來,具體過程見視頻<html><head><title>51reboot</title></head><body>hello world<div id="container" style="height: 400px; min-width: 310px"></div><script src=/static/jquery.js></script><script src=/static/highstock.js></script><script src=/static/exporting.js></script><script>$(function () { // 使用當前時區,否則東八區會差八個小時 Highcharts.setOptions({ global: { useUTC: false } }); $.getJSON(/data, function (data) { // Create the chart $(#container).highcharts(StockChart, { rangeSelector : { selected : 1 }, title : { text : 內存數據 }, series : [{ name : 本機內存, data : data, tooltip: { valueDecimals: 2 } }] }); });});</script></body></html>
具體觀察數據結構的過程,見視頻和demo鏈接,我們做的 就是把資料庫里的數據,拼接成前端畫圖需要的數據,展現出來
這時候前端就能看到圖表啦
我們並不僅限於此,如果想實時的看到內存,應該怎麼搞呢
- 查詢數據時候增加一個時間戳當限制條件,再次查詢時,只返回兩次查詢之間的增量數據
- 前端動態添加增量結點數據到圖表中
- 代碼呼之欲出
python
tmp_time = 0@app.route(/data)def data(): global tmp_time if tmp_time>0: sql = select * from memory where time>%s % (tmp_time/1000) else: sql = select * from memory cur.execute(sql) arr = [] for i in cur.fetchall(): arr.append([i[1]*1000,i[0]]) if len(arr)>0: tmp_time = arr[-1][0] return json.dumps(arr)
前端,3秒查一次增量數據
$.getJSON(/data, function (data) { // Create the chart $(#container).highcharts(StockChart, { chart:{ events:{ load:function(){ var series = this.series[0] setInterval(function(){ $.getJSON(/data,function(res){ $.each(res,function(i,v){ series.addPoint(v) }) }) },3000) } } }, rangeSelector : { selected : 1 }, title : { text : AAPL Stock Price }, series : [{ name : AAPL, data : data, tooltip: { valueDecimals: 2 } }] }); });
done!兩個文件都搞定,double kill!
效果
最終代碼直接下載那個木看也行
監控文件monitor.py
import timeimport MySQLdb as mysqldb = mysql.connect(user="reboot",passwd="reboot123",db="memory",host="localhost")db.autocommit(True)cur = db.cursor()def getMem(): f = open(/proc/meminfo) total = int(f.readline().split()[1]) free = int(f.readline().split()[1]) buffers = int(f.readline().split()[1]) cache = int(f.readline().split()[1]) mem_use = total-free-buffers-cache t = int(time.time()) sql = insert into memory (memory,time) value (%s,%s)%(mem_use/1024,t) cur.execute(sql) print mem_use/1024 #print okwhile True: time.sleep(1) getMem()
flask
from flask import Flask,render_template,requestimport MySQLdb as mysqlcon = mysql.connect(user=reboot,passwd=reboot123,host=localhost,db=memory)con.autocommit(True)cur = con.cursor()app = Flask(__name__)import json@app.route(/)def index(): return render_template(index.html)tmp_time = 0@app.route(/data)def data(): global tmp_time if tmp_time>0: sql = select * from memory where time>%s % (tmp_time/1000) else: sql = select * from memory cur.execute(sql) arr = [] for i in cur.fetchall(): arr.append([i[1]*1000,i[0]]) if len(arr)>0: tmp_time = arr[-1][0] return json.dumps(arr)if __name__==__main__: app.run(host=0.0.0.0,port=9092,debug=True)
前端
<html><head><title>51reboot</title><meta charset=utf-8></head><body>hello world<div id="container" style="height: 400px; min-width: 310px"></div><script src=/static/jquery.js></script><script src=/static/highstock.js></script><script src=/static/exporting.js></script><script>$(function () { // 使用當前時區,否則東八區會差八個小時 Highcharts.setOptions({ global: { useUTC: false } }); $.getJSON(/data, function (data) { // Create the chart $(#container).highcharts(StockChart, { chart:{ events:{ load:function(){ var series = this.series[0] setInterval(function(){ $.getJSON(/data,function(res){ $.each(res,function(i,v){ series.addPoint(v) }) }) },3000) } } }, rangeSelector : { selected : 1 }, title : { text : 內存數據 }, series : [{ name : 本機內存, data : data, tooltip: { valueDecimals: 2 } }] }); });});</script></body></html>
代碼沒有特別注意細節,希望大家喜歡
運維開發交流QQ群:238757010
歡迎大家關注公共號,高品質運維開發
本文僅授權51Reboot相關賬號發布。
推薦閱讀:
※為什麼 x in range(1000000000000001) 的執行速度這麼快
※如何看待將Python代碼轉換成Go代碼並進一步編譯的 Grumpy 項目?
※基於ArcGIS的python編程:2.python基礎(一)
※不再寫 for 循環