python-Gunicorn部署

摘要

官网
文档

Gunicorn(绿色独角兽)是一个被广泛使用的高性能的python Wsgi http server,只支持在Unix系统上运行,移植自Rubyunicorn(独角兽)项目。使用pre-fork master-worker模型(在gunicorn中,master被称为arbiter),具有使用非常简单,轻量级的资源消耗,以及高性能等特点。

Gunicorn服务器作为wsgi app的容器,能够与各种Web框架兼容(flaskdjango等),得益于gevent等技术,使用Gunicorn能够在基本不改变wsgi app代码的前提下,大幅度提高wsgi app的性能。

WSGI协议

Web框架致力于如何生成HTML代码,而Web服务器用于处理和响应HTTP请求。Web框架和Web服务器之间的通信,需要一套双方都遵守的接口协议。WSGI协议就是用来统一这两者的接口的。

工作原理

https://blog.csdn.net/jailman/article/details/78496522

Gunicorn易于配置,兼容性好,CPU消耗很少,在豆瓣使用广泛。它支持多种Worker模式,推荐的模式有如如下几种:

  • 同步Worker:默认模式,也就是一次只处理一个请求
  • 异步Worker:通过Eventlet、Gevent实现的异步模式
  • 异步IO Worker:目前支持gthread和gaiohttp两种类型

安装配置

gunicorn的安装非常简单

1
2
3
4
pip install guncorn
pip install greenlet # Required for both
pip install eventlet # For eventlet workers
pip install gevent # For gevent workers

后续如果用到异步的worker模型,还需要安装对应的模块(如gevent)

简单实用

app

1
2
3
4
5
6
7
def app(environ, start_response):
data = b"Hello, World!\n"
start_response("200 OK", [
("Content-Type", "text/plain"),
("Content-Length", str(len(data)))
])
return iter([data])

启动

1
2
3
4
5
6
7
8
9
10
# gunicorn [options] module_name:variable_name
# module_name对应python文件,variable_name对应web应用实例。
$ gunicorn -w 4 myapp:app
[2018-09-19 16:24:55 +0800] [32957] [INFO] Starting gunicorn 19.9.0
[2018-09-19 16:24:55 +0800] [32957] [INFO] Listening at: http://127.0.0.1:8000 (32957)
[2018-09-19 16:24:55 +0800] [32957] [INFO] Using worker: sync
[2018-09-19 16:24:55 +0800] [32960] [INFO] Booting worker with pid: 32960
[2018-09-19 16:24:55 +0800] [32961] [INFO] Booting worker with pid: 32961
[2018-09-19 16:24:55 +0800] [32962] [INFO] Booting worker with pid: 32962
[2018-09-19 16:24:55 +0800] [32963] [INFO] Booting worker with pid: 32963

nginx 配置

