tornado 环境部署 supervisor配置

这个直接安装在root 角色下面,不是在虚拟环境的,虚拟环境知识和程序有关

1、下载安装

# 使用 pip 装会出问题的, 最好用yum 安装 可以直接使用 systemctl 会有问题
#sudo pip install supervisor

yum -y install supervisor

2、创建配置文件

这一步是生成supervisor 的配置文件

echo_supervisord_conf > /etc/supervisord.conf

3、修改 里面的配置文件

[include]
files = relative/directory/*.ini

修改为

[include]
files = /etc/supervisor/*.conf

这样配置的说明,相当于给这个文件进行扩展了不然太长

4、在etc 下面创建 supervisor目录,创建xxx.conf

mkdir /etc/supervisor
touch yabg.conf

启动的时候就会找到这个文件

5、填写配置信息

[group:tornadoes]
programs=tornado-8000,tornado-8001,tornado-8002

[program:tornado-8000]
command=/home/python/.virtualenvs/tornado_py2/bin/python /home/python/Documents/demo/chat    /server.py --port=8000
directory=/home/python/Documents/demo/chat
user=python
autorestart=true
redirect_stderr=true
stdout_logfile=/home/python/tornado.log
loglevel=info

[program:tornado-8001]
command=/home/python/.virtualenvs/tornado_py2/bin/python /home/python/Documents/demo/chat    /server.py --port=8001
directory=/home/python/Documents/demo/chat
user=python
autorestart=true
redirect_stderr=true
stdout_logfile=/home/python/tornado.log
loglevel=info

[program:tornado-8002]
command=/home/python/.virtualenvs/tornado_py2/bin/python /home/python/Documents/demo/chat    /server.py --port=8002
directory=/home/python/Documents/demo/chat
user=python
autorestart=true
redirect_stderr=true
stdout_logfile=/home/python/tornado.log     存放日志的地方(标准日志输出)
loglevel=info

说明:

command 前面的是python 解释权所在的位置(这里为设置的虚拟的目录位置), 后面是tornado 的 main.py 所在的位置 –port 监听端口
directory 文件所在的目录
user 用户
上面有多个不同端口,直接监听不同的端口
现在来看下生成目前的配置

[yangxiaodong@dev conf.d]$ cat ohho.conf 
[program:ohho]

user=www
command=/data/env/yang/bin/python  /data/websites/work/main.py

process_name=%(program_name)s ; process_name expr (default %(program_name)s)
numprocs=1                    ; number of processes copies to start (def 1)
startretries=2                ;
stopsignal=TERM               ; signal used to kill process (default TERM)
redirect_stderr=true          ; redirect proc stderr to stdout (default false)
directory=/data/websites/SDevelop/
autostart=true
stdout_logfile = /data/websites/logs/ohho.out
stdout_logfile_maxbytes=100MB
stdout_logfile_backups=10
stderr_logfile = /data/websites/logs/ohho.err
stderr_logfile_maxbytes=100MB
stderr_logfile_backups=10

直接启动报错

systemctl start supervisord.service
Failed to start supervisord.service: Unit not found.

解决办法:

最好使用 yum 安装就可以啦
使用配置文件启动

supervisord -c /etc/supervisord.conf

查看是不是启动了

ps aux | grep supervisord

supervisorctl

我们可以利用supervisorctl来管理supervisor。

supervisorctl

status # 查看程序状态
stop tornadoes:* # 关闭 tornadoes组 程序
start tornadoes:* # 启动 tornadoes组 程序
restart tornadoes:* # 重启 tornadoes组 程序
update # 重启配置文件修改过的程序

Ubuntu16.04 中 supervisor 安装到使用

supervisor 进程管理是可以让进程在后台运行,而不占用控制台影响使用。

1. 安装 supervisor

sudo apt install supervisor

2. 添加进程

supervisor 可以将每个进程分别写成一个文件,supervisor 的进程文件放在 /etc/supervisor/conf.d/ 目录下,本例创建 test.conf 进程配置文件。其中 program 为要运行的进程的名称, command 为要执行的命令,directory 要执行命令的目录,user 运行的用户。

[program:test]
command=php artisan queue:work
directory=/var/www/html/wisdom
user=ubuntu

3. 启动进程

首先要重启supervisor,让配置文件生效

sudo supervisorctl reload

然后启动进程

sudo supervisorctl start test

完成。

supervisor集中化管理web工具cesi

linux进程管理器supervisor是会经常被用到的,但服务器多了之后,每个服务器的进程也不方便管理。同时,supervisor自带的web界面比较简陋,所以尝试了一下官网推荐的一些第三方开源软件,推荐一下这个cesi。

最终效果如下:

未分类

未分类

1. 首先是关于supervisor

通过apt或pip安装都可以

apt-get install supervisor
#pip install supervisor
echo_supervisord_conf > /etc/supervisor/supervisord.conf

关于supervisor配置文件

[unix_http_server]
#这里配置是否用unix socket通信来让supervisor与supervisorctl做通信

[inet_http_server]
#这里是用的http的方式做通信

[supervisorctl]
#这里选择supervisorctl到底用以上两种中的哪种方式来与supervisor通信,选择一种即可,记得填写密码

[program:pro_name]
stdout_logfile = {path}
redirect_stderr = true  ;让stderr也写入stdout中

常用操作

supervisorctl reload #重启加载supervisor配置文件
supervisorctl update #只增加新增的配置文件

2. 关于cesi

项目地址:https://github.com/Gamegos/cesi

安装cesi

apt-get install sqlite3 python python-flask
git clone https://github.com/Gamegos/cesi
cd cesi
sqlite3 ./userinfo.db < userinfo.sql
cp cesi.conf /etc/cesi.conf

配置cesi.conf,我的配置如下,一看就懂了

[node:118]
username = ***
password = ***
host = 127.0.0.1
port = 9001

[node:calmkart]
username = ***
password = ***
host = 45.76.71.69
port = 9001

[node:121]
username = ***
password = ***
host = *.*.*.121
port = 9001

[environment:my_env]
members = 118,calmkart,121

[cesi]
database = /root/cesi/userinfo.db
activity_log = /var/log/cesi.log
host = 0.0.0.0

用supervisor运行cesi,配置文件如下

[program:cesi]
directory = /root/cesi/cesi/
command = python web.py
autostart = true
startsecs = 5
autorestart = true
startretries = 3
user = root
redirect_stderr = true
stdout_logfile = /var/log/cesi1.log

开启任务

supervisorctl start cesi

默认账号密码:admin,admin
端口需要改的自己去web.py里面改

you get it

本测试服地址:
http://cesi.calmkart.com

此外,其他常用的supervisor相关第三方工具还有

  • suponoff
  • gosuv

supervisor 和gunicorn部署django项目

安装使用到的基本软件nginx、supervisor、gunicorn

vi /etc/supervisor/conf.d/django_project.conf
[program:django_project]
command=gunicorn xxx.wsgi:application -b 127.0.0.1:8080 -w 8
user=user #当前用户
directory=/home/user/django_project
stdout_logfile=/tmp/var/logs/supervisor/%(program_name)s-stdout.log
stderr_logfile=/tmp/var/logs/supervisor/%(program_name)s-stderr.log
killasgroup=true
stopasgroup=true
autorstart=true
autorestart=true

# rq队列的配置

[program:rqworker]
command=python manage.py rqworker default low
user=user
directory=/home/django_project/platform
stdout_logfile=/tmp/var/logs/supervisor/%(program_name)s-stdout.log
stderr_logfile=/tmp/var/logs/supervisor/%(program_name)s-stderr.log
killasgroup=true
stopasgroup=true
autorstart=true
autorestart=true```

再在nginx配置中的location,添加

proxy_pass http://127.0.0.1:8080;

另外静态文件的代理可以添加下面的配置

location /static/ {

alias /django_project/statics/;

}

Ubuntu部署python3-flask-nginx-uwsgi-supervisor完美

安装虚拟环境

$ pip install virtualenv
$ pip install virtualenvwrapper

把虚拟机环境添加环境变量中

这个最好find / -name virtualenvwrapper.sh 看下位置

$ vi .bashrc
if [ -f /usr/local/bin/virtualenvwrapper.sh ]; then
    export WORKON_HOME=$HOME/.virtualenvs
    source /usr/local/bin/virtualenvwrapper.sh
fi

为flask项目创建一个虚拟环境

$ mkvirtualenv --python=python3 flask  #flask这个名字可以按自己需求修改,我项目是需要python3。所以选择 --python=python3,如果需要python2可以不加这个。
$ deactivate  #安装完虚拟环境后,先退出这个虚拟环境。

安装mysql数据库,安装数据这个没什么好提的网上有很多详细教程

$ apt install mysql-server mysql-client
$ apt install libmysqld-dev

安装nginx

$ apt install nginx   #这个安装也比较简单

安装supervisor

需要是python2 暂时不支持python3,这里有时候会遇到坑。pip install –upgrade pip 看看现在pip是什么版本。

$ vi /usr/local/bin/pip #如果发现pip是python3,不要慌用这个命令把第一行的python3修改python2 即可,如果是python2就无视这步
$ pip install supervisor #安装supervisor

安装uwsgi

需要注意flask项目需要的环境 选择python3 还是python2.

这个我的项目是python3,如果是python2创建虚拟环境就用python2。具体可以看上面的为项目创建虚拟环境

$ workon flask  #进入虚拟环境
$ pip install uwsgi  #这个之前装到虚拟环境里面

如果出现Failed building wheel for uwsgi执行下面语句

apt-get install python3-dev

项目文件创建

这个按自己需要创建,也可以按我这个创建

$ mkdir /www  #根目录下创建一个www
$ mkdir /www/wwwroot  #这个项目文件全部放这个理
$ mkdir /www/log #日志文件

uwsgi配置

uwsgi配置好后,可以测试下

uwsgi配置路径:/www/wwwroot/uwsgi.ini

$ cd /www/wwwroot #可以放到项目,按自己需求都可以
$ vi uwsgi.ini   #创建一个uwsgi配置文件

[uwsgi]
# 当前这个项目的路径
chdir           = /www/wwwroot
# 模块
module          = manage   #启动文件名 个人理解
# python的虚拟环境
home            = /root/.virtualenvs/python3
# 是否启用mater模式
master          = true
# 进程数
processes       = 2
# socket文件地址
socket          = /www/wwwroot/uwsgi.sock
# wsgi文件
wsgi-file       = /www/wwwroot/manage.py  #启动文件
# wsgi文件中的app变量
callable        = app
# socket文件的权限
chmod-socket    = 666

配置好后可以运行起来测试是否成功

$ workon python3 #进入虚拟环境
$ uwsgi --uid www --gid www --ini /www/wwwroot/uwsgi.ini #这个可以指定用户和用户组权限,也可以不指定。测试没能正常打开项目就往下面步骤继续配置

nginx配置

$ cd /etc/nginx/sites-enabled/   #切换到nginx默认配置目录
$ mv default default.bak #修改配置前先备份下配置
$ vi default
server {
        listen 80;
        server_name www.xxoo.com;
        charset utf-8;
        client_max_body_size 75M;
        access_log /www/log/xxoo.access.log;
        error_log /www/log/xxoo.error.log;

        location / {
                include uwsgi_params;
                uwsgi_pass unix:/www/wwwroot/uwsgi.sock; #这个.sock文件一定要和uwsgi配置中一样
        }
}

修改nginx配置/etc/nginx/nginx.conf ,第一行user www www ; Nginx用户及组:用户 组 按自己需求配置。详细配置参数网上自己找

supervisor配置

supervisor配置路径:/www/wwwroot/supervisor.conf

$ vi supervisor.conf
[program:python]  #这个python可以按自己需求写
# supervisor执行的命令
command=/root/.virtualenvs/py3-zqcms/bin/uwsgi --uid www --gid www --ini /www/wwwroot/uwsgi.ini
# 项目的目录
directory = /www/wwwroot
# 开始的时候等待多少秒
startsecs= 5   #按自己需求写
# 停止的时候等待多少秒
stopwaitsecs= 5 #按自己需求写
# 自动开始
autostart=true
# 程序挂了后自动重启
autorestart=true
# 输出的log文件
stdout_logfile=/www/log/supervisord.log
# 输出的错误文件
stderr_logfile=/www/log/supervisorderr.log

[supervisord]
# log的级别
loglevel=info

配置好后就运行

$ supervisord -c /www/wwwroot/supervisor.conf  #执行的时候注意是在python2环境

如何终止多余 Supervisor 进程?

$ ps -ef | grep supervisor  #查看
$ kill 4012 #结束进程

注意:uwsgi nginx supervisor我只是简单配置了下,各位可以按需求配置。详细配置参数网上有很多资料。哪里写错,可以留言告诉我。

使用Nginx 和Supervisor在Linux服务器上部署Tornado

Nginx 安装: sudo apt-get install nginx

Nginx 安装后用浏览器进入127.0.0.1就可以看到nginx的欢迎页了

nginx 常用命令

  1. sudo service nginx start 启动nginx
  2. sudo service nginx stop 停止nginx
  3. sudo service nginx restart 重启nginx
  4. sudo service nginx reload 重新加载配置文件

未分类

Supervisor 安装: sudo apt-get install supervisor

部署步骤:

  • Tornado项目路径 : /home/你的用户名/Tornado项目文件夹名称/main.py

  • 在/etc/nginx/下 创建nginx.conf配置文件
    这里我们使用8000-8003四个端口,进行端口转发 配置文件编写要注意main.py所在位置要写对,即下面配置文件中的中文

user root;
worker_processes auto;
pid /run/nginx.pid;

events {
    worker_connections 768;
    multi_accept on;
    use epoll;
}
http {
    # Enumerate all the Tornado servers here
    upstream frontends {
        server 127.0.0.1:8000;
        server 127.0.0.1:8001;
        server 127.0.0.1:8002;
        server 127.0.0.1:8003;
    }

    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    access_log /var/log/nginx/access.log;

    keepalive_timeout 65;
    proxy_read_timeout 200;
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    gzip on;
    gzip_min_length 1000;
    gzip_proxied any;
    gzip_types text/plain text/html text/css text/xml
               application/x-javascript application/xml
               application/atom+xml text/javascript;
    proxy_next_upstream error;

    server {
        listen 80;

        # Allow file uploads
        client_max_body_size 50M;

        location ^~ /static/ {
            root /home/用户名/项目文件夹名/;
            if ($query_string) {
                expires max;
            }
        }
        location = /favicon.ico {
            rewrite (.*) /static/favicon.ico;
        }
        location = /robots.txt {
            rewrite (.*) /static/robots.txt;
        }

        location / {
            proxy_pass_header Server;
            proxy_set_header Host $http_host;
            proxy_redirect off;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Scheme $scheme;
            proxy_pass http://frontends;
        }
    }
}
  • 编写supervisor配置文件

  • 进入supervisor配置文件夹 cd /etc/supervisor/conf.d/

  • 创建tornados.conf

[group:tornadoes]
programs=tornado-8000,tornado-8001,tornado-8002,tornado-8003

[program:tornado-8000]
command=python /home/用户名/项目文件夹名/main.py --port=8000
directory=/home/用户名/项目文件夹名
user=root
autorestart=true
redirect_stderr=true
stdout_logfile=/var/log/tornado.log
loglevel=info

[program:tornado-8001]
command=python /home/用户名/项目文件夹名/main.py --port=8001
directory=/home/用户名/项目文件夹名
user=root
autorestart=true
redirect_stderr=true
stdout_logfile=/var/log/tornado.log
loglevel=info

[program:tornado-8002]
command=python /home/用户名/项目文件夹名/main.py --port=8002
directory=/home/用户名/项目文件夹名
user=root
autorestart=true
redirect_stderr=true
stdout_logfile=/var/log/tornado.log
loglevel=info

[program:tornado-8003]
command=python /home/用户名/项目文件夹名/main.py --port=8003
directory=/home/用户名/项目文件夹名
user=root
autorestart=true
redirect_stderr=true
stdout_logfile=/var/log/tornado.log
loglevel=info
  • 其中/var/log/tornado.log为日志文件目录
    然后先重载nginx的配置文件 sudo service nginx reload
    重启 nginx : sudo service nginx restart
    supervisor开启所有进程: sudo supervisorctrl restart all

再次打开127.0.0.1后可以看到项目已经成功部署。

Linux下的守护进程工具-Supervisor

简介:没有

安装

sudo apt-get install supervisor

(其实我是用Mint的软件管理器安装的……)

配置

参考帖子:

详解supervisor使用教程 http://www.jb51.net/article/128676.htm

supervisor 从安装到使用 http://www.jianshu.com/p/3658c963d28b

使用 Supervisor 进行进程管理 http://www.jianshu.com/p/2a48b2c987e0

执行命令

sudo supervisord
sudo supervisorctl start/stop/restart RROGRAM_NAME
sudo supervisorctl reload
sudo supervisorctl status

配置文件模板

我的配置文件在/etc/supervisor/supervisord.conf
我的配置模板:

[program:ssr]
command = python local.py -c /home/jerry/opt/shadowsocksr-manyuser/shadowsocks/shadowsocksr.json
stdout_logfile=/tmp/ssr.log
stdout_logfile_backups=2 ;默认为10 
stdout_capture_maxbytes=1MB 

[program:drcom]
command = python2 /home/jerry/opt/DRCOM_PY/latest-wired.py
stdout_logfile=/tmp/drcom.log
stdout_logfile_backups=2 ;默认为10 
stdout_capture_maxbytes=1MB 
autostart= false

通用模板

;[program:theprogramname]
;command=/bin/cat              ; the program (relative uses PATH, can take args)
;process_name=%(program_name)s ; process_name expr (default %(program_name)s)
;numprocs=1                    ; number of processes copies to start (def 1)
;directory=/tmp                ; directory to cwd to before exec (def no cwd)
;umask=022                     ; umask for process (default None)
;priority=999                  ; the relative start priority (default 999)
;autostart=true                ; start at supervisord start (default: true)
;startsecs=1                   ; # of secs prog must stay up to be running (def. 1)
;startretries=3                ; max # of serial start failures when starting (default 3)
;autorestart=unexpected        ; when to restart if exited after running (def: unexpected)
;exitcodes=0,2                 ; 'expected' exit codes used with autorestart (default 0,2)
;stopsignal=QUIT               ; signal used to kill process (default TERM)
;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                   ; setuid to this UNIX account to run the program
;redirect_stderr=true          ; redirect proc stderr to stdout (default false)
;stdout_logfile=/a/path        ; stdout log path, NONE for none; default AUTO
;stdout_logfile_maxbytes=1MB   ; max # logfile bytes b4 rotation (default 50MB)
;stdout_logfile_backups=10     ; # of stdout logfile backups (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        ; stderr log path, NONE for none; default AUTO
;stderr_logfile_maxbytes=1MB   ; max # logfile bytes b4 rotation (default 50MB)
;stderr_logfile_backups=10     ; # of stderr logfile backups (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"       ; process environment additions (def no adds)
;serverurl=AUTO                ; override serverurl computation (childutils)

; The below sample eventlistener section shows all possible
; eventlistener subsection values, create one or more 'real'
; eventlistener: sections to be able to handle event notifications
; sent by supervisor.

进程管理工具Supervisor(二)Events

supervisor可以当做一个简单的进程启动、重启、控制工具使用,也可以作为一个进程监控框架使用,作为后者,需要使用supervisor的Events机制。

Event Listeners

supervisor对子程序的监控通过叫做event listener的程序实现。supervisor控制的子程序状态发生变化时,就会产生一些事件通知,event listener可以对这些事件通知进行订阅。

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

配置

event listener的配置放置于配置文件中的[eventlistener:x]块中。

[eventlistener:mylistener]
command=my_custom_listener.py
events=PROCESS_STATE,TICK_60

x是listener的名称,command是执行listener脚本的命令,events是要监控的事件类型。

event listener本身是作为supervisor的子程序运行的,所以与配置子程序[program:x]块类似,官网例子:

[eventlistener:theeventlistenername]
command=/bin/eventlistener
process_name=%(program_name)s_%(process_num)02d
numprocs=5
events=PROCESS_STATE
buffer_size=10
directory=/tmp
umask=022
priority=-1
autostart=true
autorestart=unexpected
startsecs=1
startretries=3
exitcodes=0,2
stopsignal=QUIT
stopwaitsecs=10
stopasgroup=false
killasgroup=false
user=chrism
redirect_stderr=false
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

事件通知协议

一个event listener可以处于三种状态,ACKNOWLEDGED、READY、BUSY,只有在READY状态下才可以接收事件通知。

event listener启动时处于ACKNOWLEDGED状态,直到event listener向stdout中输出“READYn”字符串为止。

event listener向stdout中输出“READYn”之后就处于READY状态,supervisor会向处于READY状态的listener发送listener订阅的事件通知。

listener接收事件通知之后就处于BUSY状态,期间listener对接收到的事件通知进行处理,处理结束后向stdout输出“RESULT 2nOK”或者“RESULT 4nFAIL”,前者代表处理成功,后者代表处理失败。

supervisor收到OK或者FAIL输出后,就将event listener的状态置于ACKNOWLEDGED。FAIL的事件通知会被缓存然后再次发送。

event listener的状态处于ACKNOWLEDGED后可以退出执行,也可以继续执行,继续执行就可以向stdout输出“READYn”形成一个循环。

supervisor向listener发送的事件通知由两部分组成,header和body,由”n”换行符分开。

一个header例子:

ver:3.0 server:supervisor serial:21 pool:listener poolserial:10 eventname:PROCESS_COMMUNICATION_STDOUT len:54

ver:协议版本

server:supervisor的标识符,由[supervisord]块中的identifier选项设置。

serial:event的序列号

pool:listener的pool的名字。

poolserial:event在pool中的的序列号

eventname:event类型名称

len:header后面的body长度。

一个body例子:

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

processname:事件所属的子进程名字

groupname:子进程所属组名

pid:子进程pid

一个简单的listener脚本,listener.py:

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 True:
        # 进入READY状态
    ┆   write_stdout('READYn')
    ┆   # 读取事件通知的header
    ┆   line = sys.stdin.readline()
    ┆   write_stderr(line)
        # 获取body长度,读取body
    ┆   headers=dict([x.split(':') for x in line.split() ])
    ┆   data = sys.stdin.read(int(headers['len']))
    ┆   write_stderr(data+'n')
        # 发送OK进入ACKNOWLEDGED状态
    ┆   write_stdout('RESULT 2nOK')
if __name__ == '__main__':
    main()

在conf.d目录中建立一个listener配置文件mylistener.conf:

[eventlistener:mylistener]
command=python listener.py
directory=/thedirectoroflistener.py
user=user
events=PROCESS_STATE,TICK_5
stdout_logfile=/path/to/mylistener_stdout.log
stderr_logfile=/path/to/mylistener_stderr.log

启动:

ubuntu:$ sudo supervisorctl start all
mylistener: started
celerybeat: started
ubuntu:$ sudo supervisorctl status
celerybeat                       RUNNING   pid 87729, uptime 0:00:20
mylistener                       RUNNING   pid 87728, uptime 0:00:20

监控就开始了,可以到日志中查看事件通知的内容:

ver:3.0 server:supervisor serial:15361 pool:mylistener poolserial:15361 eventname:PROCESS_STATE_RUNNING len:73
processname:mylistener groupname:mylistener from_state:STARTING pid:87728
ver:3.0 server:supervisor serial:15362 pool:mylistener poolserial:15362 eventname:TICK_5 len:15
when:1514313560
ver:3.0 server:supervisor serial:15364 pool:mylistener poolserial:15364 eventname:PROCESS_STATE_RUNNING len:73
processname:celerybeat groupname:celerybeat from_state:STARTING pid:87729

可以根据自己的需要设定监控的事件类型,然后根据不同的事件类型和内容做出不同的应变,具体的事件类型可以官网查看。

python的supervisor.childutils模块对header和body的处理进行了包装:

def get_headers(line):
    return dict([ x.split(':') for x in line.split() ])

def eventdata(payload):
    headerinfo, data = payload.split('n', 1)
    headers = get_headers(headerinfo)
    return headers, data

def get_asctime(now=None):
    if now is None: # for testing
        now = time.time() # pragma: no cover
    msecs = (now - long(now)) * 1000
    part1 = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(now))
    asctime = '%s,%03d' % (part1, msecs)
    return asctime

class ProcessCommunicationsProtocol:
    def send(self, msg, fp=sys.stdout):
        fp.write(ProcessCommunicationEvent.BEGIN_TOKEN)
        fp.write(msg)
        fp.write(ProcessCommunicationEvent.END_TOKEN)

    def stdout(self, msg):
        return self.send(msg, sys.stdout)

    def stderr(self, msg):
        return self.send(msg, sys.stderr)

pcomm = ProcessCommunicationsProtocol()

class EventListenerProtocol:
    def wait(self, stdin=sys.stdin, stdout=sys.stdout):
        self.ready(stdout)
        line = stdin.readline()
        headers = get_headers(line)
        payload = stdin.read(int(headers['len']))
        return headers, payload

    def ready(self, stdout=sys.stdout):
        stdout.write(PEventListenerDispatcher.READY_FOR_EVENTS_TOKEN)
        stdout.flush()

    def ok(self, stdout=sys.stdout):
        self.send('OK', stdout)

    def fail(self, stdout=sys.stdout):
        self.send('FAIL', stdout)

    def send(self, data, stdout=sys.stdout):
        resultlen = len(data)
        result = '%s%sn%s' % (PEventListenerDispatcher.RESULT_TOKEN_START,
                               str(resultlen),
                               data)
        stdout.write(result)
        stdout.flush()

listener = EventListenerProtocol()

listener脚本可以方便的写做:

import sys

from supervisor import childutils

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 True:
    ┆   headers, payload = childutils.listener.wait()
    ┆   write_stderr(payload+'n')
    ┆   childutils.listener.ok(sys.stdout)

if __name__ == '__main__':
    main()

进程管理工具Supervisor(一)简介与使用

Supervisor是用Python开发的一套client/server架构的进程管理程序,能做到开机启动,以daemon进程的方式运行程序,并可以监控进程状态等等。

linux进程管理方式有传统的rc.d、新兴的upstart、systemd等,与这些相比,Supervisor有着自己的特点。

便利性

使用rc.d管理进程的时候,一是要写耗时耗力的脚本,二是管理的进程挂掉的话不会自动重启。

而supervisor要启动子进程,只需要将子进程的启动命令写入配置文件即可,配置自动重启子进程也很方便。

精确

supervisor作为父进程监控子进程,得到的子进程状态是很准确的。

授权

一般要管理linux进程的话,特别是在一些“low” tcp端口,比如1024以下端口中运行的程序,都需要root权限。

而以root权限启动supervisord后,一般的用户可以在一个简单的shell或者web界面中获取supervisord控制的子进程运行状态,并通过stop、start、restart的命令控制子进程的运行。

进程组

supervisor可以对子进程以start all或者restart all命令的方式进行统一管理。

中央集中式管理

supervisor可以在同一个地方启动、停止或者监视管理的进程。既可以单独的控制一个进程,也可以一起控制一组进程。

管理的时候,既可以本地管理,又可以远程连接,提供命令行接口与web页面接口。

高效性

supervisor是通过fork/exec的方式启动子进程的,子进程挂掉的话,操作系统会立即通知supervisor。

兼容性

除了windows,其他操作系统平台都可运行supervisor。supervisor使用python编写,不需要c编译器。

组件

supervisord

supervisor的服务器端,负责启动子程序,响应客户端发来的命令,重启子程序,记录子程序stdout和stderr的日志,处理Event。

配置文件一般是名为/etc/supervisord.conf的ini文件。

supervisorctl

supervisor的命令行客户端,提供一个类shell接口,用户可以使用supervisorctl连接不同的supervisord进程,查看子进程状态,start、stop子进程,获取控制的子进程列表。

客户端可以使用unix socket或者tcp socket与服务端进行通讯,通过配置文件中的[supervisorctl]段进行配置。

Web Server

使用tcp socket启动supervisord的时候,提供的一个访问supervisor的web接口。

url地址通过配置文件中的[inet_http_server]进行设置。

XML-RPC Interface

一个XML-RPC接口

下载

可以使用setuptools或者pip下载:

easy_install supervisor
or
pip install supervisor

ubuntu中使用apt下载:

apt-get install supervisor

配置文件

运行echo_supervisord_conf命令可以在shell中显示一份supervisor配置文件样本。配置一般是放在文件/etc/supervisord.conf的,所以可以将配置输入到配置文件中:

echo_supervisord_conf > /etc/supervisord.conf

上述命令需要root权限,如果没有权限或者想另置配置文件地址,可以在当前目录生成:

echo_supervisord_conf > supervisord.conf

然后启动时使用-c选项指定配置文件即可:

supervisord -c supervisord.conf

启动

首先配置要启动的子进程,可以在supervisord.conf中配置,也可以单独配置,supervisord.conf中的include配置:

[include]
files = /etc/supervisor/conf.d/*.conf

所以可以在/etc/supervisor/conf.d/目录下,以.conf作为扩展名为子进程建立单独的配置文件,比如建立一个foo.conf文件:

[program:foo]
command=/bin/cat

上述是最简单的配置了,foo为子进程名称,command是子进程运行命令。

重启supervisor使配置生效:

service supervisor restart

或者直接执行启动supervisord:

$BINDIR/supervisord

启动foo子进程:

supervisorctl start foo

一个实际例子,启动celery beat服务,建立celerybeat.conf文件:

; ================================
;  celery beat supervisor example
; ================================

[program:celerybeat]
; Set full path to celery program if using virtualenv
command=celery beat -A myapp --schedule /var/lib/celery/beat.db --loglevel=INFO

; remove the -A myapp argument if you aren't using an app instance

directory=/path/to/project
user=nobody
numprocs=1
stdout_logfile=/var/log/celery/beat.log
stderr_logfile=/var/log/celery/beat.log
autostart=true
autorestart=true
startsecs=10

; Causes supervisor to send the termination signal (SIGTERM) to the whole process group.
stopasgroup=true

; if rabbitmq is supervised, set its priority higher
; so it starts first
priority=999

启动:

$ supervisorctl start celerybeat
celerybeat: started

celery beat服务开始运行了:

[2017-12-22 07:13:47,904: WARNING/ForkPoolWorker-1] 32
[2017-12-22 07:13:47,908: INFO/ForkPoolWorker-1] Task tests.tasks.add[77706e41-83c1-4545-922b-b77a57205ef5] succeeded in 0.00359446300718s: None
[2017-12-22 07:13:57,903: INFO/MainProcess] Received task: tests.tasks.add[3f9c7c88-61aa-44cc-a517-14f32305ad64] 
[2017-12-22 07:13:57,907: WARNING/ForkPoolWorker-1] 32
[2017-12-22 07:13:57,910: INFO/ForkPoolWorker-1] Task tests.tasks.add[3f9c7c88-61aa-44cc-a517-14f32305ad64] succeeded in 0.00268728499941s: None
[2017-12-22 07:14:07,903: INFO/MainProcess] Received task: tests.tasks.add[90e4277b-7041-4c3a-905c-1a5e16272d31] 
[2017-12-22 07:14:07,907: WARNING/ForkPoolWorker-1] 32
[2017-12-22 07:14:07,910: INFO/ForkPoolWorker-1] Task tests.tasks.add[90e4277b-7041-4c3a-905c-1a5e16272d31] succeeded in 0.0029478570068s: None

配置不正确的话,会报supervisor ERROR (spawn error)错误,可以使用tail命令看下错误日志:

supervisorctl tail celerybeat stdout

查看管理的子进程运行状态:

$ supervisorctl status
celerybeat                       RUNNING   pid 66802, uptime 0:12:59

关闭子进程:

supervisorctl stop celerybeat

不加参数的直接运行supervisorctl命令,会进入supervisor客户端的交互终端进行操作。

要通过web页面访问supervisor,可以添加以下配置:

[inet_http_server]
port = 127.0.0.1:9001
username = username
password = yourpwd

浏览器访问127.0.0.1:9001,输入配置的用户名、密码,进入页面:

未分类

supervisor 安装和使用

安裝 supervisord

wget -c https://bootstrap.pypa.io/ez_setup.py
python ez_setup.py
easy_install supervisor

配置

### 生成配置文件,且放在/etc目录下
echo_supervisord_conf > /etc/supervisord.conf  

### 为了不将所有新增配置信息全写在一个配置文件里,这里新建一个文件夹,每个程序设置一个配置文件,相互隔离
mkdir /etc/supervisord.d/  

### 修改配置文件
vim /etc/supervisord.conf

### 加入以下配置信息
[include]
files = /etc/supervisord.d/*.conf

### 在supervisord.conf中设置通过web可以查看管理的进程,加入以下代码(默认即有,取消注释即可)  
[inet_http_server] 
port=9001
username=user      
password=123

添加一个示例进程

将下面代码保存为:

<?php

$i=0;
while(true){
    sleep(1);
    echo $i++."n";
}

/root/demo.php

在 /etc/supervisord.d/ 下添加 demo.conf, 内容为:

[program:demo]
### 启动命令
command=/usr/local/server/php/bin/php -f /root/demo.php  
### 进程数
numprocs=2 
### 进程名称
process_name=%(program_name)s_%(process_num)02d 
startsecs=0  
stopwaitsecs=0
### 是否自动启动
autostart=true  
### 当进程丢失自动重启
autorestart=true  
stdout_logfile=/var/log/demo.log
stderr_logfile=/var/log/demo.log

启动:

supervisord -c /etc/supervisord.conf
supervisorctl start demo

查看启动的进程:

supervisorctl status

常用命令

查看状态:

supervisorctl status

启动进程:

supervisorctl start demo

重启进程:

supervisorctl restart demo

重新加载配置:

supervisorctl reload

注意新增或修改了配置都需要执行 reload 命令来让修改生效