python-supervisor

来源:
http://blog.csdn.net/xyang81/article/details/51555473
http://blog.csdn.net/chenyulancn/article/details/52789565

Supervisor(http://supervisord.org/)是用Python开发的一个client/server服务,是Linux/Unix系统下的一个进程管理工具,不支持Windows系统。

它可以很方便的监听、启动、停止、重启一个或多个进程。用Supervisor管理的进程,当一个进程意外被杀死,supervisort监听到进程死后,会自动将它重新拉起,很方便的做到进程自动恢复的功能,不再需要自己写shell脚本来控制。

安装 pip install supervisor

配置: 生成默认配置文件/etc/supervisor/supervisord.conf

mkdir /etc/supervisor
echo_supervisord_conf > /etc/supervisor/supervisord.conf

组成:

supervisord 服务端
supervisorctl 客户端

配置参数
supervisor的配置参数较多,下面介绍一下常用的参数配置,详细的配置及说明,请参考官方文档介绍。
注:分号(;)开头的配置表示注释

[unix_http_server]
file=/tmp/supervisor.sock   ;UNIX socket 文件,supervisorctl 会使用
;chmod=0700                 ;socket文件的mode,默认是0700
;chown=nobody:nogroup       ;socket文件的owner,格式:uid:gid

;[inet_http_server]         ;HTTP服务器,提供web管理界面
;port=127.0.0.1:9001        ;Web管理后台运行的IP和端口,如果开放到公网,需要注意安全性
;username=user              ;登录管理后台的用户名
;password=123               ;登录管理后台的密码

[supervisord]
logfile=/tmp/supervisord.log ;日志文件,默认是 $CWD/supervisord.log
logfile_maxbytes=50MB        ;日志文件大小,超出会rotate,默认 50MB,如果设成0,表示不限制大小
logfile_backups=10           ;日志文件保留备份数量默认10,设为0表示不备份
loglevel=info                ;日志级别,默认info,其它: debug,warn,trace
pidfile=/tmp/supervisord.pid ;pid 文件
nodaemon=false               ;是否在前台启动,默认是false,即以 daemon 的方式启动
minfds=1024                  ;可以打开的文件描述符的最小值,默认 1024
minprocs=200                 ;可以打开的进程数的最小值,默认 200

[supervisorctl]
serverurl=unix:///tmp/supervisor.sock ;通过UNIX socket连接supervisord,路径与unix_http_server部分的file一致
;serverurl=http://127.0.0.1:9001 ; 通过HTTP的方式连接supervisord

; [program:xx]是被管理的进程配置参数,xx是进程的名称
[program:xx]
command=/opt/apache-tomcat-8.0.35/bin/catalina.sh run  ; 程序启动命令
autostart=true       ; 在supervisord启动的时候也自动启动
startsecs=10         ; 启动10秒后没有异常退出,就表示进程正常启动了,默认为1秒
autorestart=true     ; 程序退出后自动重启,可选值:[unexpected,true,false],默认为unexpected,表示进程意外杀死后才重启
startretries=3       ; 启动失败自动重试次数,默认是3
user=tomcat          ; 用哪个用户启动进程,默认是root
priority=999         ; 进程启动优先级,默认999,值小的优先启动
redirect_stderr=true ; 把stderr重定向到stdout,默认false
stdout_logfile_maxbytes=20MB  ; stdout 日志文件大小,默认50MB
stdout_logfile_backups = 20   ; stdout 日志文件备份数,默认是10
; stdout 日志文件,需要注意当指定目录不存在时无法正常启动,所以需要手动创建目录(supervisord 会自动创建日志文件)
stdout_logfile=/opt/apache-tomcat-8.0.35/logs/catalina.out
;stdout_events_enabled=false   ; 当设置为ture的时候,当子进程由stdout向文件描述符中写日志的时候,将
                                 触发supervisord发送PROCESS_LOG_STDOUT类型的event
                                 默认为false。。。非必须设置
;stderr_logfile=/a/path        ; 这个东西是设置stderr写的日志路径,当redirect_stderr=true。这个就不用
                                 设置了,设置了也是白搭。因为它会被写入stdout_logfile的同一个文件中
                                 默认为AUTO,也就是随便找个地存,supervisord重启被清空。。非必须设置
;stderr_logfile_maxbytes=1MB   ; 这个出现好几次了,就不重复了
;stderr_logfile_backups=10     ; 这个也是
;stderr_capture_maxbytes=1MB   ; 这个一样,和stdout_capture一样。 默认为0,关闭状态
;stderr_events_enabled=false   ; 这个也是一样,默认为false
;environment=A="1",B="2"       ; 这个是该子进程的环境变量,和别的子进程是不共享的
stopasgroup=false     ;默认为false,进程被杀死时,是否向这个进程组发送stop信号,包括子进程
killasgroup=false     ;默认为false,向进程组发送kill信号,包括子进程

;[group:thegroupname]  ;这个东西就是给programs分组,划分到组里面的program。我们就不用一个一个去操作了
                         我们可以对组名进行统一的操作。 注意:program被划分到组里面之后,就相当于原来
                         的配置从supervisor的配置文件里消失了。。。supervisor只会对组进行管理,而不再
                         会对组里面的单个program进行管理了
;programs=progname1,progname2  ; 组成员,用逗号分开
                                 这个是个必须的设置项
;priority=999                  ; 优先级,相对于组和组之间说的
                                 默认999。。非必须选项

;包含其它配置文件
[include]
files = relative/directory/*.ini    ;可以指定一个或多个以.ini结束的配置文件

进程管理配置参数,不建议全都写在supervisord.conf文件中,应该每个进程写一个配置文件放在include指定的目录下包含进supervisord.conf文件中。
1> 创建/etc/supervisor/config.d目录,用于存放进程管理的配置文件
2> 修改/etc/supervisor/supervisord.conf中的include参数,将/etc/supervisor/conf.d目录添加到include中

[include]
files = /etc/supervisor/config.d/*.ini
[program:tomcat]
command=/opt/apache-tomcat-8.0.35/bin/catalina.sh run
stdout_logfile=/opt/apache-tomcat-8.0.35/logs/catalina.out
autostart=true
autorestart=true
startsecs=5
priority=1
stopasgroup=true
killasgroup=true

启动 (服务端):

supervisord -c /etc/supervisor/supervisord.conf # 指定配置文件目录

控制进程(客户端)

  • 交互终端: supervisorctl

  • bash 终端:

supervisorctl status   查看状态
supervisorctl update  更新配置
pervisorctl stop program_name  停止某个进程 
supervisorctl start program_name  启动某个进程, 不停supervisor 添加program
supervisorctl restart program_name  重启某个进程
supervisorctl stop all  关闭所有进程
supervisorctl reload    重新启动配置中的所有程序
supervisorctl update
  • web管理:
    出于安全考虑,默认配置是没有开启web管理界面,需要修改supervisord.conf配置文件打开http访权限,将下面的配置:
;[inet_http_server]         ; inet (TCP) server disabled by default
;port=127.0.0.1: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))

修改成:

[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))

port:绑定访问IP和端口,这里是绑定的是本地IP和9001端口
username:登录管理后台的用户名
password:登录管理后台的密码

开机启动:

http://blog.csdn.net/xyang81/article/details/51555473

注意:

修改ip后
supervisorctl要和supervisord配置文件一致才能正常启动
supervisord -c /etc/supervisor/supervisord.conf # 指定配置文件目录
supervisorctl -c /etc/supervisor/supervisord.conf # 指定配置文件目录

参考:https://stackoverflow.com/questions/18859063/supervisor-socket-error-issue

event

为监控程序添加通知提醒 或者 自定义一些别的操作
官网
参考博客:
http://talk.withme.me/?p=318
https://www.cnblogs.com/linxiyue/p/8121982.html

event listener本身也是作为supervisor的子程序运行的。事件通知协议的实现基于event listener子程序的stdin和stdout。supervisor发送特定格式的信息到event listener的stdin,然后从event listener的stdout获得特定格式的输出,从而形成一个请求/应答循环。

先来看下怎么配置event listener:
来自http://blog.51cto.com/lixcto/1540169

;[eventlistener:theeventlistenername] ;这个东西其实和program的地位是一样的,也是suopervisor启动的子进程,不过它干的活是订阅supervisord发送的event。
                                       
;command=/bin/eventlistener    ; 这个和上面的program一样,表示listener的可执行文件的路径
;process_name=%(program_name)s ; 这个也一样,进程名,当下面的numprocs为多个的时候,才需要。否则默认就
                                 OK了
;numprocs=1                    ; 相同的listener启动的个数
;events=EVENT                  ; event事件的类型,也就是说,只有写在这个地方的事件类型。才会被发送
                      
                                 
;buffer_size=10                ; 这个是event队列缓存大小,单位不太清楚,楼主猜测应该是个吧。当buffer
                                 超过10的时候,最旧的event将会被清除,并把新的event放进去。
                                 默认值为10。。非必须选项
;directory=/tmp                ; 进程执行前,会切换到这个目录下执行
                                 默认为不切换。。。非必须
;umask=022                     ; 淹没,默认为none,不说了
;priority=-1                   ; 启动优先级,默认-1,也不扯了
;autostart=true                ; 是否随supervisord启动一起启动,默认true
;autorestart=unexpected        ; 是否自动重启,和program一个样,分true,false,unexpected等,注意
                                  unexpected和exitcodes的关系
;startsecs=1                   ; 也是一样,进程启动后跑了几秒钟,才被认定为成功启动,默认1
;startretries=3                ; 失败最大尝试次数,默认3
;exitcodes=0,2                 ; 期望或者说预料中的进程退出码,
;stopsignal=QUIT               ; 干掉进程的信号,默认为TERM,比如设置为QUIT,那么如果QUIT来干这个进程 那么会被认为是正常维护,退出码也被认为是expected中的
;stopwaitsecs=10               ; max num secs to wait b4 SIGKILL (default 10)
;stopasgroup=false             ; send stop signal to the UNIX process group (default false)
;killasgroup=false             ; SIGKILL the UNIX process group (def false)
;user=chrism                   ;设置普通用户,可以用来管理该listener进程。
                                默认为空。。非必须设置
;redirect_stderr=true          ; 为true的话,stderr的log会并入stdout的log里面
                                默认为false。。。非必须设置
;stdout_logfile=/a/path        ; 这个不说了,好几遍了
;stdout_logfile_maxbytes=1MB   ; logfile的最大字节数
;stdout_logfile_backups=10     ; logfile文件数, 超过循环覆盖
;stdout_events_enabled=false   ; (listener本身发送stdout enent?  可以再起一个listenser作为监控的监控?) 
;stderr_logfile=/a/path        ; 错误输出的位置
;stderr_logfile_maxbytes=1MB   ; 
;stderr_logfile_backups=10        ; 
;stderr_events_enabled=false   ; 
;environment=A="1",B="2"       ; 这个是该子进程的环境变量  默认为空。。。非必须设置
;serverurl=AUTO                ; override serverurl computation (childutils)

Event Notification Protocol:

通信数据
Header Tokens

当出现异常时(配置里events= 决定发送哪些消息) supervisord 会给listener process发送消息, listener先会通过stdin接收一个Header Tokens, 如示例,以空格分隔的key:value 对, 以 '\n'结尾, 所以用 sys.stdin.readline()来获取一行

ver:3.0 server:supervisor serial:21 pool:listener poolserial:10 eventname:PROCESS_COMMUNICATION_STDOUT len:54
Key Description Example
ver The event system protocol version 协议版本 3.0
server The identifier of the supervisord sending the event (see config file <tt class="docutils literal">[supervisord]</tt> section <tt class="docutils literal">identifier</tt> value. supervisor的标识符,由[supervisord]块中的identifier选项设置。
serial An integer assigned to each event. No two events generated during the lifetime of a supervisord process will have the same serial number. The value is useful for functional testing and detecting event ordering anomalies. event的序列号 独一无二 30
pool The name of the event listener pool which generated this event. listener的pool的名字。当配置numprocs > 1时 myeventpool
poolserial An integer assigned to each event by the eventlistener pool which it is being sent from. No two events generated by the same eventlister pool during the lifetime of a supervisord process will have the same <tt class="docutils literal">poolserial</tt> number. This value can be used to detect event ordering anomalies. event在pool中的的序列号, 每个listener进程单独计数的event 30
eventname The specific event type name (see Event Types) event类型名称 这个很重要,被配置里envent选项中包含 TICK_5
len An integer indicating the number of bytes in the event payload, aka the <tt class="docutils literal">PAYLOAD_LENGTH</tt> header后面的body字节长度。 22
event payload

紧跟Header Tokens还发送了 the event payload, 即body, 用来描述envent具体对应了哪一个program进程, listener也是通过stdin来获取,但是这次是根据字节数来读sys.stdin.read(int(headers['len']))

enventname=PROCESS_COMMUNICATION_STDOUT时格式如下(格式由eventType来决定,):

processname:foo groupname:bar pid:123
This is the data that was sent between the tags
event type

Supervisord支持的Event有:

    PROCESS_STATE 进程状态发生改变
    PROCESS_STATE_STARTING 进程状态从其他状态转换为正在启动(Supervisord的配置项中有startsecs配置项,是指程序启动时需要程序至少稳定运行x秒才认为程序运行正常,在这x秒中程序状态为正在启动)
    PROCESS_STATE_RUNNING 进程状态由正在启动转换为正在运行
    PROCESS_STATE_BACKOFF 进程状态由正在启动转换为失败
    PROCESS_STATE_STOPPING 进程状态由正在运行转换为正在停止
    PROCESS_STATE_EXITED 进程状态由正在运行转换为退出
    PROCESS_STATE_STOPPED 进程状态由正在停止转换为已经停止(exited和stopped的区别是exited是程序自行退出,而stopped为人为控制其退出)
    PROCESS_STATE_FATAL 进程状态由正在运行转换为失败
    PROCESS_STATE_UNKNOWN 未知的进程状态
    REMOTE_COMMUNICATION 使用Supervisord的RPC接口与Supervisord进行通信
    PROCESS_LOG 进程产生日志输出,包括标准输出和标准错误输出
    PROCESS_LOG_STDOUT 进程产生标准输出
    PROCESS_LOG_STDERR 进程产生标准错误输出
    PROCESS_COMMUNICATION 进程的日志输出包含 和
    PROCESS_COMMUNICATION_STDOUT 进程的标准输出包含 和
    PROCESS_COMMUNICATION_STDERR 进程的标准错误输出包含 和
    SUPERVISOR_STATE_CHANGE_RUNNING Supervisord启动
    SUPERVISOR_STATE_CHANGE_STOPPING Supervisord停止
    TICK_5 每隔5秒触发
    TICK_60 每隔60秒触发
    TICK_3600 每隔3600触发
    PROCESS_GROUP Supervisord的进程组发生变化
    PROCESS_GROUP_ADDED 新增了Supervisord的进程组
    PROCESS_GROUP_REMOVED 删除了Supervisord的进程组
Event Listener States

Listener有三种状态, 由supervisor服务端来维护,Listener通过stdout来告诉 supervisor自己的状态, 以便supervisor决定下一条消息的发送时间

Name Description
ACKNOWLEDGED The event listener has acknowledged(accepted or rejected) an event send.
READY Event notificatons may be sent to this event listener
BUSY Event notifications may not be sent to this event listener.
  • supervisor调起listener, listener就处于ACKNOWLEDGED状态了;
  • listener通过sys.stdout.write('READY\n') 来通知supervisor自己处于READY状态;
  • supervisor 为listener发送消息, 发送完supervisor就把listener标记为BUSY状态;
  • listener处理完, 发送write_stdout('RESULT 2\nOK')表示自己处理成功了, 或者write_stdout('RESULT 2\nFAIL') 来表示自己处理失败了(这里前面一行RESULT 2, 是为了告诉supervisor这个是给你的, 不是普通的log)
  • supervisor接收到 RESULT 2\nOK 或 RESULT 2\nFAIL 把listener置为ACKNOWLEDGED, 然后决定是重新发送一次还是发送下一条
  • listener exit(autostart=true配置下 会被supervisor无限次调起 )或 加一个while 1, 发送 READY\n' 告诉supervisor开始新一轮

listener code:

import sys

def write_stdout(s):
    # only eventlistener protocol messages may be sent to stdout
    sys.stdout.write(s)
    sys.stdout.flush()

def write_stderr(s):
    sys.stderr.write(s)
    sys.stderr.flush()

def main():
    while 1:
        # transition from ACKNOWLEDGED to READY
        write_stdout('READY\n')

        # read header line and print it to stderr
        line = sys.stdin.readline()
        write_stderr(line)

        # read event payload and print it to stderr
        headers = dict([ x.split(':') for x in line.split() ])
        data = sys.stdin.read(int(headers['len']))
        write_stderr(data)

        # transition from READY to ACKNOWLEDGED
        write_stdout('RESULT 2\nOK')

if __name__ == '__main__':
    main()

补充:

今天发现supervisorctl 报错: unix:///tmp/supervisor.sock no such file

找到了https://blog.csdn.net/qq_28885149/article/details/79364685

额, 想起来最近tmp临时文件满了, 清了一次, 导致supervisor文件丢失了
为了避免这个问题, 需要重启 supervisord, 我是用supervisord来监控yarn-cluster模式的spark-streaming的,得一个个手动kill了。。。。

然后修改下文件配置 supervisord.conf:

1,   /tmp/supervisor.sock  改为 ./tmp/supervisor.sock
2,  /tmp/supervisord.log  改为  ./tmp/supervisord.log
3,  /tmp/supervisord.pid  改为  ./tmp/supervisor.pid

创建supervisor.sock

touch ./tmp/supervisor.sock

重启 supervisord -c supervisord.conf

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容