1
2
3
4
5
6
7
8
9
10
11
server {
listen 80;
server_name example.org;
access_log /var/log/nginx/example.log;

location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

配置参数

config

-c CONFIG, --config CONFIG

Gunicorn配置文件路径,路径形式的字符串格式,如:

1
gunicorn -c gunicorn.conf manager:app

bind

-b ADDRESS, --bind ADDRESS

Gunicorn绑定服务器套接字,Host形式的字符串格式。Gunicorn可绑定多个套接字,如:

1
gunicorn -b 127.0.0.1:8000 -b [::1]:9000 manager:app

backlog

--backlog

未决连接的最大数量,即等待服务的客户的数量。必须是正整数,一般设定在64~2048的范围内,一般设置为2048,超过这个数字将导致客户端在尝试连接时错误

workers

-w INT, --workers INT

用于处理工作进程的数量,为正整数,默认为1。worker推荐的数量为当前的CPU个数*2 + 1。计算当前的CPU个数方法:

1
2
import multiprocessing
print multiprocessing.cpu_count()

worker_class

-k STRTING, --worker-class STRTING

要使用的工作模式,默认为sync。可引用以下常见类型“字符串”作为捆绑类:

1
2
3
4
5
6
sync
eventlet:需要下载eventlet>=0.9.7
gevent:需要下载gevent>=0.13
tornado:需要下载tornado>=0.2
gthread
gaiohttp:需要python 3.4和aiohttp>=0.21.5

threads

--threads INT

处理请求的工作线程数,使用指定数量的线程运行每个worker。为正整数,默认为1。

worker_connections

--worker-connections INT

最大客户端并发数量,默认情况下这个值为1000。此设置将影响geventeventlet工作模式

max_requests

--max-requests INT

重新启动之前,工作将处理的最大请求数。默认值为0。

max_requests_jitter

--max-requests-jitter INT

要添加到max_requests的最大抖动。抖动将导致每个工作的重启被随机化,这是为了避免所有工作被重启。randint(0,max-requests-jitter)

timeout

-t INT, --timeout INT

超过这么多秒后工作将被杀掉,并重新启动。一般设定为30秒

graceful_timeout

--graceful-timeout INT

优雅的人工超时时间,默认情况下,这个值为30。收到重启信号后,工作人员有那么多时间来完成服务请求。在超时(从接收到重启信号开始)之后仍然活着的工作将被强行杀死。

keepalive

--keep-alive INT

keep-alive连接上等待请求的秒数,默认情况下值为2。一般设定在1~5秒之间。

limit_request_line

--limit-request-line INT

HTTP请求行的最大大小,此参数用于限制HTTP请求行的允许大小,默认情况下,这个值为4094。值是0~8190的数字。此参数可以防止任何DDOS攻击

limit_request_fields

--limit-request-fields INT

限制HTTP请求中请求头字段的数量。此字段用于限制请求头字段的数量以防止DDOS攻击,与limit-request-field-size一起使用可以提高安全性。默认情况下,这个值为100,这个值不能超过32768

limit_request_field_size

--limit-request-field-size INT

限制HTTP请求中请求头的大小,默认情况下这个值为8190。值是一个整数或者0,当该值为0时,表示将对请求头大小不做限制

reload

--reload

代码更新时将重启工作,默认为False。此设置用于开发,每当应用程序发生更改时,都会导致工作重新启动。

reload_engine

--reload-engine STRTING

选择重载的引擎,支持的有三种:

1
2
3
auto
pull
inotity:需要下载

spew

--spew

打印服务器执行过的每一条语句,默认False。此选择为原子性的,即要么全部打印,要么全部不打印

check_config

--check-config

显示现在的配置,默认值为False,即显示。

preload_app

--preload

在工作进程被复制(派生)之前加载应用程序代码,默认为False。通过预加载应用程序,你可以节省RAM资源,并且加快服务器启动时间。

chdir

--chdir

加载应用程序之前将chdir目录指定到指定目录

daemon

--daemon

守护Gunicorn进程,默认False

raw_env

-e ENV, --env ENV

设置环境变量(key=value),将变量传递给执行环境,如:

1
gunicorin -b 127.0.0.1:8000 -e abc=123 manager:app

在配置文件中写法:

1
raw_env=["abc=123"]

pidfile

-p FILE, --pid FILE

设置pid文件的文件名,如果不设置将不会创建pid文件

worker_tmp_dir

--worker-tmp-dir DIR

设置工作临时文件目录,如果不设置会采用默认值。

accesslog

--access-logfile FILE

要写入的访问日志目录

access_log_format

--access-logformat STRING

要写入的访问日志格式。如:

1
2
access_log_format = '%(h)s %(l)s %(u)s %(t)s'
access_log_format = '%(h)s %(t)s "%(r)s" %(s)s %(b)s'
识别码 说明
h 远程地址
l “-“
u 用户名
t 时间
r 状态行,如:GET
m 请求方法
U 没有查询字符串的URL
q 查询字符串
H 协议
s 状态码
B response长度
b response长度(CLF格式)
f 参考
a 用户代理
T 请求时间,单位为s
D 请求时间,单位为ms
p 进程id
{Header}i 请求头
{Header}o 相应头
{Variable}e 环境变量

errorlog

--error-logfile FILE, --log-file FILE

要写入错误日志的文件目录。

loglevel

--log-level LEVEL

错误日志输出等级。

支持的级别名称为:

  • debug(调试)
  • info(信息)
  • warning(警告)
  • error(错误)
  • critical(危急)

更多配置

用于Flask

开发flask应用时,常用flask-script添加一些命令扩展。而部署应用时,就不需要再从flask-scriptManager实例中启动应用了。

main.py

1
2
3
4
5
6
7
8
9
10
#main.py
from flask import Flask
app = Flask(__name__)

@app.route('/')
def index():
return 'hello world'

if __name__ == '__main__':
app.run()

调试

1
2
3
# main为程序入口的py文件名, app是Flask应用名
# main.py 中 app = Flask(__name__)
gunicorn -w 4 -b 127.0.0.1:5000 main:app
  • -w 是设置运行工作线程数
  • -b 是设置监听IP和端口

配置文件

1
2
3
4
5
6
7
8
9
10
11
# 并行工作线程数
workers = 4
# 监听内网端口5000
bind = '127.0.0.1:5000'
# 设置守护进程
daemon = True
# 设置超时时间120s,默认为30s。按自己的需求进行设置
timeout = 120
# 设置访问日志和错误信息日志路径
accesslog = '/data/logs/acess.log'
errorlog = '/data/logs/error.log'

运行

1
2
# gunicorn 运行模块名:应用名 -c 配置文件
gunicorn main:app -c gunicorn.conf

配置wsgi

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# -*- coding: utf-8 -*-
import os

from . import create_app
import datetime

application = app = create_app('default')

@app.context_processor
def template_extras():
"""
上下文处理装饰器,返回的字典的键可以在上下文中使用
:return:
"""
return {'enumerate': enumerate, 'len': len, 'datetime': datetime}
  • 在wsgi文件中创建flask实例给gunicorn使用。
  • 创建实例后,注册上下文装饰器。
1
gunicorn -b 127.0.0.1:8000 -k gevent -w 1 app.wsgi

待验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# _*_ coding=utf-8 _*_

from walkerfree import app
from walkerfree.config import config
from walkerfree import bootstrap
from walkerfree import mail
from walkerfree import moment
from walkerfree import db
from walkerfree import cache
from walkerfree import dispatch_handlers, register_blueprints, register_jinja_env, configure_assets, configure_logging


def create_app(config_name):
app.config.from_object(config[config_name])
config[config_name].init_app(app)
bootstrap.init_app(app)
mail.init_app(app)
moment.init_app(app)
db.init_app(app)
cache.init_app(app)

dispatch_handlers(app)
register_blueprints(app)
register_jinja_env(app)
configure_logging(app)
configure_assets(app)

return app


application = create_app('production')

if __name__ == '__main__':
application.run()

###
gunicorn wsgi:application -c gunicorn.conf

生命周期

  • nginx接收到客户端发来的请求,根据路由转发给wsgi
  • wsgi服务根据wsgi协议解析请求,设置环境变量
  • 调用start_response方法调用flask框架
  • flask根据env环境变量,请求参数和路径找到对应处理函数,生成html
  • wsgi拿到html,再根据env变量组装成一个http响应,发送给nginx
  • nginx再把响应发送给客户端

用于Django

配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import os
from multiprocessing import cpu_count

#配置nginx时,需要将此地址写入nginx配置文件中
bind=["127.0.0.1:9000"]
proc_name = "project"
# 守护进程
daemon = True
# reload = True
workers = cpu_count()*2
# gthread eventlet gevent
worker_class = "gevent"
forworded_allow_ips = '*'

# threads = 10
keepalive = 6
timeout = 65
graceful_timeout = 10
worker_connections = 65535
# pidfile = "g.pid"
accesslog = "/data/logs/g_access.log"
errorlog = "/data/logs/g_error.log"
access_log_format = '%(h)s %(t)s "%(r)s" %(s)s %(b)s'

启动

1
2
3
4
方式一:
gunicorn -c gunicorn-config.py project.wsgi
方式二:
gunicorn --bind 0.0.0.0:8000 project.wsgi:application

性能测试

1
ab -n 1000 -c 10 http://127.0.0.1:9000/post/home

nginx配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
upstream app_server {
server 127.0.0.1:8000; #与gunicorn配置中bind的地址一致
}

server {
listen 80;
server_name _;

access_log host.access.log main;

location = /favicon.ico {
empty_gif;
access_log off;
}

location /static/ {
root /data/www/;
expires 30d;
access_log off;
}

location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server;
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}

usgi

1
uwsgi --http 0.0.0.0:9000 --wsgi-file manager.py --callable app --processes 4 --threads 2 --stats 0.0.0.0:5000
参数名 含义
–http 协议类型和端口号
–processes 开启的进程数量
–callable uWSGI加载的模块哪个变量将被调用
–workers 开启的进行数量,等同于processes
–chdir 指定运行目录
–wsgi-file 载入wsgi-file(加载wsgi.py文件)
–stats 在指定的地址上开启状态服务
–threads 开启的线程数量
–master 允许主进程存在
–daemonize 使进程在后台运行,并将日志输出到指定的日志文件或者UDP服务器
–pidfile 指定PID文件的位置,记录主进程的PID号
–vacuum 当服务器退出时自动清理环境,删除Unix