一、Supervisor 是什么

Supervisor是一款由Python语言编写的管理进程的工具。为什么要用supervisor呢?因为,相对于我们Linux传统的进程管理方式来说,它有很多的优势,我们可以编写 Listener 监听器,用来监控 supervisor 所管理子进程的状态,当子进程异常退出时,楼主写的这个listener将会触发报警。

二、具体特点说明

1. 简单

为啥简单呢?因为咱们通常管理linux进程的时候,一般来说都需要自己编写一个能够实现进程start/stop/restart/reload功能的脚本,然后丢到/etc/init.d/下面。这么做有很多不好的地方,第一我们要编写这个脚本,这就很耗时耗力了。第二,当这个进程挂掉的时候,linux不会自动重启它的,想要自动重启的话,我们还要自己写一个监控重启脚本。而supervisor则可以完美的解决这些问题。怎么解决的呢,其实supervisor管理进程,就是通过fork/exec的方式把这些被管理的进程,当作supervisor的子进程来启动。这样的话,我们只要在supervisor的配置文件中,把要管理的进程的可执行文件的路径写进去就OK了。这样就省下了我们如同linux管理进程的时候,自己写控制脚本的麻烦了。第二,被管理进程作为supervisor的子进程,当子进程挂掉的时候,父进程可以准确获取子进程挂掉的信息的,所以当然也就可以对挂掉的子进程进行自动重启了,当然重启还是不重启,也要看你的配置文件里面有木有设置autostart=true了,这是后话。

2. 精确

为啥说精确呢?因为linux对进程状态的反馈,有时候不太准确。为啥不准确?这个楼主也不知道啊,官方文档是这么说的,知道的告诉楼主一下吧,感激不尽。而supervisor监控子进程,得到的子进程状态无疑是准确的。

3. 进程组

supervisor可以对进程组统一管理,也就是说咱们可以把需要管理的进程写到一个组里面,然后我们把这个组作为一个对象进行管理,如启动,停止,重启等等操作。而linux系统则是没有这种功能的,我们想要停止一个进程,只能一个一个的去停止,要么就自己写个脚本去批量停止。

4. 集中式管理

supervisor管理的进程,进程组信息,全部都写在一个ini格式的文件里就OK了。而且,我们管理supervisor的时候的可以在本地进行管理,也可以远程管理,而且supervisor提供了一个web界面,我们可以在web界面上监控,管理进程。 当然了,本地,远程和web管理的时候,需要调用supervisor的xml_rpc接口,这个也是后话。

5. 有效性

当supervisor的子进程挂掉的时候,操作系统会直接给supervisor发信号。而其他的一些类似supervisor的工具,则是通过进程的pid文件,来发送信号的,然后定期轮询来重启失败的进程。显然supervisor更加高效。。。至于是哪些类似supervisor工具,这个楼主就不太清楚了,楼主还听说过god,director,但是没用过。有兴趣的朋友可以玩玩

6. 可扩展性

supervisor是个开源软件,牛逼点的,可以直接去改软件。不过咱们大多数人还是老老实实研究supervisot提供的接口吧,supervisor主要提供了两个可扩展的功能。一个是event机制,这个就是楼主这两天干的活要用到的东西。再一个是xml_rpc,supervisor的web管理端和远程调用的时候,就要用到它了。

7. 权限

大伙都知道linux的进程,特别是侦听在1024端口之下的进程,一般用户大多数情况下,是不能对其进行控制的。想要控制的话,必须要有root权限。而supervisor提供了一个功能,可以为supervisord或者每个子进程,设置一个非root的user,这个user就可以管理它对应的进程了。

三、Supervisor 组件

supervisord 启动配置文件寻找优先级顺序

  • 当前目录 supervisord.conf

  • 当前目录下 etc 目录 supervisord.conf

  • /etc/supervisord.conf 的配置文件

  • supervisord -c /home/supervisord.conf

1. supervisord

