簡易的內存監控系統
本文需要有一定的python和前端基礎,如果沒基礎的,請關注我后續的基礎教程系列博客
文章github源地址,還可以看到具體的代碼,喜歡請在原鏈接右上角加個star
騰訊視頻鏈接
錄制中間網出問題了,重啟了一下,所以有兩部分
本文的目的在於,盡可能用簡單的代碼,讓大家了解內存監控的原理
主題思路
- 獲取內存信息
- 存儲信息
- 展現
- 后續擴展
- 加主機名,monitor部署在多台機器,不直接插數據庫
- 通過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/1024
while True:
time.sleep(1)
getMem()
執行文件 python monitor.py,每一秒打印一條內存信息
[woniu@teach memory]$ python mointor.py
2920
2919
2919
2919
2919
我們可以寫個很搓的測試代碼,占用一點內存,看看數據會不會變
執行下面代碼,能看到內存使用量明顯多了幾M
# test.py
s = 'akdsakjhdjkashdjkhasjkdhasjkdhkjashdaskjhfoopnnm,ioqouiew'*100000
for i in s:
for j in s:
s.count(j)
獲取內存數據done!
第二步存儲數據庫
我們選用mysql
新建表格,我們需要兩個字段,內存和時間 sql呼之欲出,簡單粗暴
create memory(memory int,time int)
我們的 monitor.py就不能只打印內存信息了,要存儲數據庫啦,引入mysql模塊,代碼如下
import time
import MySQLdb as mysql
db = 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 'ok'
while 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,request
import MySQLdb as mysql
con = 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 time
import MySQLdb as mysql
db = 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 'ok'
while True:
time.sleep(1)
getMem()
flask
from flask import Flask,render_template,request
import MySQLdb as mysql
con = 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>
代碼沒有特別注意細節,希望大家喜歡。
最后 github原地址繼續求star哇
https://github.com/shengxinjing/my_blog/issues/1