supervisor - Python进程管理工具(转)

add by zhj: 下面是在ubuntu上的一些使用经验

 

1. 简介

supervisor有两个组件:supervisord和supervisorctl,组成了client/server结构。

supervisord负责读入配置文件,然后supervisord监管的应用程序以supervisord子进程的方式启动,supervisord会自动将应用程序的进程转为守护进程,

这样即使你退出shell也没影响。注意,如果一个进程已经是守护进程了,那用supervisord监控时,会出错。

supervisorctl则负责和supervisord进行沟通,获取运行中的进程信息,包含pid,uptime等信息。supervisorctl既可以通过命令行参数进行控制,又能够

直接进入一个特有的shell,通过这个shell管控进程组。这样,既能够让部分同学准确把握进程状况,又能避免放开shell权限,一举多得。

 

2. 安装和配置

官网: http://www.supervisord.org/

建议用sudo pip install supervisor来安装,不要用apt-get安装

安装后,用echo_supervisord_conf > ~/supervisord.conf生成配置文件

 

3. 启动和关闭

启动supervisor: supervisord -c /etc/supervisor/supervisor.conf   # 如果不指定配置文件,那自动加载/etc/supervisord.conf

一般会配置成开机自启动,所以需要一个init脚本,参见Running supervisord automatically on startup,下载对应你的操作系统的启动脚本就可以了,

不过,里面的内容可能需要修改,比如supervisord和supervisorctl的路径,pid和log的路径与你supervisord.conf中的pid和log路径要相同

关闭supervisor: sudo kill <supervisord进程id>          # kill默然会发送SIGTERM信号,supervisord收到该信号会,会关闭所有子进程,最后关闭自己,这个过程可能需要几秒钟

 

4. 配置文件

详细的配置参见http://www.cnblogs.com/ajianbeyourself/p/5534737.html

supervisord要求监控的进程不能是守护进程。比如要监控nginx,那你要在nginx配置文件nginx.conf中,设置daemon off

supervisor的配置项有很多,下面是公司dev环境上的celery_beat应用程序的配置项

[program:celery_beat]
command=python manage.py celery beat --loglevel=info --settings=configs.dev
directory=/home/zhj/work/hera/   ; 执行command前,先跳转到directory
autorestart=true          ; 当进程关闭后,重启,当然,对于用supervisorctl stop xx关闭的进程,不会重启
redirect_stderr=true      ; 重定向程序的标准错误到标准输出 (default false)
startsecs=10              ; 启动后坚持运行多长时间被认为是启动成功了, (def. 1)
stopwaitsecs=30           ; 最长结束等待时间,超过这个时间还没收到子进程的SIGCHLD信号,那就用SIGKILL强制结束子进程 (default 10)
stdout_logfile=/var/log/celery/celery_beat.log
stdout_logfile_maxbytes=50MB
autostart=true            ; 当supervisor启动后,也随之启动

5. supervisorctl命令

貌似只有启动supervisor时,用到supervisord命令,其实情况下,用supervisorctl就可以了。

用下面的命令进入supervisor shell, sudo最好加上,不然有可能报错

执行supervisorctl时,配置文件的搜索路径如下

 

  1. $CWD/supervisord.conf
  2. $CWD/etc/supervisord.conf
  3. /etc/supervisord.conf

 

zhj@pc:~$ supervisorctl -c /etc/supervisor/supervisord.conf 
celery_beat                      STOPPED   Not started
celeryworker_celery:0            STOPPED   Not started
celeryworker_celery:1            STOPPED   Not started
celeryworker_email               STOPPED   Not started
supervisor> help

default commands (type help <topic>):
=====================================
add    exit      open  reload  restart   start   tail   
avail  fg        pid   remove  shutdown  status  update 
clear  maintail  quit  reread  signal    stop    version

supervisor> help start
start <name>        Start a process
start <gname>:*        Start all processes in a group
start <name> <name>    Start multiple processes or groups
start all        Start all processes
supervisor> 

下面是supervisorctl命令行下的命令:

status  #查看supervisord监控的所有进程的状态

celery status  #查看celery进程的状态

stop xxx   #停止某一个进程(xxx),xxx为[program:theprogramname]里配置的值

start xxx  #启动某个进程

restart xxx  #重启某个进程

stop groupworker  #重启所

stop all  #停止全部进程,注:start有属于名为groupworker这个分组的进程(start,restart同理)restartstop都不会载入最新的配置文件

reload   #重启supervisor

update  #根据最新的配置文件,启动新配置或有改动的进程,配置没有改动的进程不会受影响而重启。 当配置文件修改后,要执行这条命令。

                               #显示用stop停止掉的进程,即使配置文件设置了autorestart=true,用reload或者update都不会自动重启。

用supervisor监控celery和celery beat,配置参数见celery官方文档提供的链接,

http://docs.celeryproject.org/en/latest/tutorials/daemonizing.html#supervisord

 

6. supervisor的log

  在[program:xxx]中,如果设置了numprocs > 1, 那每个进程会使用单独的一个log文件,我们来分析下面的配置。

stdout和stderr文件都是/var/log/celery/celeryworker_celery.log

supervisor会启动两个celeryworker_celery进程(名称分别是celeryworker_celery:0和celeryworker_celery:1),并在启动时创建celeryworker_celery.log

