简介
Gunicorn是基于unix系统,被广泛应用的高性能的Python WSGI HTTP Server。用来解析HTTP请求的网关服务。
它通常是在进行反向代理(如nginx),或者进行负载均衡(如 AWS ELB)和一个web 应用(比如 Django 或者 Flask)之间。
它的运行模型基于pre-fork worker 模型,即就是支持eventlet,也支持greenlet。
目前,gunicorn只能运行在Linux环境中,不支持windows平台。
信号
gunicorn是通过信号处理来达到对进程管理的目的,先看一下他接收的几种信号
QUIT
: 快速关闭TERM
: 优雅的关闭。等待worker完成当前请求直到达到超时时间HUP
: 重新加载配置,使用新的配置启动新的工作进程,并优雅地关闭较老的工作进程。TTIN
: 增加一个进程TTOU
: 减少一个进程USR1
: 重新打开日志文件USR2
: 在线升级gunicornWINCH
: 优雅地关闭守护进程(后台运行的进程)
HUP
文档中的意思使用HUP可以达到重启的效果,测试的日志是这样的
[2021-01-21 17:25:14 +0800] [20388] [INFO] Handling signal: hup
[2021-01-21 17:25:14 +0800] [20388] [INFO] Hang up: Master
[2021-01-21 17:25:14 +0800] [29249] [INFO] Booting worker with pid: 29249
[2021-01-21 17:25:14 +0800] [29248] [INFO] Booting worker with pid: 29248
[2021-01-21 17:25:14 +0800] [29250] [INFO] Booting worker with pid: 29250
[2021-01-21 17:25:14 +0800] [28643] [INFO] Shutting down
[2021-01-21 17:25:14 +0800] [28643] [INFO] Error while closing socket [Errno 9] Bad file descriptor
[2021-01-21 17:25:14 +0800] [28640] [INFO] Shutting down
[2021-01-21 17:25:14 +0800] [28640] [INFO] Error while closing socket [Errno 9] Bad file descriptor
[2021-01-21 17:25:14 +0800] [28642] [INFO] Shutting down
[2021-01-21 17:25:14 +0800] [28642] [INFO] Error while closing socket [Errno 9] Bad file descriptor
[2021-01-21 17:25:14 +0800] [28643] [INFO] Finished server process [28643]
[2021-01-21 17:25:14 +0800] [28643] [INFO] Worker exiting (pid: 28643)
[2021-01-21 17:25:14 +0800] [28640] [INFO] Finished server process [28640]
[2021-01-21 17:25:14 +0800] [28640] [INFO] Worker exiting (pid: 28640)
[2021-01-21 17:25:14 +0800] [28642] [INFO] Finished server process [28642]
[2021-01-21 17:25:14 +0800] [28642] [INFO] Worker exiting (pid: 28642)
[2021-01-21 17:25:15 +0800] [29248] [INFO] Started server process [29248]
[2021-01-21 17:25:15 +0800] [29248] [INFO] Waiting for application startup.
[2021-01-21 17:25:15 +0800] [29248] [INFO] ASGI 'lifespan' protocol appears unsupported.
[2021-01-21 17:25:15 +0800] [29248] [INFO] Application startup complete.
[2021-01-21 17:25:15 +0800] [29249] [INFO] Started server process [29249]
[2021-01-21 17:25:15 +0800] [29249] [INFO] Waiting for application startup.
[2021-01-21 17:25:15 +0800] [29249] [INFO] ASGI 'lifespan' protocol appears unsupported.
[2021-01-21 17:25:15 +0800] [29249] [INFO] Application startup complete.
通过日志可以看到他是先停止了旧进程然后再启动了新的进程,但是从gunicorn源码中看是先启动了进程然后通过进程数和配置的进程数对比来kill掉老的进程:
# 简化后的处理HUP方法
# spawn new workers
for _ in range(self.cfg.workers):
self.spawn_worker() # 这里启动了进程
# manage workers
self.manage_workers() # 这里根据进程启动的时候给的一个age值来kill掉老的进程
# manage_workers方法
def manage_workers(self):
"""\
Maintain the number of workers by spawning or killing
as required.
"""
if len(self.WORKERS) < self.num_workers:
self.spawn_workers()
workers = self.WORKERS.items()
workers = sorted(workers, key=lambda w: w[1].age)
while len(workers) > self.num_workers:
(pid, _) = workers.pop(0)
self.kill_worker(pid, signal.SIGTERM)
active_worker_count = len(workers)
if self._last_logged_active_worker_count != active_worker_count:
self._last_logged_active_worker_count = active_worker_count
self.log.debug("{0} workers".format(active_worker_count),
extra={"metric": "gunicorn.workers",
"value": active_worker_count,
"mtype": "gauge"})
实操
- 获取Gunicorn进程树:
pstree -ap|grep gunicorn
结果如下:
| |-gunicorn,29863 /usr/local/bin/gunicorn -c gun.tests.conf app:app
| | |-gunicorn,29867 /usr/local/bin/gunicorn -c gun.tests.conf app:app
| | | `-{gunicorn},31724
| | |-gunicorn,29868 /usr/local/bin/gunicorn -c gun.tests.conf app:app
| | | `-{gunicorn},30979
| | |-gunicorn,29869 /usr/local/bin/gunicorn -c gun.tests.conf app:app
| | | `-{gunicorn},30953
| | |-gunicorn,29870 /usr/local/bin/gunicorn -c gun.tests.conf app:app
| | | `-{gunicorn},30532
| | |-gunicorn,29872 /usr/local/bin/gunicorn -c gun.tests.conf app:app
| | | `-{gunicorn},30951
| | |-gunicorn,29875 /usr/local/bin/gunicorn -c gun.tests.conf app:app
| | | `-{gunicorn},30533
| | |-gunicorn,29876 /usr/local/bin/gunicorn -c gun.tests.conf app:app
| | | `-{gunicorn},30714
| | |-gunicorn,29877 /usr/local/bin/gunicorn -c gun.tests.conf app:app
| | | `-{gunicorn},30952
| | `-gunicorn,29878 /usr/local/bin/gunicorn -c gun.tests.conf app:app
| | `-{gunicorn},30510
- 重启Gunicorn任务
kill -HUP 29863
补充其他内容
安装
pip install gunicorn
配置与启动
Gunicorn可以以三种方式读取配置信息。
- 从framework定义的配置信息中读取,目前只对 Paster 框架有效。本方式较少用到。
- 在命令行中定义,命令行中定义的配置信息将会覆盖掉框架中定义的相同的参数名的值。
- 将所有的参数信息,放到一个python文件中,只要是在命令行中可以定义的参数中,在配置文件中都可以定义。
命令行配置参数
命令行有哪些参数可以通过gunicorn -h 查到
实例:
gunicorn -D -t 300 -w 2 -b 0.0.0.0:8787 flaskr:create_app()
下面是flaskr下 init.py 的内容
import os
from flask import Flask
from flask_cors import CORS
def create_app(test_config=None):
# create and configure the app
app = Flask(__name__, instance_relative_config=True)
CORS(app, supports_credentials=True)
app.config.from_mapping(
SECRET_KEY='dev',
DATABASE=os.path.join(app.instance_path, 'flaskr.sqlite'),
)
if test_config is None:
# load the instance config, if it exists, when not testing
app.config.from_pyfile('config.py', silent=True)
else:
# load the test config if passed in
app.config.from_mapping(test_config)
# ensure the instance folder exists
try:
os.makedirs(app.instance_path)
except OSError:
pass
# a simple page that says hello
from . import api, db
db.init_app(app)
app.register_blueprint(api.bp)
return app
python文件配置参数
命令行中定义的参数,都可以放在配置文件(config_gunicorn.py)中。
#config_gunicorn.py
#import multiprocessing
bind = "0.0.0.0:8787"#gunicorn监控的接口
#workers = multiprocessing.cpu_count() * 2 + 1
workers = 2#进程数
#threads = 1 #每个进程开启的线程数
timeout = 300
backlog = 2048
worker_class = "eventlet"# 工作模式协程,详看https://ox0spy.github.io/post/web-test/gunicorn-worker-class/
worker_connections = 1000
daemon = True
pidfile = 'log/gunicorn.pid'#gunicorn进程id,kill掉该文件的id,gunicorn就停止
#loglevel = 'debug'
accesslog = 'log/access.log'
errorlog = 'log/gunicorn.log'
gunicorn --config=config_gunicorn.py flaskr:create_app()
命令行参数和文件配置还可以混合使用,此时命令行中定义的配置信息将会被优先采用。
gunicorn --config=config_gunicorn.py --worker-class=gevent flaskr:create_app()
服务重启、退出
获取Gunicorn进程树(用下面的命令获取gunicorn的Master PID)
#方法1
pstree -ap|grep gunicorn
#方法2
ps -ef|grep gunicorn
重启Gunicorn进程
HUP(终端断线)信号发出之后,worker进程会进行被杀掉,并启动新的进程,保证源代码的修改会反映进来。master进程不会变
kill -HUP master_pid
优雅停止Gunicorn进程
kill -9 master_pid
自动化管理:supervisor
gunicorn无法重启,关闭进程麻烦,因此还需要一个程序(如supervisor)来管理gunicorn,以达到自动化.而supervisor是一个专门用来管理进程的工具,还可以管理系统的工具进程,甚至可设置web页面管理相关进程;
下面的命令是将gunicorn配置在supervisor之下的情况。仅做参考。
# 重新加载配置
sudo supervisorctl reload
# 重启动
sudo supervisorctl restart all(你想重启的单个应用名字也可以)
# 查看状态
sudo supervisorctl status
安装
pip install supervisor
supervisor设置配置文件(supervisor.conf)还可以将脚本打印信息输出到指定文件内,设置内存上限可自动清理等等;
配置文件
创建配置文件的默认路径
sudo mkdir /etc/supervisor
sudo mkdir /etc/conf.d
创建配置文件
cat /etc/supervisor/conf.d/wsgi.ini
[program:wsgi] ;program:名称
;启动命令,当然你可以直接 python run.py,此处使用gunicorn启动
command=gunicorn pygun.conf wsgi:app --log-level=debug --preload
;工作目录(脚本启动目录的全路径)
directory=/data/test
startsecs=0
stopwaitsecs=0
autostart=true ;supervisord守护程序启动时自动启动tornado
autorestart=true ;supervisord守护程序重启时自动重启tornado
redirect_stderr=true ;将stderr重定向到stdout
;日志标准输出路径,同时脚本print打印信息也会在改文件显示
stdout_logfile=./stdout.log
stderr_logfile=./error.log
;守护进程,可在 web 上访问
[inet_http_server] ; inet (TCP) server disabled by default
port=127.0.0.1:9001 ; (ip_address:port specifier, *:port for all iface)
username=wialsh ; (default is no username (open server))
password=wialsh ; (default is no password (open server))
;supervisord日志配置
[supervisord]
logfile=/tmp/supervisord.log ; main log file; default $CWD/supervisord.log
logfile_maxbytes=50MB ; max main logfile bytes b4 rotation; default 50MB
logfile_backups=1
若无特别需求,只需修改启动命令(command)、部分文件(directory、stdout_logfile、stderr_logfile、logfile)路径和守护进程(inet_http_server),其他参数默认即可;
启动
完成配置后,执行如下脚本启动(supervisord -c 启动指定路径的配置):
supervisord -c /etc/supervisor/conf.d/wsgi.ini
在完成配置后,查看监控日志,以检查启动是否成功,可执行如下操作
less error.log #gunicorn的errorlog路径
less /tmp/supervisord.log #supervisor的logfile路径
查看状态(如无错误情况,可查看状态)
supervisorctl -c /etc/supervisor/conf.d/wsgi.ini status
wsgi RUNNING pid 274203, uptime 0:17:35
重启服务
supervisorctl -c /etc/supervisor/conf.d/wsgi.ini reload
Restarted supervisord
关闭服务
supervisorctl -c /etc/supervisor/conf.d/wsgi.ini shutdown
Shut down
参考
官方文档
Gunicorn简介、安装、配置、启动
gunicorn不停服重启
优化 Gunicorn 配置
supervisor + gunicorn + flask 入门
详解gunicorn的功能及使用方法
supervisor配置详解