gunicorn实现flask并发
目录
一、什么是gunicorn
1、简介
2、优势
3、源码分析入口
二、gunicorn安装部署
三、gunicorn简单应用
四、gunicorn worker Model
1、同步worker模式sync
2、异步worker模式
3、Tornado Workers
4、AsyncIO Workers(gthread, gaiohttp)
5、各模式对比
6、如何选择工作模式
五、gunicorn启动多少个workers子进程
六、如何动态修改worker数量
七、多线程模式
八、gevent协程-实现高并发
九、gunicorn部署
十、压力测试
1、Flask原生压力测试
2、gunicorn并发压测压力测试
3、当并发用户数为1时,二者吞吐率几乎一样
4、ab参数说明
十二、eventlet和gevent对比
1、Gevent简介
2、eventlet简介
一、什么是gunicorn
1、简介
Gunicorn(绿色独角兽Green Unicorn的简称),是一个Python WSGI HTTP server,只支持在Unix系统上运行,来源于Ruby的unicorn项目。
Gunicorn服务器广泛兼容各种web框架,实现简单,服务器资源少,而且速度相当快。官方建议Nginx+gunicorn性能最好。
2、优势
Gunicorn的优势在于,它采用的是pre-fork worker模式, gunicorn在启动时,会在主进程中预先fork出指定数量的worker进程来处理请求,即一个master进程管理多个worker进程(管理进程:master,工作进程:worker),所有请求和响应均由Worker处理。
Master进程是一个简单的loop, 监听 worker不同进程信号并且作出响应。这样可以减少频繁创建和销毁进程的开销,但是一个进程相对占用资源,会消耗大量内存。
Gunicorn推荐的worker数量是:(2*$num_cores)+1。
3、源码分析入口
https://github.com/benoitc/gunicorn/blob/master/gunicorn/app/wsgiapp.py
二、gunicorn安装部署
$ pip install gunicorn如果应用程序可能需要在请求处理期间暂停很长一段时间,这时建议安装Eventlet或Gevent,异步执行worker。$ pip install greenlet$ pip install eventlet$ pip install gevent
三、gunicorn简单应用
基本使用格式:
$ gunicorn [OPTIONS] [WSGI_APP]
使用示例,在/home/myproject目录下,创建test.py文件,如下:
def app(environ, start_response):"""Simplest possible application object"""data = b'Hello, World!\n'status = '200 OK'response_headers = [('Content-type', 'text/plain'),('Content-Length', str(len(data)))]start_response(status, response_headers)return iter([data])
运行:
$ gunicorn --workers=8 --chdir /home/myproject test:app
常用参数:
-c CONFIG, --config=CONFIG 指定配置文件-b BIND, --bind=BIND 绑定运行的主机和端口-w INT, --workers INT 用于处理worker进程的数量,默认为1-k STRTING, --worker-class STRTING 指定要使用的工作模式,默认为sync异步,类型:sync, eventlet, gevent, tornado, gthread, gaiohttp--threads INT 处理请求的工作线程数,使用指定数量的线程运行每个worker。为正整数,默认为1--worker-connections INT 最大客户端并发数量,默认1000--chdir 在加载应用程序之前切换目录
更多参数详情参考:$ gunicorn -h
四、gunicorn worker Model
Gunicorn的工作模式是通过work_class参数配置的值,默认缺省值为sync。
当前支持的工作模式类型清单:sync, eventlet, gevent, tornado, gthread, gaiohttp
1、同步worker模式sync
默认worker class,为sync worker,是最简单的工作模式,在cpu和带宽方面会消耗资源。性能低。
大多数情况下,采用的worker类型是同步方式,也就是说一次仅处理一个请求。这种模型方式是最简单的,因为期间发生的任何错误最多只影响到一个请求。
对应class SyncWorker(base.Worker) ,源码分析参考:https://github.com/benoitc/gunicorn/blob/master/gunicorn/workers/sync.py
2、异步worker模式
这里指的是greenlet worker,异步workers分两种,一个是eventlet,另一个是gevent。二者都是基于greenlets软件包。
greenlet是用python来实现的协程方式实现的(cooperative multi-threading)。源码对应文件:geventlet.py和ggevent.py。
建议采用异步worker的场景:
1)需要长时间阻塞调用的应用,比如外部的web service
2)直接给internet提供服务
3)stream流请求和响应
4)长轮询
5)Web sockets(web sockets可以允许用户在浏览器中实现双向通信,实现数据的及时推送)
6)Comet彗星(基于HTTP长连接的服务器推送技术(Server Push),是一种新的 Web 应用架构。服务器端会主动以异步的方式向客户端程序推送数据。Comet架构适用于事件驱动的 Web 应用,以及对交互性和实时性要求很强的应用)
3、Tornado Workers
可以用于使用Tornado框架编写应用程序。不推荐使用这种配置。
4、AsyncIO Workers(gthread, gaiohttp)
此worker与Python3兼容。
gaiohttp worker利用aiohttp库实现异步I/O,支持web socket;
gthread worker采用的是线程工作模式,利用线程池管理连接。它在主循环中接受连接,已接受的连接作为连接作业添加到线程池中。
5、各模式对比
sync底层实作是每个请求都由一个process处理。多进程模式,--workers参数,指定了工作进程的数量。
gthread则是每个请求都由一个thread处理。多线程模式。
eventlet、gevent底层则是利用非同步IO让一个process在等待IO回应时继续处理下个请求。协程模式。
6、如何选择工作模式
IO受限,建议使用gevent或者asyncio
CPU受限,建议增加workers数量
不确定内存占用?建议使用gthread
不知道怎么选择?建议增加workers数量
五、gunicorn启动多少个workers子进程
gunicorn可以启动多个worker子进程,每个子进程可以看做是一个独立的Flask进程。在处理请求时,gunicorn依靠操作系统来提供负载均衡。
预期多少个客户端,就启用多少个worker。gunicorn只需要启用4–12个workers,就足以每秒钟处理几百甚至上千个请求了。
推荐的worker数量是:(2 x $num_cores) + 1,这个公式很简单,它是基于给定的核心处理器数量,在其他worker处理请求时,每个worker将从socket那进行读写操作。
如果worker太多,会在某一个时刻发生系统颠簸,降低整个系统的吞吐量。
六、如何动态修改worker数量
TTIN和TTOU信号可以发送给master来增加或减少worker的数量。
将worke数增加1:
$ kill -TTIN $masterpid
将worke数量减少1:
$ kill -TTOU $masterpid
操作示例:
[root@controller1 ~]# ps -ef| grep gunicorn
root 18290 6795 0 11:00 pts/1 00:00:00 /usr/bin/python /usr/bin/gunicorn -w 3 -b 127.0.0.1:5000 --chdir /home/monitor_project start_monitor:app -k eventlet
root 18303 18290 0 11:00 pts/1 00:00:00 /usr/bin/python /usr/bin/gunicorn -w 3 -b 127.0.0.1:5000 --chdir /home/monitor_project start_monitor:app -k eventlet
root 18304 18290 0 11:00 pts/1 00:00:00 /usr/bin/python /usr/bin/gunicorn -w 3 -b 127.0.0.1:5000 --chdir /home/monitor_project start_monitor:app -k eventlet
root 18306 18290 0 11:00 pts/1 00:00:00 /usr/bin/python /usr/bin/gunicorn -w 3 -b 127.0.0.1:5000 --chdir /home/monitor_project start_monitor:app -k eventlet
root 25038 12940 0 11:01 pts/6 00:00:00 grep --color=auto gunicorn
[root@controller1 ~]# kill -TTIN 18290
[root@controller1 ~]# kill -TTIN 18290
[root@controller1 ~]# ps -ef| grep gunicorn
root 18290 6795 0 11:00 pts/1 00:00:00 /usr/bin/python /usr/bin/gunicorn -w 3 -b 127.0.0.1:5000 --chdir /home/monitor_project start_monitor:app -k eventlet
root 18303 18290 0 11:00 pts/1 00:00:00 /usr/bin/python /usr/bin/gunicorn -w 3 -b 127.0.0.1:5000 --chdir /home/monitor_project start_monitor:app -k eventlet
root 18304 18290 0 11:00 pts/1 00:00:00 /usr/bin/python /usr/bin/gunicorn -w 3 -b 127.0.0.1:5000 --chdir /home/monitor_project start_monitor:app -k eventlet
root 18306 18290 0 11:00 pts/1 00:00:00 /usr/bin/python /usr/bin/gunicorn -w 3 -b 127.0.0.1:5000 --chdir /home/monitor_project start_monitor:app -k eventlet
root 25726 18290 0 11:01 pts/1 00:00:00 /usr/bin/python /usr/bin/gunicorn -w 3 -b 127.0.0.1:5000 --chdir /home/monitor_project start_monitor:app -k eventlet
root 27029 18290 4 11:01 pts/1 00:00:00 /usr/bin/python /usr/bin/gunicorn -w 3 -b 127.0.0.1:5000 --chdir /home/monitor_project start_monitor:app -k eventlet
root 27231 12940 0 11:01 pts/6 00:00:00 grep --color=auto gunicorn
[root@controller1 ~]# kill -TTOU 18290
[root@controller1 ~]# kill -TTOU 18290
[root@controller1 ~]# kill -TTOU 18290
[root@controller1 ~]# ps -ef| grep gunicorn
root 18290 6795 0 11:00 pts/1 00:00:00 /usr/bin/python /usr/bin/gunicorn -w 3 -b 127.0.0.1:5000 --chdir /home/monitor_project start_monitor:app -k eventlet
root 25726 18290 0 11:01 pts/1 00:00:00 /usr/bin/python /usr/bin/gunicorn -w 3 -b 127.0.0.1:5000 --chdir /home/monitor_project start_monitor:app -k eventlet
root 27029 18290 0 11:01 pts/1 00:00:00 /usr/bin/python /usr/bin/gunicorn -w 3 -b 127.0.0.1:5000 --chdir /home/monitor_project start_monitor:app -k eventlet
root 31435 12940 0 11:02 pts/6 00:00:00 grep --color=auto gunicorn
[root@controller1 ~]#
七、多线程模式
gunicorn允许每个worker拥有多个线程。
多线程模式下,每个worker都会加载一次,同一个worker生成的每个线程共享相同的内存空间。
使用threads模式,每一次使用threads模式,worker类就会是gthread。
执行如下:
# gunicorn -w 5 --threads=2 main:app
等同于:
# gunicorn -w 5 --thread=2 --worker-class=gthread main:app
以上所举示例,最大的并发请求就是worker*线程,也就是10。 worker建议的最大并发数是(2*CPU) +1
八、gevent协程-实现高并发
eventlet和gevent都是协程工作模式。
以下示例,使用gevent做协程,解决高并发的问题。
$ gunicorn --worker-class=gevent --worker-connections=1000 -w 3 main:app
work-connections 是对gevent worker类的特殊设置,当前配置的最大的并发请求数是3000(3个worker*1000连接)
建议workers最大数量仍是 (2*CPU) + 1
九、gunicorn部署
管理gunicorn服务,可以使用systemd和supervisord,这里使用linux自带的系统服务管理器Systemd,来管理gunicorn服务。
下面是使用systemd为传入的Gunicorn请求创建unix套接字的配置文件和说明。Systemd将监听这个套接字,并启动gunicorn自动响应流量。
/etc/systemd/system/gunicorn.service
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target[Service]
Type=notify
# the specific user that our service will run as
User=someuser
Group=someuser
# another option for an even more restricted service is
# DynamicUser=yes
# see http://0pointer.net/blog/dynamic-users-with-systemd.html
RuntimeDirectory=gunicorn
WorkingDirectory=/home/someuser/applicationroot
ExecStart=/usr/bin/gunicorn applicationname.wsgi
ExecReload=/bin/kill -s HUP $MAINPID
KillMode=mixed
TimeoutStopSec=5
PrivateTmp=true[Install]
WantedBy=multi-user.target
/etc/systemd/system/gunicorn.socket
[Unit]
Description=gunicorn socket
[Socket]
ListenStream=/run/gunicorn.sock
# Our service won't need permissions for the socket, since it
# inherits the file descriptor by socket activation
# only the nginx daemon will need access to the socket
SocketUser=www-data
# Optionally restrict the socket permissions even more.
# SocketMode=600
[Install]
WantedBy=sockets.target
启动gunicorn.socket
systemctl enable --now gunicorn.socket
十、压力测试
Flask原生和gunicorn并发,压测对比
1、Flask原生压力测试
直接用python执行monitor.py文件:
[root@controller1 ~]# python /home/monitor_project/test_app.py
* Running on http://127.0.0.1:6666/ (Press CTRL+C to quit)
[root@controller1 ~]# ab -n 500 -c 100 http://127.0.0.1:6666/todos
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/Benchmarking 127.0.0.1 (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Finished 500 requestsServer Software: Werkzeug/1.0.1
Server Hostname: 127.0.0.1
Server Port: 6666Document Path: /todos
Document Length: 152 bytesConcurrency Level: 100
Time taken for tests: 0.571 seconds
Complete requests: 500
Failed requests: 0
Write errors: 0
Total transferred: 149000 bytes
HTML transferred: 76000 bytes
Requests per second: 876.02 [#/sec] (mean)
Time per request: 114.153 [ms] (mean)
Time per request: 1.142 [ms] (mean, across all concurrent requests)
Transfer rate: 254.93 [Kbytes/sec] receivedConnection Times (ms)min mean[+/-sd] median max
Connect: 0 1 1.4 0 5
Processing: 3 101 25.6 110 117
Waiting: 3 100 25.7 109 116
Total: 7 101 24.4 110 117Percentage of the requests served within a certain time (ms)50% 11066% 11175% 11280% 11390% 11695% 11698% 11799% 117100% 117 (longest request)
[root@controller1 ~]#
可看出 Requests per second为 876
2、gunicorn并发压测压力测试
[root@controller1 ~]# gunicorn -w 12 -b 127.0.0.1:6666 --chdir /home/myproject test_app:app -k eventlet
[2021-01-22 11:38:34 +0000] [10695] [INFO] Starting gunicorn 19.10.0
[2021-01-22 11:38:34 +0000] [10695] [INFO] Listening at: http://127.0.0.1:6666 (10695)
[2021-01-22 11:38:34 +0000] [10695] [INFO] Using worker: eventlet
使用ab进行压力测试:
[root@controller1 ~]# ab -n 500 -c 100 http://127.0.0.1:6666/todos
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/Benchmarking 127.0.0.1 (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Finished 500 requestsServer Software: gunicorn/19.10.0
Server Hostname: 127.0.0.1
Server Port: 6666Document Path: /todos
Document Length: 94 bytesConcurrency Level: 100
Time taken for tests: 0.081 seconds
Complete requests: 500
Failed requests: 0
Write errors: 0
Total transferred: 123500 bytes
HTML transferred: 47000 bytes
Requests per second: 6186.28 [#/sec] (mean)
Time per request: 16.165 [ms] (mean)
Time per request: 0.162 [ms] (mean, across all concurrent requests)
Transfer rate: 1492.20 [Kbytes/sec] receivedConnection Times (ms)min mean[+/-sd] median max
Connect: 0 1 1.5 0 6
Processing: 1 10 9.2 8 73
Waiting: 1 10 9.2 8 73
Total: 1 11 9.2 9 77Percentage of the requests served within a certain time (ms)50% 966% 1275% 1480% 1590% 2195% 3098% 4099% 44100% 77 (longest request)
[root@controller1 ~]#
对比可看出,单个程序运行和使用gunicorn,吞吐率相差很多。
可看出 Requests per second为 6186.28,吞吐性能提高了8倍。
3、当并发用户数为1时,二者吞吐率几乎一样
[root@controller1 ~]# ab -n 5000 -c 1 http://127.0.0.1:6666/todos
单进程吞吐率:
Requests per second: 876.02 [#/sec] (mean)
gunicorn多进程吞吐率:
Requests per second: 865.62 [#/sec] (mean)
4、ab参数说明
Server Hostname: 请求的URL中的主机部分名称,它来自于http请求数据的头信息。
Server Port: 被测试Web服务器监听端口。
Document Path: 请求的URL中根绝对路径,它同样来自于http请求数据的头信息,通过它的后缀名,我们一般可以理解该请求的类型。
Document Length: http响应数据的正文长度。
Concurrency Level: 并发用户数,由命令行的-c设置的参数。
Time taken for tests: 所有请求被处理完成花费的总时间。
Complete requests: 总请求数,由命令行-n设置的参数。
Failed requests: 失败的请求数。
Total transferred: 所有请求响应数据长度总和。不包括http请求数据的长度,使用ab的-v参数可查看详细的http头信息。
HTML transferred: 所有请求的响应数据中正文数据的总和,也就是减去了Total transferred中http响应数据中头信息的长度。
Requests per second:【重点关注】吞吐率,计算方法:Complete requests / Time taken for tests = Requests per second
Time per request:用户平均请求等待时间,计算方法: Time per request = Time taken for tests / (Complete requests /Concurrency Level)
Time per request(across all concurrent requests): 服务器平均请求处理时间,计算方法: Time per request(across all concurrent requests) = Time taken for tests / Complete requests
Time per request(across all concurrent requests) = 1 / Requests per second
Time per request(across all concurrent requests) = Time per request / Concurrency Level
Transfer rate :请求在单位时间内从服务器获取的数据长度,计算方法: Transfer rate = Total transferred / Time taken for tests 。这个统计项可以很好的说明服务器在处理能力达到限制时,其出口带宽的需求量。
Percentage of the requests served within a certain time(ms): 描述每个请求处理时间的分布情况。
十二、eventlet和gevent对比
1、Gevent简介
Gevent是一个基于greenlet的Python的并发框架,以微线程greenlet为核心,使用了epoll事件监听机制以及诸多其他优化而变得高效。
与greenlet、eventlet相比,Gevent性能略低,但是它封装的API非常完善,还提供了一个monkey类,可以将现有基于Python线程直接转化为greenlet。
2、eventlet简介
eventlet是一款使用Python编写的为高并发的网络编程而设计的库。由第二人生(secondlife)所开源发布。在开源云计算技术OpenStack里起到了比较重要的作用。
它通过greenlet提供的协程功能,让开发者可以不用将以往的多线程等并发程序的开发方式转变成异步状态机模型,就能直接使用select/epoll/kqueue等操作系统提供的支持高并发IO接口,并且能尽可能地发挥它们在并发上的优势。
与它同类的另一款产品是Gevent,它们有着很类似的设计。
在CPython下,由于Gevent使用了Cython绑定了libev或者libevent等C库,导致Gevent比eventlet有着更优秀的性能。
但是也因为Cython写的部分组件,导致Gevent无法借助PyPy来给它加速,而eventlet则没有这个限制。在PyPy的加速下,eventlet的性能可以有成倍的提升。
参考:
https://dormousehole.readthedocs.io/en/latest/quickstart.html
https://docs.gunicorn.org/en/latest/run.html
https://gunicorn.readthedocs.io/en/latest/
gunicorn实现flask并发相关推荐
- 利用flask写的接口(base64, 二进制, 上传视频流)+异步+gunicorn部署Flask服务+多gpu卡部署
一.flask写的接口 1.1 manage.py启动服务(发送图片base64版) 这里要注意的是用docker的话,记得端口映射 #coding:utf-8 import base64 impor ...
- 使用 Nginx + Gunicorn 部署 Flask 项目
使用 Nginx + Gunicorn 部署 Flask 项目 Flask Web 项目开发完成后,开发人员只是在开发环境运行,只有本地可以访问到项目.如果要让用户访问到项目,需要将项目部署到生产环境 ...
- python supervisor flask_python web 部署:nginx + gunicorn + supervisor + flask 部署笔记
分享一篇文章,原文来自:python web 部署. Python web 部署 web开发中,各种语言争奇斗艳,web的部署方面,却没有太多的方式.简单而已,大概都是 nginx 做前端代理,中间 ...
- Gunicorn部署Flask
Gunicorn是一个被广泛使用的高性能的Python WSGI UNIX HTTP服务组件(WSGI: Web Server Gateway Interface),移植自Ruby的独角兽(Unico ...
- gunicorn部署Flask服务
作为一个Python选手,工作中需要的一些服务接口一般会用Flask来开发. Flask非常容易上手,它自带的app.run(host="0.0.0.0", port=7001)用 ...
- 使用 gunicorn 部署flask项目
1.WSGI协议 Web框架致力于如何生成HTML代码,而Web服务器用于处理和响应HTTP请求.Web框架和Web服务器之间的通信,需要一套双方都遵守的接口协议.WSGI协议就是用来统一这两者的接口 ...
- python supervisor flask_Python Web 部署:Nginx Gunicorn Supervisor Flask部署笔记
python web 部署 web开发中,各种语言争奇斗艳,web的部署方面,却没有太多的方式.简单而已,大概都是 nginx 做前端代理,中间 webservice 调用程序脚本.大概方式:ngin ...
- 【flask】适合生产环境的高并发部署方案(gunicorn + gevent + supervisor)
文章目录 1.安装docker镜像 2.查看alphin版本 3.更换alpine源 4.更换pip源 5.安装requirements.txt 6.安装完成 7.启动flask应用 8.用gunic ...
- Flask 应用部署方式之 Flask+Gunicorn+Nginx
1. Why Flask+Gunicorn+Nginx Flask+Gunicorn+Nginx是最常用的Flask部署方案,大家深究过为何用这样的搭配么? 1.1 Why? Flask 是一个web ...
最新文章
- Android WebView缓存策略详解
- 音乐网站购买服务器,怎么样去做一个音乐网站
- 远程桌面连接时显示密码已过期
- 京东2019春招Java工程师编程题题解
- 【算法分析与设计】辗转相除法
- Android Animation学习(三) ApiDemos解析:XML动画文件的使用
- ActiveMQ消息队列的使用
- java server faces
- 手把手教你搭建Pytest+Allure2.X环境详细教程 - 01
- linux系统电脑的权限设置,Linux下的文件权限设置修改详解linux操作系统 -电脑资料...
- python 爬取实时数据django显示_python脚本采集服务器数据通过API提交到django web服务器,然后展示在页面上...
- DevExpress chartControl 数据绑定
- oBlog 4.0 正式版 2006-09-06
- ImportError: cannot import name ‘_validate_lengths‘ from ‘numpy.lib.arraypad‘完美解决方法
- 中控WinSwitch3 WinSwitch可视化软件 灯光控制管理系统
- 2022年第31届中国国际信息通信展览会
- HTML5期末大作业:XXX 网站设计——指环王:护戒使者(13页) HTML+CSS+JavaScript HTML+CSS+JS网页设计期末课程大作业 web前端开发技术 web课程设计 网页规
- 找对英语学习方法的第一本书之:标准发音
- SYN010型铷原子钟(全国产)
- python爬虫学习笔记-scrapy框架之start_url