还有celeryworker_celery.log.1 ~ celeryworker_celery.log.5这5个轮转log文件。这两个进程会分别写不同的log文件,不会写到同一个文件,

这是supervisor保证的。celeryworker_celery.log只会被其中一个进程使用,另一个进程会使用celeryworker_celery.log.xx。当celeryworker_celery.log

达到stdout_logfile_maxbytes时,它会被关闭,并重命名为celeryworker_celery.log.1,如果发现celeryworker_celery.log.1已经存在,那就把这

个已存在的celeryworker_celery.log.1重命名为celeryworker_celery.log.2,依次类推。你可以想象有多个水缸并排,在第一个水缸的顶部有一个注水

口,满了之后,将水缸向右推一个位置,即推到第二个水缸的位置,然后在第一个水缸的位置增加一个新水缸,而最右边的那个水缸被挤出队列。一个注水

口就相当于一个进程,当numprocs>1,即多个进程时,就是在numprocs个水缸上面各有一个进水口。在

http://supervisord.org/configuration.html#program-x-section-settings的配置项`stdout_logfile`中提到It is not possible for two processes

to share a single log file (stdout_logfile) when rotation (stdout_logfile_maxbytes) is enabled. This will result in the file being corrupted. 

即当设置了log rotate时,supervisor可以保证每个进程使用不同的log文件

[program:celeryworker_celery]
command=python manage.py celery worker -l info -Q celery -c 1 --settings=configs.local_default
directory=/home/workspace/gikoo/
redirect_stderr=true                     ; 将stderr重定向到stdout
startsecs=10
stopwaitsecs=30
stdout_logfile=/var/log/celery/celeryworker_celery.log
stdout_logfile_maxbytes=3KB
autostart=false
autorestart=false
numprocs=2
process_name=%(process_num)d
stdout_logfile_backups=5

7. 遇到的一些问题

不知是什么原因,用supervisor监控celery worker时,有时会出现僵尸进程,每个celery worker都是一个进程池,

每个进程池有一个main process和一组worker process,每个main process都是supervisor的子进程。但使用中

发现,有时会出现一些celery进程的父进程是1号进程,当时没有检查这些进程是main process还是worker process,

猜想是worker process的可能性比较大,原因有可能是supervisor关闭celery时,main process在没有等待worker 

process关闭的情况下就关闭了,这样worker process就没了父进程,1号进程就成了他们的父进程。由于任务的获取

都是main process与broker之间进行的,这样的话,那些1号进程下的worker process由于无法与broker通信,所以

也就不会再执行任务了(这块东西待研究)。

 

原文:http://chenxiaoyu.org/2011/05/31/python-supervisor.html

经常会碰到要写一些守护进程,简单做法放入后台:

shell> nohup python xxx.py & 

偶尔这么做还可以接受,如果一堆这样的呢?

当然还有一个问题,就是各种服务,对应的命令或者路径都不太一致,比如Apache、MySQL或者其他自行编译的工具。

如果可以统一管理这些应用,是不是很哈皮?

按照惯例现Google一把,不失所望找到一个神奇的利器。supervisor!

supervisor地址:http://supervisord.org,官方标语就是:一个进程管理工具。

安装:

sudo pip install supervisor

安装好以后,有两个可执行文件和一个配置文件(平台差异,可能路径不一致):

/usr/bin/supervisord             --  supervisor服务守护进程 

/usr/bin/supervisorctl -- supervisor服务控制程序,比如:status/start/stop/restart/update

/etc/supervisor/supervisord.conf -- 配置文件,定义服务名称以及接口等等

下面来一个示例,用web.py写一个hello的程序:

import web
urls = (     '/(.*)','hello' ) 
app = web.application(urls, globals())
class hello:     
    def GET(self, name):         
        return 'hello: ' + name 

if __name__ == '__main__':     
    app.run() 

这个时候可以直接启动这个程序了,下面来配置supervisor,加入管理。修改supervisord.conf,加入如下片段:

[program:hello]
command=python /home/smallfish/hello.py
autorstart=true
stdout_logfile=/home/smallfish/hello.log

上面的意思应该很容易懂,program后面跟服务的名称,command是程序的执行路径,autorstart是表示应用程序随supervisor的启动而启动,stdout_logfile是捕获标准输出。

到这里,基本搞定了,下面就是启动管理:

shell> sudo /etc/init.d/supervisor start   -- 启动supervisor服务 
shell> sudo supervisorctl status hello     -- 获取hello服务的状态,因为是autorstart,这里已经启动了 
hello  RUNNING    pid 1159, uptime :20:32 
shell> sudo supervisorctl stop hello       -- 停止hello服务 
hello: stopped 
shell> sudo supervisorctl stop hello       -- 再次停止hello,会有错误信息 hello: ERROR (not running) 
shell> sudo supervisorctl start hello      -- 启动hello服务 hello: started 

OK,基本的操作就是类似这个了,仔细看supervisord.conf文件里会发现有一段[unix_http_server]的配置,默认是9001端口,可以输入用户名和密码,主要用于Basic Auth认证用的。

填写一下,然后重启supervisor服务,打开浏览器输入:http://localhost:9001,如图:

sudo supervisorctl shutdown  # 关闭supervisord,会同时关闭supervisord监控的所有进程

 

posted @ 2015-11-17 00:26  奋斗终生  Views(3554)  Comments(0Edit  收藏  举报