supervisor

前言

假设我们用python开发了一个爬虫, 放在linux运行, 我们很担心这个爬虫会挂掉, 一旦挂掉会影响我们后面的所有业务, 因为我们的数据没了, 这个时候supervisor可以帮助我们, 它一直监控我们的爬虫, 一旦挂掉,它会帮助我们重启

安装

supervisor是由python编写, 所以可以使用pip安装

1
pip install supervisor

组件

有两个组件:supervisordsupervisorctl

supervisord

运行 Supervisor 时会启动一个进程 supervisord,它负责启动所管理的进程,并将所管理的进程作为自己的子进程来启动,而且可以在所管理的进程出现崩溃时自动重启。

supervisorctl

是命令行管理工具,可以用来执行 stop、start、restart 等命令,来对这些子进程进行管理

命令解释

1
2
3
4
5
6
7
8
supervisord 初始启动Supervisord,启动、管理配置中设置的进程
supervisorctl stop programxxx 停止某一个进程(programxxx),programxxx为[program:chatdemon]里配置的值,这个示例就是chatdemon
supervisorctl start programxxx 启动某个进程
supervisorctl restart programxxx 重启某个进程
supervisorctl stop groupworker 重启所有属于名为groupworker这个分组的进程(start,restart同理)
supervisorctl stop all 停止全部进程,注:start、restart、stop都不会载入最新的配置文件
supervisorctl reload 载入最新的配置文件,停止原有进程并按新的配置启动、管理所有进程
supervisorctl update 根据最新的配置文件,启动新配置或有改动的进程,配置没有改动的进程不会受影响而重启。注意:显示用stop停止掉的进程,用reload或者update都不会自动重启

创建文件

手动创建一个配置文件

1
2
3
echo_supervisord_conf > /etc/supervisord.conf
#没有权限的话执行下面的命令
sudo su - root -c "echo_supervisord_conf > /etc/supervisord.conf"

配置说明

前面已经生成了配置文件, 打开文件,有英文的字段说明, 下面简单的介绍一些配置
管理单个进程的配置,可创建多个,下面是所有可能的配置选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
;[program:theprogramname]
;command=/bin/cat ; 启动进程的命令 使用相对路径,可以加参数
;process_name=%(program_name)s ; 进程名称 表达式 (默认 %(program_name)s)
;numprocs=1 ; 进程数目 (def 1)
;directory=/tmp ; 执行命令所在的目录 (def no cwd)
;umask=022 ; 进程默认权限 (default None)
;priority=999 ; 进程启动相对优先权 (default 999)
;autostart=true ; 跟随supervisor启动时启动 (default: true)
;autorestart=unexpected ; 计划启动 (default: unexpected)
;startsecs=1 ; 延时启动 (def. 1)
;startretries=3 ; 最多连续启动失败 (default 3)
;exitcodes=0,2 ; 进程结束代码 (default 0,2)
;stopsignal=QUIT ; signal used to kill process (default TERM)
;stopwaitsecs=10 ; 最长结束等待时间,否则使用 SIGKILL (default 10)
;stopasgroup=false ; 是否想UNIX进程组发送结束信号 (default false)
;killasgroup=false ; SIGKILL UNIX 进程组 (def false)
;user=chrism ; 设置启动此程序的用户
;redirect_stderr=true ; 重定向程序的标准错误到标准输出 (default false)
;stdout_logfile=/a/path ; 标准输出的日志路径, NONE for none; default AUTO
;stdout_logfile_maxbytes=1MB ; 日志文件最大值,否则循环写入 (default 50MB)
;stdout_logfile_backups=10 ; 标准输出日志备份数目 (default 10)
;stdout_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0)
;stdout_events_enabled=false ; emit events on stdout writes (default false)
;stderr_logfile=/a/path ; 标准错误输出日志路径, NONE for none; default AUTO
;stderr_logfile_maxbytes=1MB ; 日志文件最大值,否则循环写入 (default 50MB)
;stderr_logfile_backups=10 ; 标准错误日志备份数目 (default 10)
;stderr_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0)
;stderr_events_enabled=false ; emit events on stderr writes (default false)
;environment=A="1",B="2" ; 进程附加环境 (def no adds)
;serverurl=AUTO ; override serverurl computation (childutils)

流程

修改/etc/supervisord.conf最后的[include]如下

1
2
[include]
files = supervisor-conf.d/*.ini

然后mkdir /etc/supervisor-conf.d, 以后每个程序的配置都放到这个目录下面,更加合理

启动

supervisord -c /etc/supervisord.conf启动服务, 之后sudo supervisorctl status没有报错表示服务端正常启动

案例

py程序

我们还是写一个py的小例子:
test.py放在/root/下面

1
2
3
4
5
6
7
8
9
10
11
12
#! /usr/bin/env python
# -*- coding: utf-8 -*-

import time

while True:
time.sleep(5)
f=open("log",'a')
t=time.time()
f.write(str(t))
f.write("\n")
f.close()

这个程序是死循环, 一直向log文件里面写当前时间

创建ini配置文件

vim /etc/supervisor-conf.d/test.ini
配置如下:

1
2
3
4
5
6
7
8
9
[program:test]
directory=/root/
command=python test.py
user=root
autostart=true
autorestart=true
redirect_stderr=true
stopsignal=TERM
stopasgroup=true

一般就改下前面四行配置项目, 很简单能明白

更新一下supervisor

supervisorctl update
然后查看test.py是否正常运行
supervisorctl status

模拟重启

当前test.py正在运行, 接下来我们手动kill掉test.py, 看supervisor会不会帮助我们重启

我们能看到两次是不同的进程, 说明帮助我们已经重启了

使用浏览器管理supervisor

supervisor给我们提供了一个web界面来管理
nano /etc/supervisord.conf编辑:

1
2
3
4
[inet_http_server]         ; inet (TCP) server disabled by default
port=0.0.0.0:9001 ; (ip_address:port specifier, *:port for all iface)
username=user ; (default is no username (open server))
password=123 ; (default is no password (open server))