supervisord是supervisor的服务端程序。启动supervisor程序自身,启动supervisor管理的子进程,响应来自clients的请求,重启闪退或异常退出的子进程,把子进程的stderr或stdout记录到日志文件中,生成和处理Event

2. supervisorctl

如果说supervisord是supervisor的服务端程序,那么supervisorctl就是client端程序了。supervisorctl有一个类型shell的命令行界面,我们可以利用它来查看子进程状态,启动/停止/重启子进程,获取running子进程的列表等等。supervisorctl不仅可以连接到本机上的supervisord,还可以连接到远程的supervisord,当然在本机上面是通过UNIX socket连接的,远程是通过TCP socket连接的。supervisorctl和supervisord之间的通信,是通过xml_rpc完成的。相应的配置在[supervisorctl]块里面

3.Web Server

Web Server主要可以在界面上管理进程,Web Server其实是通过XML_RPC来实现的,可以向supervisor请求数据,也可以控制supervisor及子进程。配置在[inet_http_server]块里面

4. XML_RPC接口

这个就是远程调用的,上面的supervisorctl和Web Server就是它弄的

四、配置文件详解

[unix_http_server]

; socket 文件的路径,supervisorctl 用 XML_RPC 和 supervsord
; 通信就是通过它进行的。如果不设置的话,supervisorctl也就不用了,默认为none
file=/tmp/supervisor.sock

; 修改上面的 socket 文件的权限为0700,默认为0700
chmod=0700

; 修改上面的 socket 文件的属组为 user.group
; 默认为 supervisord 进程的用户及属组。
chown=nobody:nogroup

; 使用 supervisorc tl连接的时候,认证的用户不设置的话,默认为不需要用户
username=user

; 和上面的用户名对应的密码,可以直接使用明码,也可以使用SHA加密
;  默认不设置
password=123

; 侦听在TCP上的socket,WebServer和远程的supervisorct
; 默认为不开启
[inet_http_server]

; 侦听的IP和端口
port=127.0.0.1:9001

; 这个和上面的uinx_http_server一个样。非必须设置
username=user

; 这个也一个样。非必须设置
password=123

; 这个主要是定义supervisord这个服务端进程的一些参数的这个必须设置
; 不设supervisor就不用干活了
[supervisord]

; 这个是supervisord这个主进程的日志路径,注意和子进程的日志不搭嘎
; 默认径$CWD/supervisord.log
logfile=/tmp/supervisord.log

; 这个是上面那个日志文件的最大的大小,当超过50M的时候,会生成一个新的日志文件
; 设置为0时,表示不限制文件大小默认值是50M,非必须设置。
logfile_maxbytes=50MB

; 日志文件保持的数量,supervisor在启动程序时,会自动创建10个buckup
; 文件,用于logrotate当设置为0时,表示不限制文件的数量。默认情况下为1
logfile_backups=10

; 日志级别,有critical,error,warn,info,debug,trae,orblather等默认为info
loglevel=info

; supervisord的pid文件路径。默认为$CWD/supervisord.id
pidfile=/tmp/supervisord.pid

; 如果是true,supervisord进程将在前台运行默认为false
; 也就是后以守护进程运行
nodaemon=false

; 这个是最少系统空闲的文件描述符,低于这个值supervisor将不会启动
; 系统的件描述符在这里设置cat/proc/sys/fs/file-max默认情况下为024
minfds=1024

; 最小可用的进程描述符,低于这个值supervisor也将不会正常启动
; ulimi -u这个命令,可以查看linux下面用户的最大进程数默认为200
minprocs=200

; 进程创建文件的掩码默认为022
umask=022

; 这个参数可以设置一个非root用户,当我们以root用户启动supervisor之后
; 这里面设置的这个用户,也可以对supervisord进行管理默认情况是设置
user=chrism

