gunicorn
1. 简介
官网:https://gunicorn.org/#docs
Gunicorn 'Green Unicorn' is a Python WSGI HTTP Server for UNIX. It's a pre-fork worker model. The Gunicorn server is broadly compatible with various web frameworks, simply implemented, light on server resources, and fairly speedy.
它是一个pythonWSGI HTTP Server,运行于UNIX平台。pre-fork worker model。
Gunicorn是一个unix上被广泛使用的高性能的Python WSGI UNIX HTTP Server。
和大多数的web框架兼容,并具有实现简单,轻量级,高性能等特点。
1.1. 相关概念
架构
服务模型(Server Model)
Gunicorn是基于pre-fork模型的。也就意味着有一个中心管理进程(masterprocess)用来管理worker进程集合。Master从不知道任何关于客户端的信息。所有的请求和响应处理都是由worker进程来处理的。
Master(管理者)
主程序是一个简单的循环,监听各种信号以及相应的响应进程。master管理着正在运行的worker集合,通过监听各种信号比如TTIN,TTOU,andCHLD.TTINandTTOU响应的增加和减少worker的数目。CHLD信号表明一个子进程已经结束了,在这种情况下master会自动的重启失败的worker。
worker
woker有很多种,包括:ggevent、geventlet、gtornado等等。这里主要分析ggevent。
每个ggeventworker启动的时候会启动多个server对象:worker首先为每个listener创建一个server对象(注:为什么是一组listener,因为gunicorn可以绑定一组地址,每个地址对于一个listener),每个server对象都有运行在一个单独的geventpool对象中。真正等待链接和处理链接的操作是在server对象中进行的。
1.2. gunicorn安装
pip install gunicorn
示例:
wsgi_my.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from app import create_app
application = app = create_app()
1.2.1. 测试运行
gunicorn wsgi_my:app
默认绑定127.0.0.1,所以不能在其它ip访问
测试结果:
[root@soft ~]# curl http://localhost:8000
Index.
[root@soft ~]# curl http://localhost:8000/hello
Hello. number: 1
[root@soft ~]# curl http://localhost:8000/hello
Hello. number: 2
1.3. 使用及配置
doc: https://docs.gunicorn.org/en/stable/run.html
gunicorn
最简单的运行方式:gunicorn code:application
Gunicorn从三个不同地方获取配置:
框架设置(通常只影响到Paster应用)
配置文件(python文件):配置文件中的配置会覆盖框架的设置。
命令行
框架设置只跟Paster(一个Web框架)有关,不讨论;命令行配置如上部分所示;
1.3.1. 命令行常用配置参数:
-c CONFIG, --config=CONFIG - Specify a config file in the form $(PATH), file:$(PATH), or python:$(MODULE_NAME).指定配置文件
-b BIND, --bind=BIND - Specify a server socket to bind. Server sockets can be any of $(HOST), $(HOST):$(PORT)指定监听端口.
-w WORKERS, --workers=WORKERS - The number of worker processes. This number should generally be between 2-4 workers per core in the server. Check the FAQ for ideas on tuning this parameter.指定进程数,一般建议数量设置为2*CPU+1
-k WORKERCLASS, --worker-class=WORKERCLASS - The type of worker process to run. You’ll definitely want to read the production page for the implications of this parameter. You can set this to $(NAME) where $(NAME) is one of sync, eventlet, gevent, tornado, gthread, gaiohttp (deprecated). sync is the default. See the worker_class documentation for more information.
工作模式,有多种,默认sync,一般gevent,tornado。
--backlog INT 指定最大挂起的连接数;
--log-level LEVEL:debug,info,warning,error,critical
--access-logfile FILE 日志文件,-表示输出到标准输出
--error-logfile FILE 错误日志文件
典型启动命令:
gunicorn -w 1 -k gevent wsgi_my -b 0.0.0.0:9000
1.3.2. 配置文件启动
生产中通常通过配置文件指定参数,它必须是一个python文件,只是将命令行中的参数写进py文件中而已,如果需要设置哪个参数,则在py文件中为该参数赋值即可。
配置文件案例:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# gunicorn 配置文件
import multiprocessing
debug = True
loglevel = 'debug'
bind = "0.0.0.0:9000"
# 最大挂起连接数
backlog = 512
# 日志
pidfile = "log/gunicorn.pid"
accesslog = "log/access.log"
errorlog = "log/debug.log"
#daemon = True
daemon = False
# 启动的进程数
workers = multiprocessing.cpu_count()
worker_class = 'gevent'
# 进程沉默限制时间,超过会重启该worker,单位秒,通常设为30
timeout = 30
x_forwarded_for_header = 'X-FORWARDED-FOR'
启动server
gunicorn -c gunicorn_conf.py wsgi_my:app
注意:指定app时不要有后缀名(例如wsgi_my.py),否则会找不到app
日志文件需要手动创建
2. 测试
2.1. 并发模式测试1-验证可用性
测试环境准备:
- 在路由函数中添加阻塞代码time.sleep(2)
- 请求使用deferred模拟并发,具体代码见下文;
flask自带server及uWSGI是不支持并发的;
直接运行app:python run.py
测试结果:
测试并发请求数:5 测试耗时:10.08759880065918
使用gvent模式
[root@soft website]# gunicorn -w 1 -k gevent wsgi_my -b 0.0.0.0:9000
测试并发请求数:5 测试耗时:2.1450159549713135
结果释义:
阻塞模式下不能同时处理多个请求,所以耗时为2*5,最终大约为10;
协程模式下可以同时处理多个请求,所以耗时为2*1,最终大约为2;
2.1.1. 并发测试代码
import time
from twisted.internet import defer, reactor
from twisted.web.client import getPage
# 测试url
url = b"http://192.168.199.129:9000/hello"
def time_count(*args, **kw):
print('测试结束。')
t = time.time()
print("测试并发请求数:{} 测试耗时:{}".format(kw['req_nums'], t - kw['t_start']))
t_start = time.time()
d = defer.DeferredList([getPage(url) for x in range(5)])
#d = getPage(url)
d.addCallbacks(time_count, lambda x:print('error'), callbackKeywords={'req_nums':5, 't_start':t_start})
reactor.callLater(20, reactor.stop)
reactor.run()
2.2. 性能测试
主要测试flask+ gunicorn与werkzurg的性能。
2.2.1. python自带web server
E:\Apache24\bin>ab -n 3000 -c 50 http://192.168.199.129:9000/req_test
This is ApacheBench, Version 2.3 <$Revision: 1843412 $>
Benchmarking 192.168.199.129 (be patient)
Completed 3000 requests
Finished 3000 requests
Server Software: Werkzeug/0.14.1
Server Hostname: 192.168.199.129
Server Port: 9000
Document Path: /req_test
Document Length: 27 bytes
Concurrency Level: 50
Time taken for tests: 27.518 seconds
Complete requests: 3000
Failed requests: 2951
(Connect: 0, Receive: 0, Length: 2951, Exceptions: 0)
Total transferred: 548002 bytes
HTML transferred: 86002 bytes
Requests per second: 109.02 [#/sec] (mean)
Time per request: 458.632 [ms] (mean)
Time per request: 9.173 [ms] (mean, across all concurrent requests)
Transfer rate: 19.45 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 1 3.0 1 73
Processing: 35 454 72.2 429 683
Waiting: 4 453 72.1 427 680
Total: 35 455 72.4 430 684
Percentage of the requests served within a certain time (ms)
50% 430
66% 457
75% 499
80% 518
90% 569
95% 592
98% 613
99% 628
100% 684 (longest request)
2.2.2. gunicorn gevent模式
gunicorn -w 1 -k gevent wsgi_my -b 0.0.0.0:9000
E:\Apache24\bin>ab -n 3000 -c 50 http://192.168.199.129:9000/req_test
This is ApacheBench, Version 2.3 <$Revision: 1843412 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 192.168.199.129 (be patient)
Finished 3000 requests
Concurrency Level: 50
Time taken for tests: 10.541 seconds
Complete requests: 3000
Failed requests: 2991
(Connect: 0, Receive: 0, Length: 2991, Exceptions: 0)
Total transferred: 565893 bytes
HTML transferred: 85893 bytes
Requests per second: 284.60 [#/sec] (mean)
Time per request: 175.688 [ms] (mean)
Time per request: 3.514 [ms] (mean, across all concurrent requests)
Transfer rate: 52.43 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 1 0.4 1 3
Processing: 32 174 16.6 171 277
Waiting: 2 173 16.7 170 277
Total: 32 174 16.6 172 278
Percentage of the requests served within a certain time (ms)
50% 172
66% 174
75% 176
80% 177
90% 184
95% 190
98% 217
99% 276
100% 278 (longest request)
2.2.3. 测试结果解析
无论是从任务总时长,单个任务耗时各项指标上看,gevent模式是大大优于同步阻塞模式的。至于说具体优化比例要取决于各项因素了,这里的实验环境只是一台虚拟机,不具有实际应用意义。
3. 总结
常用命令
gunicorn -w 1 -k gevent wsgi_my -b 0.0.0.0:9000
gunicorn -c gunicorn_conf.py wsgi_my