进程管理 Supervisor
Supervisor 是一个用 Python 实现的进程管理工具,可以很方便地启动、重启、关闭、查看进程(不仅仅是 Python 进程)。除了对单个进程的控制,它还可以同时操作多个进程。除此之外它还能监控进程,当进程由于某种原因崩溃或者误操作杀掉后,自动重启并发送事件通知。
我们先安装它:
> pip install supervisor
Supervisor 组件
Supervisor 包含如下 4 种组件。
1.Supervisord:服务端程序,它的主要功能是启动 Supervisord 服务及其管理的子进程,记录日志,重启崩溃的进程等。
2.Supervisorctl:命令行客户端程序,它提供一个类似 Shell 的接口,通过 UNIX 域套接字或者 TCP/IP 套接字使用 XML_RPC 协议与 Supervisord 进程进行数据通信。它的主要功能就是管理(启动、关闭、重启、查看状态等)子进程。
3.Web Server:实现了在界面上管理进程,还能查看进程日志和清除日志。Web Server 其实是通过 XML_RPC 来实现的,可以向 Supervisord 请求数据。它配置在[inet_http_server]块里面。
4.XML_RPC 接口:可以通过 XML-RPC 协议对 Web Server 进行远程调用,达到和 Supervisorctl 以及 Web Server 一样的管理功能。
配置 Supervisor
Supervisor 的配置文件一般都叫作 supervisord.conf。启动 Supervisord 的时候会按照如下的路径寻找配置文件:
- 当前目录下的 supervisord.conf($CWD/etc/supervisord.conf)。
- 当前目录的 etc 目录下的 supervisord.conf($CWD/etc/supervisord.conf)。
- 相对于可执行文件 supervisord 的上一级的 etc 目录下的 supervisord.conf(../etc/super-visord.conf)。
- 相对于可执行文件 supervisord 的上一级的 supervisord.conf(../supervisord.conf)。
可以使用-c 选项指定不符合如上要求的配置文件路径。
先创建一个统一的存放日志的目录,并让 ubuntu 这个用户成为其拥有者:
> sudo mkdir/var/log/supervisord > sudo chown ubuntu:ubuntu/var/log/supervisord-R
下面的例子将通过 Supervisor 管理 Memcached 和 Gunicorn:
[unix_http_server] file=/tmp/supervisor.sock;监听 HTTP/XML-RPC 请求。分号表示之后的内容是注释 ;username=dongwm;登录管理后台的用户名 ;password=123;username 和 password 在安全的网络中不需要设置,所以都是注释的 [inet_http_server];提供 Web 管理界面 port=0.0.0.0:5000;Web 管理后台运行的 IP 和端口,需要考虑安全性 username=dongwm password=123 [supervisord] logfile=/var/log/supervisord/supervisord.log ;日志文件 logfile_maxbytes=50MB ;日志文件大小限制,超过会切分。设置 为 0 表示不限制 logfile_backups=20 ;切分后的日志保留的份数 loglevel=error ;日志级别,其他可选项为 info, debug, warn, trace pidfile=/var/run/supervisord.pid nodaemon=false ;使用 daemon 的方式启动 minfds=1024 ;可以打开的文件描述符的最小值 minprocs=200 ;可以打开的进程数的最小值 user=ubuntu ;启动 supervisord 进程使用的用户,虽然 默认就是当前用户,但是指定 user 是一个好习惯 [rpcinterface:supervisor] supervisor.rpcinterface_factory=supervisor.rpcinterface:make_main_rpcinterface [supervisorctl] serverurl=unix:///tmp/supervisor.sock ;使用 UNIX 域套接字的方式,文件路径必须 和 unix_http_server 里面的设定匹配 prompt=web_develop;定义提示文本,常用来区分不同的环境。使用清晰的提示能减少操作出错 [include];包含其他的配置文件,本例因为演示才把全部配置放在了一起,如果管理的进程较多,应该按一定规则分散到不同的配置文件中 files=/etc/supervisor/conf.d/*.conf [program:app_chapter6];每个 program 就是一个(组)进程 command=gunicorn-w 3 chapter6.section1.run:app-b 0.0.0.0:9000;启动命令 autostart=true;在 Supervisord 启动的时候也自动启动 autorestart=true;程序异常退出后自动重启 startsecs=5;启动 5 秒后没有异常退出,就当作已经正常启动了 startretries=3;启动失败自动重试次数,默认是 3 次 user=ubuntu priority=100;优先级设置。低优先级会先启动,后关闭。应用进程应该是优先级最高 redirect_stderr=true;把错误日志重定向到输出的日志中。当然可以把错误日志分开存放,需要使用 stderr_logfile 参数 stdout_logfile=/var/log/supervisord/chapter6.log;指定输出的日志的文件路径 directory=%(ENV_HOME)s/web_develop;启动时会先切换目录进来,保证启动的时候的相对路径正确性 stdout_logfile_maxbytes=200MB;输出日志文件大小限制,超过会切分。设置为 0 表示不限制 [program:memcached] priority=10 numprocs=2;使用进程组 numprocs_start=2;进程组的数从 2 开始计数,因为 numprocs 是 2,也就是使用 2 和 3。如果不指定则是 0 和 1 process_name=1121%(process_num)s;当 numprocs>1 进程名字就需要带 process_num 变量 command=memcached-m 64-p 1121%(process_num)d-l 127.0.0.1;启动多个进程,由于 process_num 不同而启动命令不同 redirect_stderr=true stdout_logfile=/var/log/supervisord/memcached.log stopasgroup=false;如果设置为 true,当进程收到 stop 信号时,会自动将该信号发给该进程的子进程 killasgroup=false;如果设置为 true,当进程收到 kill 信号时,会自动将该信号发给该进程的子进程 [eventlistener:listener];Supervisor 提供事件监听和通知机制 buffer_size=30;增大事件队列的长度,如果监控的事件量大,不能处理的事件会被抛弃 priority=-1;事件监控的优先级应该最低 command=python%(ENV_HOME)s/web_develop/chapter7/section1/listener.py events=PROCESS_STATE_EXITED,PROCESS_STATE_STOPPED,PROCESS_STATE_FATAL,TICK_60;检测如上三种事件,全部事件类型可以查看[Event Types](http://supervisord.org/events.html#event-types) stdout_logfile=/var/log/supervisord/listener.log stderr_logfile=/var/log/supervisord/listener.log;eventlistener 类型不能使用 redirect_stderr=true stdout_events_enabled=false stderr_events_enabled=false
Supervisor 的注释要使用分号。在上述配置中,program 块中指定了要管理的进程,但是要注意,被管理的进程不能使用 daemon 模式,必须在前台运行。
ENV_HOME 是 Supervisor 内置的变量之一,表示当前用户的家目录。
在 eventlistener 块中使用了自定义的事件监听脚本 listener.py,它用来把事件日志写到文件中:
import sys from datetime import datetime from supervisor import childutils #通过 childutils 模块来创建事件监听 def write_log(headers, payload): if not headers['eventname'].startswith('PROCESS_STATE_'): return f=open('/tmp/log.txt', 'a') f.write(str(headers)+'\n\n') #为了查看事件通知的格式 pheaders, pdata=childutils.eventdata(payload+'\n') pheaders['dt']=datetime.now() #我们对事件的头信息做了扩充,添加当前时间 msg=('[{dt}]Process{processname}in group{groupname}exited ' 'unexpectedly (pid{pid}) from state{from_state}\n').format( **pheaders) f.write(msg) #当出现符合条件的三种事件,会记录如上日志 f.flush() f.close() def main(): while 1: headers, payload=childutils.listener.wait(sys.stdin, sys.stdout) write_log(headers, payload) childutils.listener.ok(sys.stdout) if__name__=='__main__': main()
Supervisor 有官方的插件集合 Superlance(https://github.com/Supervisor/superlance ),提供监控内存的使用、发送报警邮件等功能,但是建议只把它用作自定义脚本实现时的参考。更多第三方应用和插件可以在 Third Party Applications and Libraries(http://supervisord.org/plugins.html )找到。
使用 Supervisor
首先启动 Supervisord 进程:
> supervisord-c chapter7/section1/supervisord.conf
进程会以 daemon 的方式后台运行。使用 Supervisorctl 连接它:
> supervisorctl-c chapter7/section1/supervisord.conf app_chapter6 RUNNING pid 12316, uptime 0:00:11 listener RUNNING pid 12313, uptime 0:00:11 memcached:11212 RUNNING pid 12314, uptime 0:00:11 memcached:11213 RUNNING pid 12315, uptime 0:00:11 web_develop>
可以看到启动了两个 Memcached 进程、listener 进程和应用(Gunicorn)进程。现在管理进程:
web_develop>stop memcached:11212 #关闭 memcached:11212 进程 memcached:11212:stopped web_develop>status app_chapter6 STARTING listener RUNNING pid 17604, uptime 0:02:15 memcached:11212 STOPPED Jun 04 01:21 AM memcached:11213 RUNNING pid 17606, uptime 0:02:15 web_develop>update # 更新 supervisord.conf 配置后,可以使用这个命令让配置生效 web_develop>start memcached:11212 #重新启动 memcached:11212:started web_develop>pid app_chapter6 #查看进程 id 12316 web_develop>maintail #查看 Supervisor 日志 web_develop>tail-10 listener #查看 listener 进程日志,支持进程名自动补全 2 OKREADY
通过 help 命令可获取全部命令的列表。管理命令可以作为 supervisorctl 的参数来使用:
> supervisorctl-c chapter7/section1/supervisord.conf stop memcached:11212
由于监听程序会监听 PROCESS_STATE_STOPPED,所以会记录停止 memcached:11212 的事件。查看/tmp/log.txt,就会看到如下记录:
{'ver':'3.0', 'poolserial':'3', 'len':'67', 'server':'supervisor', 'eventname':' PROCESS_STATE_STOPPED', 'serial':'3', 'pool':'listener'} [2016-06-04 01:21:11.914393]Process 11212 in group memcached exited unexpectedly (pid 12314) from state STOPPING
还可以通过事件返回的结果来组织内容发送邮件、HTTP 请求、短信,甚至触发某些其他操作。
可以访问 http://localhost:5000,看到 HTTP 的管理页面。因为在[inet_http_server]块中配置了用户和密码,所以访问的时候是有用户访问验证的。
除此之外,还可以通过 XML_RPC 接口来管理进程:
In : import xmlrpclib In : server=xmlrpclib.Server('http://dongwm:123@localhost:5000/RPC2') In : server.supervisor.stopProcess('memcached:11212') Out: True In : server.supervisor.getProcessInfo('memcached:11212') Out: {'description':'Jun 04 01:31 AM', 'exitstatus':0, 'group':'memcached', 'logfile':'/var/log/supervisord/memcached.log', 'name':'11212', 'now':1465003888, 'pid':0, 'spawnerr':'', 'start':1465003311, 'state':0, 'statename':'STOPPED', 'stderr_logfile':'', 'stdout_logfile':'/var/log/supervisord/memcached.log', 'stop':1465003867} In:server.supervisor.startProcess('memcached:11212') Out:True
支持的全部命令可以使用 server.system.listMethods() 获取。
之前的例子是在虚拟环境中实现的,如果 Supervisor 安装在全局而要使用虚拟环境,可以通过如下两种方法。
1.把 program 项中的 command 改成完整路径:
[program:app_chapter6] command=%(ENV_HOME)s/.virtualenvs/venv/bin/gunicorn-w 3 chapter6.section1.app: app-b 0.0.0.0:9000
2.使用参数 environment 把全局环境目录放进 PATH:
[program:app_chapter6] environment=PATH=%(ENV_HOME)s/.virtualenvs/venv/bin:%(ENV_PATH)s command=gunicorn-w 3 chapter6.section1.app:app-b 0.0.0.0:9000
除了使用 Supervisor 管理进程,还可以选择 Upstart 和 Systemd 来管理,推荐 Systemd,因为它的设计更优秀,越来越多的 Linux 发行版已经选择它。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论