; 这个参数是supervisord的标识符,主要是给XML_RPC用的。当你有多个
; upervisor的时候,而且想调用XML_RPC统一管理,就需要为每个sup
; rvisor设置不同的标识符了默认是supervisord
identifier=supervisor

; 这个参数是当supervisord作为守护进程运行的时候,设置这个参数的话,启动
; upervisord进程之前,会先切换到这个目录默认不设置。。。非必须设置
directory=/tmp

; 这个参数当为false的时候,会在supervisord进程启动的时候,把以前子
; 程产生的日志文件(路径为AUTO的情况下)清除掉。有时候咱们想要看历史日志,当
; 不想日志被清除了。所以可以设置为true默认是false,有调试需求的同学可以
; 置为true。。。非必须设置
nocleanup=true

; 当子进程日志路径为AUTO的时候,子进程日志文件的存放路径。默认路径是这个东西,
; 行下面的这个命令看看就OK了,处理的东西就默认路径非必须设置
childlogdir=/tmp

; 这个是用来设置环境变量的,supervisord在linux中启动默认继承了li
; ux的环境变量,在这里可以设置supervisord进程特有的其他环境变量。s
; pervisord启动子进程时,子进程会拷贝父进程的内存空间内容。所以设置的这
; 环境变量也会被子进程继承。小例子:environment=name="haha",age="hehe"
; 默认为不设置。。。非必须设置
environment=KEY="value"

; 这个选项如果设置为true,会清除子进程日志中的所有ANSI序列。什么是ANSI
; 列呢?就是我们的,    这些东西。默认为false。。。非必须设置
strip_ansi=false

; 这个选项是给XML_RPC用的,当然你如果想使用supervisord或者web
; erver这个选项必须要开启的
[rpcinterface:supervisor]

; 这个主要是针对supervisorctl的一些配置
[supervisorctl]

; 这个是supervisorctl本地连接supervisord的时候,本地UNI
; socket路径,注意这个是和前面的[unix_http_server]对应的
; 认值就是unix:;/tmp/supervisor.sock。。非必须设置
serverurl=unix:;/tmp/supervisor.sock

; 这个是supervisorctl远程连接supervisord的时候,用到的TC
; socket路径注意这个和前面的[inet_http_server]对应默认就
; http:;127.0.0.1:9001。。。非必须项
serverurl=http:;127.0.0.1:9001

; 用户名默认空。。非必须设置
username=chris

; 密码默认空。。非必须设置
password=123

; 输入用户名密码时候的提示符默认supervisor。。非必须设置
prompt=mysupervisor

; 这个参数和shell中的history类似,我们可以用上下键来查找前面执行过的命
; 默认是nofile的。。所以我们想要有这种功能,必须指定一个文件。。。非必须设
history_file=~/.sc_history

; 咱们要管理的子进程
[program:theprogramname]

; 这个就是我们的要启动进程的命令路径了,可以带参数例子:/home/test.py
; a'hehe'有一点需要注意的是,我们的command只能是那种在终端运行的进
; ,不能是守护进程。这个想想也知道了,比如说command=servicehtt
; dstart。httpd这个进程被linux的service管理了,我们的su
; ervisor再去启动这个命令这已经不是严格意义的子进程了。这个是个必须设置的
command=/bin/cat

; 这个是进程名,如果我们下面的numprocs参数为1的话,就不用管这个参数了,它
; 认值%(program_name)s也就是上面的那个program冒号后面的名
; ,但是如果numprocs为多个的话,那就不能这么干了。想想也知道,不可能每个
; 程都用同一个进程名吧。
process_name=%(program_name)s

; 启动进程的数目。当不为1时,就是进程池的概念,注意process_name的设置
; 认为1。。非必须设置
numprocs=1

; 进程运行前,会前切换到这个目录默认不设置。。。非必须设置
directory=/tmp

; 进程掩码,默认none,非必须
umask=022

; 子进程启动关闭优先级,优先级低的,最先启动,关闭的时候最后关闭默认值为999。。
; 必须设置
priority=999

