supervisor的使用方法
简介
官网: http://supervisord.org/
supervisor是一个允许用户监视和控制在linux操作系统的进程数量的客户端/服务器系统。由python语言编写,用以监控服务器的运行,发现问题能立即自动预警及自动重启等功能
安装
#yum install supervisor
#supervisord version
supervisord的运行
supervisord -c /etc/supervisord.conf
参数-c <config-file>
可以指定配置文件运行,如不指定,则会按照以下顺序读取配置文件运行
- $CWD/supervisord.conf
- $CWD/etc/supervisord.conf
- /etc/supervisord.conf
执行后supervisord启动配置中的程序
pervisorctl
启动后可通过交互命令行的方式控制supervisord管理的程序的运行
supervisor.conf 配置文件详解
[unix_http_server]
; supervisord的基于unix socket服务配置
file=/tmp/supervisor.sock ; unix socket文件路径
chmod=0700 ; unix socket文件访问权限,默认是 0700
chown=nobody:nogroup ; unix socket文件所属用户和用户组
username=user ; 登陆使用的用户名,默认没有
password=123 ; 登陆使用的密码,默认没有
[inet_http_server] ; 使用网络方式的服务配置,同时提供一个网页端使用图形化的方式操作,不配置此项则不开启此功能port=127.0.0.1:9001 ; 服务地址和端口
username=user ; 登陆使用的用户名,默认没有
password=123 ; 登陆使用的密码,默认没有
[supervisord] ; supervisord主进程的配置
logfile=/tmp/supervisord.log ; 主进程的日志文件路径,默认为$CWD/supervisord.log
logfile_maxbytes=50MB ; 日志文件大小限制,默认50MB
logfile_backups=10 ; 日志文件缓存数量,默认为10
loglevel=info ; 日志级别,默认为info,支持debug,warn,trace
pidfile=/tmp/supervisord.pid ; pid文件路径,默认为supervisord.
pidnodaemon=false ; 是由以前台方式运行,默认为false
minfds=1024 ; 最小允许的文件描述符,默认为1024
minprocs=200 ; 最小允许的进程描述符,默认为200
umask=022 ; 进程控制权限,默认为022
user=chrism ; 进程所属用户,默认为当前用户
identifier=supervisor ; supervisord的id,默认为supervisor
directory=/tmp ; 工作目录,默认是不cd
nocleanup=true ; 是否不清除临时文件,默认为false
childlogdir=/tmp ; 默认的子log目录,默认为$TEMP
environment=KEY="value" ; 环境变量
strip_ansi=false ; 移除转义字符,默认是false
[rpcinterface:supervisor] ; rpc接口配置,支持用户修改后扩展,默认不要更改
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[supervisorctl] ; supervisorctl的配置项,supervisorctl只需要此项即可允许,supervisord的配置文件可以没有此项serverurl=unix:///tmp/supervisor.sock ; server地址,unix socket样例是unix:///tmp/supervisor.sock,网络的样例是http://127.0.0.1:9001
username=chris ; 登陆用户名,需要和服务端的配置一致
password=123 ; 登陆密码,需要和服务端的配置一致
prompt=mysupervisor ; supervisorctl里的命令行提示符
history_file=~/.sc_history ; supervisorctl命令行历史文件路径
[program:theprogramname] ; supervisord中配置的要启动的程序,名称为program:后面的部分
command=/bin/cat ; 程序命令行,包括参数
process_name=%(program_name)s ; 进程名称表达式
numprocs=1 ; 该进程的启动数量,默认是1
directory=/tmp ; 工作目录,默认是不cd
umask=022 ; 进程控制权限,默认为022
priority=999 ; 启动优先级,程序会优先从较小的优先级启动,结束程序时从较大的结束。默认999。
autostart=true ; 在supervisord启动时自动允许,默认为true
autorestart=unexpected ; 什么情况下重启,unexpected表示退出码不符合预期时自动重新启动。默认为unexpected,支持true,false
startsecs=1 ; 程序最短允许时间,默认是1秒
startretries=3 ; 最大重启尝试次数,默认是3
exitcodes=0,2 ; 符合预期的程序退出码,默认是0,2
stopsignal=QUIT ; 程序退出的信号,默认是TERM
stopwaitsecs=10 ; 最长等待SIGKILL完成退出的时间,默认是10
stopasgroup=false ; 停止时停止整个组中的进程,默认是false
killasgroup=false ; SIGKILL时杀掉整个进程组,默认是false
user=chrism ; 进程所属用户,默认为当前用户
redirect_stderr=true ; 重定向stderr到stdout,默认是false
stdout_logfile=/a/path ; stdout输出log路径,默认是没有
stdout_logfile_maxbytes=1MB ; stdout日志文件大小限制,默认50MB
stdout_logfile_backups=10 ; stdout日志文件缓存数量,默认为10
stdout_capture_maxbytes=1MB ; capture模式下stdout日志文件大小限制,默认50MB
stdout_events_enabled=false ; stdout触发写事件默认false
stderr_logfile=/a/path ; stderr输出log路径,默认是没有
stderr_logfile_maxbytes=1MB ; stderr日志文件大小限制,默认50MB
stderr_logfile_backups=10 ; stderr日志文件缓存数量,默认为10
stderr_capture_maxbytes=1MB ; capture模式下stderr日志文件大小限制,默认50MB
stderr_events_enabled=false ; stderr触发写事件默认false
environment=A="1",B="2" ; 进程额外的环境变量配置,默认没有
serverurl=AUTO ; 重写服务地址,其他工具使用,不需要配置
[eventlistener:theeventlistenername] ; eventlistener是特殊的要被supervisord启动的程序,主要进行supervisord发送的事件的处理,大多数配置与program相同,这里只注明不同的项目command=/bin/eventlistener
process_name=%(program_name)s
numprocs=1events=EVENT ; 向supervisord注册的事件类型,当这些事件被触发时,会发消息到本程序。
buffer_size=10 ; 事件队列缓冲的大小,默认10,如果队列溢出,最后一个事件被覆盖。directory=/tmpumask=022priority=-1 ; 启动优先级,默认是-1
autostart=true
autorestart=unexpectedstartsecs=1 startretries=3
exitcodes=0,2
stopsignal=QUIT
stopwaitsecs=10
stopasgroup=false
killasgroup=false
user=chrism
redirect_stderr=false ; 重定向stderr到stdout,注意这是一个bug配置项,一定不要填写该项stdout_logfile=/a/path
stdout_logfile_maxbytes=1MB
stdout_logfile_backups=10
stdout_events_enabled=false
stderr_logfile=/a/path
stderr_logfile_maxbytes=1MB
stderr_logfile_backups=10
stderr_events_enabled=false
environment=A="1",B="2"
serverurl=AUTO
[group:thegroupname] ; 程序组,可以命名程序组,其中的成员可以被统一执行start stop等操作,注意加入组后的程序,必须通过group:program的方式操作
programs=progname1,progname2 ; 组中的程序列表
priority=999 ; 组的启动优先级,默认是999
[include] ; 包含文件,supervisord支持把配置分散到多个文件中,通过包含的方式包含多个文件中的配置,可实现一个文件对应一个程序方式的管理模式
files = relative/directory/*.ini ; 文件路径
supervisorctl 命令
supervisorctl实现对supervisord的控制,支持本地unix socket方式和网络方式进行。
主要支持的命令如下:
- help 显示帮助信息
- quit 退出supervisorctl命令行
- exit 退出supervisorctl命令行
- open 连接到指定的supervisord
- version 显示版本信息
- status 显示当前程序列表中程序的状态
- start/stop/restart 启动停止重启进程
- shutdown 关闭supervisord* pid 显示进程pid
- tail 显示程序日志
- maintail 显示supervisord日志
- clear 清除日志
- fg 把一个正在运行的程序放到前台,ctrl+c退出前台
- avail 显示已经被加载的程序配置
- add/remove 激活/移除已经加载配置中的程序到程序管理表中
- reread 重新从配置文件读取配置,不自动add/remove
- update 更新配置文件,并自动add/remove
- reload 重启supervisord
事件
在supervisord的配置中,可以启动一类叫做eventlistener的程序,这类程序按照一定的规范由用户编写,他们注册关心的事件类型,当这些事件被触发时,supervisord会与eventlistener进行交互,完成数据的传递,并按照用户逻辑执行。
supervisord中支持的事件类型包括进程运行状态改变、日志输出、supervisord程序状态变化、以及预设的定时每5s/60s/3600s触发的事件。
supervisord和eventlistener之间的通信通过eventlistener的stdout、stdin传输,通过定义好的消息内容格式完成内容发送接收的流程控制,
发送到eventlistener的事件在supervisord的一个队列中缓存,这个队列的长度可以设置,若eventlistener处理速度慢,导致队列溢出,则新的事件会覆盖队列尾的最后一个事件
事件处理流程
supervisord启动,同时启动eventlistener,
eventlistener启动后进行消息循环stdout输出"READY\n",然后阻塞等待接收stdin的消息内容。当supervisord确认eventlistener为READY状态时,且有事件触发时,把消息按照协议格式发送到eventlistener的stdin中,eventlistener接收到stdin中的内容后进行处理,从中读取附加消息的长度,然后从stdin中读取指定长度的附加消息,随后按用户逻辑进行处理。处理完成之后stdout输出RESULT 2\nOK表示处理事件结束。进入下一次消息循环
eventlistener程序
eventlistener可以由任意语言编写,只要可以进行stdout,stdin的io操作即可,官方提供的样例时python编写,如下:
import sys
# 输出到stdout的函数,只有eventlistener定义的协议内容才能向stdout输出
def write_stdout(s):
sys.stdout.write(s)
sys.stdout.flush()
# 输出到stderr函数,用户消息都可以向这里输出
def write_stderr(s):
sys.stderr.write(s)
sys.stderr.flush()
# 程序入口
def main(): # 消息循环
while 1: # 告诉supervisord可以发送消息了
write_stdout('READY\n') # 阻塞等待接收消息头
line = sys.stdin.readline() # 把消息内容打印到stderr
write_stderr(line) # 接卸消息头的内容
headers = dict([ x.split(':') for x in line.split() ]) # 根据消息头中定义的附加消息的长度,从stdin中读取数据
data = sys.stdin.read(int(headers['len'])) # 打印读取的数据
write_stderr(data) # 告诉supervisord消息处理结束
write_stdout('RESULT 2\nOK')
if __name__ == '__main__':
main()