第6章:使用Python监控Linux系统
1.Python编写的监控工具
1).多功能系统资源统计工具dstat
dstat是一个用Python编写的多功能系统资源统计工具,用来取代Linux下的vmstat,iostat,netstat和ifstat等命令 dstat可以在一个界面上展示非常全面的监控信息 # yum install dstat # dstat 2 10
dstat的强大之处不仅仅是因为它聚合了很多种工具的监控结果,还因为它能通过附带的插件实现一些高级功能,如找出占用资源最高的进程和用户 dstat的--top-(io|bio|cpu|cputime|cputime-avg|mem)这几个选项可以看到具体是哪个用户和哪个进程占用了相关系统资源,对系统调优非常有效 # dstat --top-mem --top-io --top-cpu # dstat -a --output dstat_utput.csv
2).交互式监控工具glances
glances是一款使用Python开发的,基于psutil的跨平台系统监控工具 glances可以在用户终端上实时显示重要的系统信息,并动态刷新内容 # pip install glances # glances 类似top命令的交互式界面 # pip install Bottle # glances -w
2.使用Python打造自己的监控工具
1).Linux系统的/proc目录介绍
Linux系统将监控数据保存在proc目录下
proc目录是一个控制中心,用户可以通过更改其中某些文件来改变内核的运行状态
2).proc目录下常用文件介绍
/proc/loadavg /proc/meminfo /proc/diskstats /proc/net/dev /proc/cpuinfo
3).进程目录下常用文件介绍
proc目录下有很多名字为数字的目录,目录的名称与进程的id对应
4).利用/proc目录找到被删除的文件
由于有进程(MySQL进程)打开了该文件,当我们从外部执行删除命令时文件并没有被真正的删除 只有当进程关闭该文件的句柄时,文件才会被真正删除 可以使用lsof命令查看已经被删除的文件 [root@kettle1 test]# lsof | grep tt.ibd mysqld 2933 mysql 37uW REG 253,0 98304 524406 /app/mysqldata/3306/data/test/tt.ibd (deleted) 虽然从文件系统层面已经无法找到被删除的文件,我们还可以在proc目录下找到该文件的文件句柄 [root@kettle1 fd]# ll /proc/2933/fd/37 lrwx------. 1 root root 64 Aug 10 16:34 /proc/2933/fd/37 -> /app/mysqldata/3306/data/test/tt.ibd (deleted) 为了恢复出一个一致性的数据文件,可以先在MySQL数据库中为该表加上表锁,以免在恢复文件的过程中还有新的写入 (root@localhost) [test]> lock table tt read; Query OK, 0 rows affected (0.00 sec) 恢复的方式也很简单,直接对文件句柄进行cp即可 [root@kettle1 fd]# cp /proc/2933/fd/37 /app/mysqldata/3306/data/test/tt.ibd [root@kettle1 fd]# chown mysql:mysql /app/mysqldata/3306/data/test/tt.ibd 重启数据库
5).使用shell脚本监控Linux
# cat monitor.sh 在CentOS7上的监控 cpu_idle=$(top -n2 | grep 'Cpu' | tail -n 1 | awk '{ print $8 }') cpu_usage=$(echo "100 - $cpu_idle" | bc) mem_free=$(free -m | awk '/Mem:/{ print $7}') mem_total=$(free -m | awk '/Mem:/{ print $2}') mem_used=$(echo "$mem_total - $mem_free" | bc) mem_rate=$(echo "$mem_used * 100 / $mem_total" | bc) disk_usage=$(df -h / | tail -n 1 | awk '{ print $5 }') disk_used=$(df -h / | tail -n 1 | awk '{ print $3 }') echo "cpu利用率: $cpu_usage %" echo "内存使用量: $mem_used M" echo "内存利用率: $mem_rate %" echo "磁盘空间使用量: $disk_used" echo "磁盘空间利用率: $disk_usage"
6).使用Python监控Linux
使用Python监控Linux磁盘IO # -*- coding: UTF-8 -*- from collections import namedtuple Disk = namedtuple('Disk', 'major_number minor_number device_name read_count read_merged_count read_sections time_spent_reading write_count write_merged_count write_sections time_spent_write io_requests time_spent_doing_io weighted_time_spent_doing_io') def get_disk_info(device): with open("/proc/diskstats") as f: for line in f: if line.split()[2] == device: return Disk(*(line.split())) raise RuntimeError("device ({0}) not found!".format(device)) def main(): disk_info = get_disk_info('sda') print(disk_info) print("磁盘写次数:{0}".format(disk_info.write_count)) print("磁盘写字节数:{0}".format(long(disk_info.write_sections)*512)) print("磁盘写延时:{0}".format(disk_info.time_spent_write)) if __name__ == '__main__': main()
3.使用开源库监控Linux
1).psutil介绍
psutil是一个开源且跨平台的库,其提供了便利的函数用来获取操作系统的信息,如cpu,内存,磁盘,网络等信息 psutil可以用来进行进程管理,包括判断进程是否存在、获取进程列表、获取进程的详细信息等 psutil广泛应用于系统监控、进程管理、资源限制等场景 # pip install psutil
2).psutil提供的功能函数
与cpu相关的功能函数 cpu_count默认返回逻辑cpu的个数 import psutil psutil.cpu_count() psutil.cpu_count(logical=False) cpu_percent返回cpu的使用率 import psutil psutil.cpu_percent() psutil.cpu_percent(percpu=True) psutil.cpu_percent(interval=2,percpu=True)
virtual_memory以命名元组的形式返回内存使用情况,包括总内存、可用内存、内存使用率、buffer和cached等 import psutil psutil.virtual_memory() def bytes2human(n): symbols = ('K','M','G','T','P') prefix = {} for i,s in enumerate(symbols): prefix[s] = 1 << (i+1) * 10 for s in reversed(symbols): if n >= prefix[s]: value = float(n) / prefix[s] return '%.1f%s' % (value,s) return "%sB" %n bytes2human(psutil.virtual_memory().total) swap_memory以命名元组的形式返回swap memory的使用情况 psutil.swap_memory()
与磁盘相关的功能函数 disk_partitions返回所有已经挂载的磁盘,包含磁盘名称、挂载点、文件系统类型等信息 psutil.disk_partitions() disk_usage获取磁盘的使用情况,包括磁盘的容量、已经使用的磁盘容量、磁盘的空间利用率等 psutil.disk_usage('/') disk_io_counters返回磁盘io统计信息,包括读的次数、写的次数、读写字节、写字节等 psutil.disk_io_counters()
与网络相关的功能函数
net_io_counter返回每块网卡的网络io的统计信息,包括收发字节数、收发包的数量、出错情况与删包情况
psutil.net_io_counters()
net_connections返回每个网络链接的详细信息
psutil.net_connections()
net_if_addrs返回网卡的配置信息,包括ip地址,mac地址,子网掩码和广播地址
3).综合案例:使用psutil实现监控程序
使用psutil收集了cpu的信息,开机时间,内存信息以及磁盘空间等信息,以及磁盘io与网络io信息 import os import socket from datetime import datetime import psutil import jinja2 import yagmail EMAIL_USER = 'hugaochao320@163.com' EMAIL_PASSWORD = 'hgc3177678' RECIPIENTS = ['hugc@knowbox.cn'] def render(tpl_path, **kwargs): path, filename = os.path.split(tpl_path) return jinja2.Environment(loader=jinja2.FileSystemLoader(path or './')).get_template(filename).render(**kwargs) def bytes2human(n): symbols = ('K','M','G','T','P') prefix = {} for i,s in enumerate(symbols): prefix[s] = 1 << (i + i) * 10 for s in reversed(symbols): if n >= prefix[s]: value = float(n) / prefix[s] return '%.1f%s' % (value, s) return "%sB" % n def get_cpu_info(): cpu_count = psutil.cpu_count() cpu_percent = psutil.cpu_percent(interval=1) return dict(cpu_count=cpu_count, cpu_percent=cpu_percent) def get_memory_info(): virtual_mem = psutil.virtual_memory() mem_total = bytes2human(virtual_mem.total) mem_percent = virtual_mem.percent #mem_free = bytes2human(virtual_mem.free + virtual_mem.buffers + virtual_mem.cached) mem_free = bytes2human(virtual_mem.available) #mem_used = bytes2human(virtual_mem.total * virtual_mem.percent) mem_used = bytes2human(virtual_mem.used) return dict(mem_total=mem_total, mem_percent=mem_percent, mem_free=mem_free, mem_used=mem_used) def get_disk_info(): disk_usage = psutil.disk_usage('/') disk_total = bytes2human(disk_usage.total) disk_percent = disk_usage.percent disk_free = bytes2human(disk_usage.free) disk_used = bytes2human(disk_usage.used) return dict(disk_total=disk_total, disk_percent=disk_percent, disk_free=disk_free, disk_used=disk_used) def get_boot_info(): boot_time = datetime.fromtimestamp(psutil.boot_time()).strftime("%Y-%m-%d %H:%M:%S") return dict(boot_time=boot_time) def collect_monitor_data(): data = {} data.update(get_boot_info()) data.update(get_cpu_info()) data.update(get_memory_info()) data.update(get_disk_info()) return data def main(): hostname = socket.gethostname() data = collect_monitor_data() data.update(dict(hostname=hostname)) content = render('monitor.html', **data) with yagmail.SMTP(user=EMAIL_USER, password=EMAIL_PASSWORD, host='smtp.163.com', port=465) as yag: for recipient in RECIPIENTS: yag.send(recipient, "monitor information".encode('utf-8'), content.encode('utf-8')) if __name__ == '__main__': main()
4.使用pyinotify监控文件系统变化
1).pyinotify模块介绍
pyinotify用来检测文件系统变化
inotify是一个事件驱动的通知器
pip install pyinotify
python -m pyinotify /tmp
2).pyinotify模块API
pyinotify模块API
WatchManager保存了需要监视的文件和目录,以及监视文件和目录的哪些事件
import pyinotify wm = pyinotify.WatchManager() wm.add_watch('/tmp', pyinotify.ALL_EVENTS) notifier = pyinotify.Notifier(wm) notifier.loop()
仅监视创建和删除事件 import pyinotify wm = pyinotify.WatchManager() mask = pyinotify.IN_DELETE | pyinotify.IN_CREATE wm.add_watch('/tmp', mask) notifier = pyinotify.Notifier(wm) notifier.loop()
3).事件标志与事件处理器
事件标志 事件含义
IN_CREATE 在被监控目录中创建子目录或文件
IN_DELETE 在被监控目录中有子目录或文件被删除
IN_MODIFY 被监控目录中的条目被修改
IN_MOVE
...
import pyinotify wm = pyinotify.WatchManager() mask = pyinotify.IN_DELETE | pyinotify.IN_CREATE class EventHandler(pyinotify.ProcessEvent): def process_IN_CREATE(self, event): print("Creating:", event.pathname) def process_IN_DELETE(self, event): print("Removing:", event.pathname) handler = EventHandler() notifier = pyinotify.Notifier(wm, handler) wdd = wm.add_watch('/tmp', mask, rec=True) notifier.loop()
5.监控应用程序
1).使用Python监控MySQL
数据库作为应用程序的核心组件,一般都需要进行细粒度的监控
以MySQL数据库为例:
对MySQL数据库的监控应该包括数据库连接数、qps、tps、Buffer Pool命中率、复制延迟、Binlog文件大小等
2).使用Python监控MongoDB
MongoDB本身就返回一个数据字典 from __future__ import print_function import pymongo client = pymongo.MongoClient(host='127.0.0.1:27017') client.admin.authenticate('laimingxing','laimingxing') rs = client.admin.command('replSetGetStatus') print("set:",rs['set']) print("myState:",rs['myState']) print("num of members:",len(rs['members']))