; 如果是true的话,子进程将在supervisord启动后被自动启动默认就是tr
; e。。非必须设置
autostart=true

; 这个是设置子进程挂掉后自动重启的情况,有三个选项,false,unexpecte
; 和true。如果为false的时候,无论什么情况下,都不会被重新启动,如果为u
; expected,只有当进程的退出码不在下面的exitcodes里面定义的退出
; 的时候,才会被自动重启。当为true的时候,只要子进程挂掉,将会被无条件的重启
autorestart=unexpected

; 这个选项是子进程启动多少秒之后,此时状态如果是running,则我们认为启动成功
; 默认值为1。。非必须设置
startsecs=1

; 当进程启动失败后,最大尝试启动的次数。。当超过3次后,supervisor将把此
; 程的状态置为FAIL默认值为3。。非必须设置
startretries=3

; 注意和上面的的autorestart=unexpected对应。。exitcod
; s里面的定义的退出码是expected的。
exitcodes=0,2

; 进程停止信号,可以为TERM,HUP,INT,QUIT,KILL,USR1,or
; SR2等信号默认为TERM。。当用设定的信号去干掉进程,退出码会被认为是exp
; cted非必须设置
stopsignal=QUIT

; 这个是当我们向子进程发送stopsignal信号后,到系统返回信息给superv
; sord,所等待的最大时间。超过这个时间,supervisord会向该子进程发
; 一个强制kill的信号。默认为10秒。。非必须设置
stopwaitsecs=10

; 这个东西主要用于,supervisord管理的子进程,这个子进程本身还有子进程。
; 么我们如果仅仅干掉supervisord的子进程的话,子进程的子进程有可能会变
; 孤儿进程。所以咱们可以设置可个选项,把整个该子进程的整个进程组都干掉。设置为t
; ue的话,一般killasgroup也会被设置为true。需要注意的是,该选项
; 送的是stop信号默认为false。。非必须设置。。
stopasgroup=false

; 这个和上面的stopasgroup类似,不过发送的是kill信号
killasgroup=false

; 如果supervisord是root启动,我们在这里设置这个非root用户,可以
; 来管理该program默认不设置。。。非必须设置项
user=chrism

; 如果为true,则stderr的日志会被写入stdout日志文件中默认为fals
; ,非必须设置
redirect_stderr=true

; 子进程的stdout的日志路径,可以指定路径,AUTO,none等三个选项。设置
; none的话,将没有日志产生。设置为AUTO的话,将随机找一个地方生成日志文件
; 而且当supervisord重新启动的时候,以前的日志文件会被清空。当redi
; ect_stderr=true的时候,sterr也会写进这个日志文件
stdout_logfile=/a/path

; 日志文件最大大小,和[supervisord]中定义的一样。默认为50
stdout_logfile_maxbytes=1MB

; 和[supervisord]定义的一样。默认10
stdout_logfile_backups=10

; 这个东西是设定capture管道的大小,当值不为0的时候,子进程可以从stdou
; 发送信息,而supervisor可以根据信息,发送相应的event。默认为0,
; 0的时候表达关闭管道。。。非必须项
stdout_capture_maxbytes=1MB

; 当设置为ture的时候,当子进程由stdout向文件描述符中写日志的时候,将触发
; upervisord发送PROCESS_LOG_STDOUT类型的event默
; 为false。。。非必须设置
stdout_events_enabled=false

; 这个东西是设置stderr写的日志路径,当redirect_stderr=tru
; 。这个就不用设置了,设置了也是白搭。因为它会被写入stdout_logfile
; 同一个文件中默认为AUTO,也就是随便找个地存,supervisord重启被清
; 。。非必须设置
stderr_logfile=/a/path

; 这个出现好几次了,就不重复了
stderr_logfile_maxbytes=1MB

; 这个也是
stderr_logfile_backups=10

; 这个一样,和stdout_capture一样。默认为0,关闭状态
stderr_capture_maxbytes=1MB

