Python监控进程状态并实现告警
公司的应用程序有时候会莫名其妙地挂掉,如果我们经常去登录服务器看是不是程序挂了,挂了再拉起,那样是非常耗时和麻烦的事情。
后来我们通过使用 supervisor 去守护启动,实现方法如下:
那什么是 supervisor了?
Supervisor是用 Python 开发的一个client/server服务,是Linux/Unix系统下的一个进程管理工具,不支持Windows系统。它可以很方便地监听、启动、停止、重启一个或多个进程。用Supervisor管理的进程,当一个进程意外被杀死,或者是意外被停止(系统负载过高,cpu占用率很高等),supervisor 监听到进程死后,会自动将它重新拉起来,很方便地做到进程自动恢复的功能,不再需要自己写shell脚本来控制。一般情况下,yum直接安装即可。yum install supervisor
首先我们需要首先注意的一个地方是配置文件的后缀。
vim /etc/supervisord.conf
[include]
files = supervisord.d/*.ini
如果你想配置文件为其他格式,比如 conf 格式的话, 需要更改 iles = supervisord.d/*.conf 。
比如我们需要守护启动一个进程,我们就以守护Prometheus 为例:
vim /etc/supervisord.d/proms.ini
[program:proms]
command=/opt/prometheus/server/prometheus/prometheus
directory=/opt/prometheus/server/prometheus
stdout_logfile=/home/data/logs/prometheus/sever.log
autostart=true
autorestart=true
redirect_stderr=true
user=root
startsecs=3
supervisor配置文件详解:
program: 指定的守护进程名
command: 命令
stdout_logfile: 日志路径
autostart: supervisor启动的时候是否随着同时启动,默认为 true
autorestart: 是否挂了自动重启
redirect_stderr:标准错误重定向
startsecs: 子进程启动多少秒之后,此时的状态是running
启动supervisor--(yum方式安装的)
/usr/bin/python /usr/bin/supervisord -c /etc/supervisord.conf
或者
systemctl start supervisord.service
因此 我们可以使用如下的命令进行进程的停止,启动,重启等操作。
supervisorctl status # 查看应用启动状态
supervisorctl stop proms # 停止prometheus应用
supervisorctl start proms # 启动prometheus应用
supervisorctl restart proms # 重启prometheus应用
虽然使用上面的策略 supervisor, 可以实现进程的守护启动,如果进程挂了,会自动拉起,但是并没有告警通知的功能。所以我们需要监控进程的状态并实现告警 通知到对应的开发人员以及运维人员。对于这样的场景,我们如何去实现了?
分析
对于这种情况,我们可以使用如下的方案去实现:
方案一:使用 Zabbix/Prometheus监控系统,对Java应用程序做 TCP 端口检测。如果检测端口不通,就设置检测失败的触发器。然后实现告警.
方案二: 使用 Zabbix的自定义Key去实现告警,自定义key 的内容是执行一个shell脚本,Shell脚本用来检测进程是否存在,不存在的话,输出为 0,存在输出为1。然后Zabbix 的触发器 设置最近的T值 不为1,从而来实现进程状态检测的告警。
方案三:编写Python脚本用来检测进程的状态,然后使用Python的内置库,实现邮件告警。
解决
思路整理
这里我们重点讲下python如何检测。
1.首先Python程序需要检测 Java进程是否存在。
2.检测到进程如果存在不做任何处理,如果不存在,就需要触发邮件告警的函数
3.Python程序需要定时定期地去执行检测脚本。
代码实现
第一阶
首先我们先来实现判断进程是否存在的逻辑,判断进程是否存在,我们采用 psutil来实现。库的安装方法如下:
pip3 install psutil
检测进程存在的代码逻辑如下:
#coding:utf-8
import psutil
def checkprocess(processname):
pl = psutil.pids() for pid in pl: if p.utilutil.Process.pid).name() == processname: return pid
if isinstance(checkprocess("notepad++.exe"),int):
print("进程存在")
else:
print(:进程不存在")
解析:
首先我们先定义一个 checkprocess 函数,函数的第一个参数传入进程名, 其中 pl = psutil.pids() 表示把所有的进程列出来。
接着我们for循环一下pid的列表,当找到 psutil.Process(pid).name() 的名词为传入的参数的名字的时候就返回pid值,没有就不做任何操作(可以认为返回内容为空)
接着 isinstance 用于检测返回内容。
那什么是 isinstance 了?
我们可以直接看看官方文档, https://docs.python.org/3/library/functions.html ,https://docs.python.org/3/library/functions.html
isinstance(object, classinfo)
Return True if the object argument is an instance of the classinfo argument, or of a (direct, indirect or virtual) subclass thereof. If object is not an object of the given type, the function always returns False. If classinfo is a tuple of type objects (or recursively, other such tuples), return True if object is an instance of any of the types. If classinfo is not a type or tuple of types and such tuples, a TypeError exception is raised.
我们翻译成中文,可以这样理解:
1.格式
isinstance(object,type-or-tuple-or-class) -> bool
2.作用
判断一个对象是某个类或子类的实例。
3.参数介绍
第一个参数(object)为对象,第二个参数(type)为类型名(int...)或类型名的一个列表((int,list,float)是一个列表)。其返回值为布尔型(True or flase)。
当第二个参数是type-or-tuple时
若第二个参数只有一个单独的类型,对象的类型与参数二的类型相同则返回True;
若第二个参数为一个元组类型,则若对象类型与元组中类型名之一相同即返回True。
第二阶段
我们在第一阶段实现了检测进程的相关代码,现在我们来实现发送邮件的代码实现,代码:内容如下:
#coding:utf-8
import smtplib
from email.mime.text import MIMEText
#第三方 SMTP 服务
mail_host = "smtp.exmail.qq.com" # SMTP服务器
mail_user = "tech.sys@aa.cn" # 用户名
mail_pass = "aapwd" # 密码
sender = 'tech.sys@aa.cn' # 发件人邮箱
#多个邮箱用逗号隔开构成列表
receivers = ['yyy@qq.com','xxx@qq.com'] # 接收人邮箱
定义函数。传入3个参数,第一个是接收者,第二个是主题,第三个是正文内容
def SendMail(receivers,title,content):
# content = '这是正文' # title = '这是主题' # 邮件主题 message = MIMEText(content, 'plain', 'utf-8') # 内容, 格式, 编码 message['From'] = "{}".format(sender) message['To'] = ",".join(receivers) message['Subject'] = title try: smtpObj = smtplib.SMTP_SSL(mail_host, 465) # 启用SSL发信, 端口一般是465 smtpObj.login(mail_user, mail_pass) # 登录验证 smtpObj.sendmail(sender, message['To'].split(','), message.as_string()) #邮件发" 发" int("mail has been send successfully.") except smtplib.SMTPException as e: print(e)
##测试邮件发送
SendMail(receivers,"主题","正文2")
解析:
上面的代码已经做了注释,代码功能不做详解。我们要注意的一点的是:smtpObj.sendmail(sender, message['To'].split(','), message.as_string())
因为之前我们的收件人,是列表的形式,所以在发送邮件的时候,我们需要 使用, 用 收件人进行逐一发送邮件。
第三阶段
整合以上两段代码,既可以检测进程又可以发送邮件:
#coding:utf-8
import smtplib
from email.mime.text import MIMEText
import psutil
#定义第三方 SMTP 服务
mail_host = "smtp.exmail.qq.com" # SMTP服务器
mail_user = "tech.sys@aa.cn" # 用户名
mail_pass = "aapwd" # 密码
sender = 'tech.sys@aa.cn' # 发件人邮箱
receivers = ['yy@qq.com','xx@qq.com'] ## 多个邮箱用逗号隔开构成列表
#定义进程名
P_name = "node_exporter"
#邮件发送函数
def SendMail(receivers,title,content):
# content = '这是正文' # title = '这是主题' # 邮件主题 message = MIMEText(content, 'plain', 'utf-8') # 内容, 格式, 编码 message['From'] = "{}".format(sender) message['To'] = ",".join(receivers) message['Subject'] = title try: smtpObj = smtplib.SMTP_SSL(mail_host, 465) # 启用SSL发信, 端口一般是465 smtpObj.login(mail_user, mail_pass) # 登录验证 smtpObj.sendmail(sender, message['To'].split(','), message.as_string()) # 发送 print("mail has been send successfully.") except smtplib.SMTPException as e: print(e)
#定义检测进程函数
def checkprocess(processname):
pl = psutil.pids() for pid in pl: if psutil.Process(pid).name() == processname: return pid
#SendMail(receivers,"主题","正文2")
if isinstance(checkprocess(P_name),int):
pass # 进程存在
else:
print("{0}进程不存在,发送邮件".format(P_name)) SendMail(receivers,"{0}进程down掉了".format(P_name),"{0}进程down掉了,请检测原因....".format(P_name))
解析:
上面的代码逻辑只是整合了两段代码, 并没有做其他的处理。首先是导入需要的模块,然后定义所需要的变量,以及函数,最后通过format函数将变量传入函数中而已。
需要注意的一点是,因为收件人是列表,那么在邮件发送的时候需要把列表进行切分,也就是使用split把收件人一个个地拿出来,然后再去进行邮件发送。
message['To'].split 切分出每个收件人(',') #split 切分出每个收件人
我们执行一下这段函数结果如下:
[root@me03 www]# python3 check_mail.py
node_exporter进程不存在,发送邮件
mail has been send successfully.
至此我们基本上实现了可以通过检测进程然后实现告警了。但是在我们编程当中,我们需要有模块化的编程思想,也就是有一些组件如果能模块化就进行模块化,那样子如果你有其他需求的话,想复用原来脚本的函数的话就不需要再去写重复的函数了。
所以我们可以通过类的方式进行导入。然后实现模块化的编程。
第四阶段
模块化编程,我们可以把邮件发送封装成一个类,用的时候直接导入即可。目录结构如下:
[www@me03 ~]$ tree ee/
ee/
├── check.py
└── S_mail.py
0 directories, 2 files
[www@me03 ~]$
S_mail.py 代码如下:
#coding:utf-8
import smtplib
from email.mime.text import MIMEText
class SendEMail(object):
# 定义第三方 SMTP 服务 def __init__(self): self.mail_host = "smtp.exmail.qq.com" # SMTP服务器 self.mail_user = "tech.sys@aa.cn" # 用户名 self.mail_pass = "aapwd" # 密码 self.sender = 'tech.sys@aa.cn' # 发件人邮箱 self.smtpObj = smtplib.SMTP_SSL(self.mail_host, 465) self.smtpObj.login(self.mail_user, self.mail_pass) # 登录验证 def sendmail(self, receivers, title, content): message = MIMEText(content, 'plain', 'utf-8') # 内容, 格式, 编码 message['From'] = "{}".format(self.sender) message['To'] = ",".join(receivers) message['Subject'] = title try: self.smtpObj.sendmail(self.sender, message['To'].split(','), message.as_string()) # 发送 print("mail has been send successfully.") except smtplib.SMTPException as e: print(e)
if name == 'main':
sm = SendEMail() sm.sendmail(['1093381395@qq.com'], '主题', '正文')
解析:
构造函数中初始化了邮件发送人、 smtp服务器等等。mail邮件发送函数进行发送邮件。要注意sm.sendmail` 传入的收件人是列表
我们再看看check.py 的内容。
#coding:utf-8
from S_mail import SendEMail #导入邮件类
import psutil
#实例化邮件类
sm = SendEMail()
#定义收件人
receivers = ['1093381395@qq.com','xx@qq.com'] # 接收人邮箱
#定义进程名
P_name="node_exporter"
#定义检测进程函数
def checkprocess(processname):
pl = psutil.pids() for pid in pl: if psutil.Process(pid).name() == processname: return pid
if isinstance(checkprocess(P_name),int):
pass # 进程存在
else:
print("{0}进程不存在,发送邮件".format(P_name)) sm.sendmail(receivers,"{0}进程down掉了".format(P_name),"{0}进程down掉了,请检测原因....".format(P_name))
</code></pre>
check.py的代码就更加简单了,首先我们先是导入了邮件类,类的作用是用来发送邮件用的,然后实例化邮件类,再定义一些变量信息。比如收件人等。最后我们通过编写进程检测函数,用来检测进程,如果进程不存在则会调用邮件类里的邮件发送函数来实现告警
第四阶段:
我们实现了检测进程是否存在然后实现告警的代码,现在我们需要它定时去检测,然后实现告警。我们加到计划任务里去。这两个文件放到一个指定的目录 下。(一定要放到同一个目录下,不然无法导入。如果放到其他的目录的话,需要修改check.py的模块导入路径才行)
/1 * python3 /home/data/scripts/check.py
到此,我们通过定时执行脚本检测进程并实现告警的需求得以实现。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
详解.Redis Cluster 工作原理和集群创建和使用
利用原生命令手动部署redis cluster Redis Cluster 工作原理 在哨兵sentinel机制中,可以解决redis高可用问题,即当master故障后可以自动将slave提升为master,从而可以保证redis服务的正常使用,但是无法解决redis单机写入的瓶颈问题,即单机redis写入性能受限于单机的内存大小、并发数量、网卡速率等因素。 早期Redis 分布式集群部署方案: 客户端分区:由客户端程序决定key写分配和写入的redis node,但是需要客户端自己处理写入分配、高可用管理和故障转移等 代理方案:基于三方软件实现redis proxy,客户端先连接之代理层,由代理层实现key的写入分配,对客户端来说是有比较简单,但是对于集群管节点增减相对比较麻烦,而且代理本身也是单点和性能瓶颈。 redis 3.0版本之后推出了无中心架构的redis cluster机制,在无中心的redis集群当中,其每个节点保存当前节点数据和整个集群状态,每个节点都和其他所有节点连接 Redis Cluster特点如下: 所有Redis节点使用(PING机制)互联 集群中某个节点的...
- 下一篇
Gartner:2021年IT企业最高战略预测
在前几日召开的2020 Gartner IT Symposium/Xpo大会上,Gartner公布了其对2021年及以后的主要战略预测。会上,研究副总裁兼Gartner研究员Daryl Plummer表示,传统技术已被利用到了极致,正面临重重障碍,未来十年将由创新技术引领。 能够引领未来的技术具有三个关键共性: 能为企业创造更大的创新和更高的效率; 比现有的技术更有效; 对社会产生了变革性的影响。 Gartner的十大战略预测如下: 1. CIO也将是COO 到2024年,25%的传统大型企业CIO将负责数字业务运营,成为“代理COO”。 首席运营官(COO)对于企业数字化转型非常重要,COO了解业务及企业的整个运营生态系统,而CIO对业务的技术有着深入了解,可以通过担当COO角色,将技术和业务融合起来,从而提高企业效率。 2. 工作中的对话将被记录和分析 到2025年,工作中75%的对话将被记录下来并分析,由此发现其中的附加价值或风险。 如今,我们在工作中的交流更多的是在社交软件、云会议上进行,一般,此类工具会保留我们对话的记录。未来,企业将对这些记录进行分析,这可以监督企业和员工遵...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
-
Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8编译安装MySQL8.0.19
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
推荐阅读
最新文章
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Hadoop3单机部署,实现最简伪集群
- CentOS6,CentOS7官方镜像安装Oracle11G
- CentOS7安装Docker,走上虚拟化容器引擎之路
- SpringBoot2全家桶,快速入门学习开发网站教程
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库