生产环境优雅的重启基于Nginx、Tornado的Web服务进程

Nginx是一个高效的Web服务器及代理服务器,Tornado是一个基于epoll的异步Web开发框架,通常使用Nginx做为Web服务器时,都会以FastCGI模式,而我们从开发、调试、运维的角度考虑,使用了反向代理的模式,同时Nginx可以做一些特殊业务和负载均衡的处理。

其实反向代理模式很简单,Nginx监听在80端口,做为Web服务端口,而Tornado的Web服务进程监听在808*的内部端口(可以启动多个进程),使用supervisor对Nginx、Tornado服务进程进行统一的管理。

首先看supervisor的配置:

# supervisor自己的配置及日志切割等
[supervisord]
logfile = /opt/logs/supervisord.log
logfile_maxbytes = 200MB
logfile_backups=10
loglevel = warn
pidfile = /opt/logs/supervisord.pid
nodaemon = false
minfds = 1024
minprocs = 200
umask = 022
identifier = supervisor
directory = %(here)s
nocleanup = true
strip_ansi = false

[unix_http_server]
file = /opt/logs/supervisord.sock

[supervisorctl]
serverurl = unix:///opt/logs/supervisord.sock

[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

# 服务进程的启动及多端口
[program:MyWeb]
command = /opt/bin/python %(here)s/server.py --port=808%(process_num)01d
process_name = 808%(process_num)01d
numprocs = 4
numprocs_start = 1
autostart = true
autorestart = true
redirect_stderr = true
stdout_logfile = /opt/logs/stdout.log
stderr_logfile = /opt/logs/stdout.log

# Nginx的管理配置
[program:Nginx]
command = /opt/sbin/nginx -c %(here)s/nginx.conf
process_name = Nginx
numprocs = 1
autostart = true
autorestart = true
redirect_stderr = true
stdout_logfile = /opt/logs/nginx_stdout.log
stderr_logfile = /opt/logs/nginx_stdout.log

启动脚本(可以放到start.sh中):

/opt/bin/supervisord /opt/conf/supervisor.conf

重启脚本(可以放到restart.sh中)

#逐个启动MyWeb每个端口进程,不中断服务
for i in "8081 8082 8083 8084":
do
    /opt/bin/supervisorctl /opt/conf/supervisor.conf restart MyWeb:$i; 
done

#重新加载nginx的配置
/opt/sbin/nginx /opt/conf/nginx.conf -s reload; 

Nginx的部分配置(启动4个服务进程,监听在80端口,并反向代理负载到Tornado的808*端口上):

worker_processes  4;
daemon off; #nginx不能以daemon模式启动
user nobody;

http {
    upstream myweb {
        server 127.0.0.1:8081;
        server 127.0.0.1:8082;
        server 127.0.0.1:8083;
        server 127.0.0.1:8084;
    }
    server {
        listen       80;
        server_name  localhost;
        location / {
           proxy_set_header Host $http_host;
           proxy_set_header X-Real-IP $remote_addr;
           proxy_set_header X-Forwarded-For  $remote_addr;
           proxy_set_header X-Scheme $scheme;
           proxy_read_timeout 300s;
           proxy_pass http://myweb;
        }
    }
}

现在Nginx已经反向代理到Tornado的服务进程监听的端口了,那么MyWeb的服务进程如何构建、并如何优雅的重启呢,略过其他代码,介绍一下主进程采用信号停止服务,并重新启动的方法。主进程的启动参数会指定此进程监听的端口,这样supervisor检测到服务进程结束后,会自动启动对应的服务进程。

import signal
import tornado.ioloop
import tornado.httpserver

http_server = None

def sig_handler(sig, frame):
    """信号处理函数
    """
    tornado.ioloop.IOLoop.instance().add_callback(shutdown)

def shutdown():
    """进程关闭处理
    """
    # 停止接受Client连接
    global http_server
    http_server.stop()

    io_loop = tornado.ioloop.IOLoop.instance()
    deadline = time.time() + 10 #设置最长强制结束时间

    def stop_loop():
        now = time.time()
        if now < deadline:
            io_loop.add_timeout(now + 1, stop_loop)
        else:
            io_loop.stop()

    stop_loop()

if __name__ == '__main__':

    # 等待supervisor发送进程结束信号
    signal.signal(signal.SIGTERM, sig_handler) 
    signal.signal(signal.SIGINT, sig_handler)

    app = Application()
    http_server = tornado.httpserver.HTTPServer(app, xheaders=True)
    http_server.listen(tornado.options.options.port)

    tornado.ioloop.IOLoop.instance().start()

原创声明:除非注明,本站文章均为原创!转载请注明来自 嗨!大佟! www.qmailer.net
本文链接:http://www.qmailer.net/archives/165.html

本文现有 2 条评论:

  1. leilux说道:

    受益良多!
    我发现可以用:
    /opt/bin/supervisorctl /opt/conf/supervisor.conf restart MyWeb:
    来替代,更加完美

    #逐个启动MyWeb每个端口进程,不中断服务
    for i in “8081 8082 8083 8084″:
    do
    /opt/bin/supervisorctl /opt/conf/supervisor.conf restart MyWeb:$i;
    done

  2. 大佟说道:

    /opt/bin/supervisorctl /opt/conf/supervisor.conf restart MyWeb:*
    这样会stop all所有进程,然后再start all进程,此时会造成部分中断,所以我们是采用逐个进程stop/start,这样保证有进程在处理业务,同时中间可以sleep(1)及验证是否成功启动。

发表评论