; 这个也是一样,默认为false
stderr_events_enabled=false

; 这个是该子进程的环境变量,和别的子进程是不共享的
environment=A="1",B="2"

; 
serverurl=AUTO

; 这个东西其实和program的地位是一样的,也是suopervisor启动的子进
; ,不过它干的活是订阅supervisord发送的event。他的名字就叫lis
; ener了。我们可以在listener里面做一系列处理,比如报警等等楼主这两天
; 的活,就是弄的这玩意
[eventlistener:theeventlistenername]

; 这个和上面的program一样,表示listener的可执行文件的路径
command=/bin/eventlistener

; 这个也一样,进程名,当下面的numprocs为多个的时候,才需要。否则默认就OK
; 
process_name=%(program_name)s

; 相同的listener启动的个数
numprocs=1

; event事件的类型,也就是说,只有写在这个地方的事件类型。才会被发送
events=EVENT

; 这个是event队列缓存大小,单位不太清楚,楼主猜测应该是个吧。当buffer超
; 10的时候,最旧的event将会被清除,并把新的event放进去。默认值为10
; 。非必须选项
buffer_size=10

; 进程执行前,会切换到这个目录下执行默认为不切换。。。非必须
directory=/tmp

; 淹没,默认为none,不说了
umask=022

; 启动优先级,默认-1,也不扯了
priority=-1

; 是否随supervisord启动一起启动,默认true
autostart=true

; 是否自动重启,和program一个样,分true,false,unexpecte
; 等,注意unexpected和exitcodes的关系
autorestart=unexpected

; 也是一样,进程启动后跑了几秒钟,才被认定为成功启动,默认1
startsecs=1

; 失败最大尝试次数,默认3
startretries=3

; 期望或者说预料中的进程退出码,
exitcodes=0,2

; 干掉进程的信号,默认为TERM,比如设置为QUIT,那么如果QUIT来干这个进程
; 么会被认为是正常维护,退出码也被认为是expected中的
stopsignal=QUIT

; maxnumsecstowaitb4SIGKILL(default10)
stopwaitsecs=10

; sendstopsignaltotheUNIXprocessgroup(defa
; ltfalse)
stopasgroup=false

; SIGKILLtheUNIXprocessgroup(deffalse)
killasgroup=false

; 设置普通用户,可以用来管理该listener进程。默认为空。。非必须设置
user=chrism

; 为true的话,stderr的log会并入stdout的log里面默认为fals
; 。。。非必须设置
redirect_stderr=true

; 这个不说了,好几遍了
stdout_logfile=/a/path

; 这个也是
stdout_logfile_maxbytes=1MB

; 这个也是
stdout_logfile_backups=10

; 这个其实是错的,listener是不能发送event
stdout_events_enabled=false

; 这个也是
stderr_logfile=/a/path

; 这个也是
stderr_logfile_maxbytes=1MB

; 这个不说了
stderr_logfile_backups

; 这个也是错的,listener不能发送event
stderr_events_enabled=false

; 这个是该子进程的环境变量默认为空。。。非必须设置
environment=A="1",B="2"

; overrideserverurlcomputation(childutils)
serverurl=AUTO

; 这个东西就是给programs分组,划分到组里面的program。我们就不用一个
; 个去操作了我们可以对组名进行统一的操作。注意:program被划分到组里面之后
; 就相当于原来的配置从supervisor的配置文件里消失了。。。supervi
; or只会对组进行管理,而不再会对组里面的单个program进行管理了
[group:thegroupname]

; 组成员,用逗号分开这个是个必须的设置项
programs=progname1,progname2

; 优先级,相对于组和组之间说的默认999。。非必须选项
priority=999

; 这个东西挺有用的,当我们要管理的进程很多的时候,写在一个文件里面就有点大了。我们
; 以把配置信息写到多个文件中,然后include过来
[include]
files=relative/directory/*.ini

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