gunicorn 高性能wsgi服务器
参考
: https://zhuanlan.zhihu.com/p/102716258
Gunicorn是什么
Gunicorn Green Unicorn
是一个 UNIX 下的 WSGI HTTP 服务器,它是一个 移植自 Ruby 的 Unicorn 项目的 pre-fork worker 模型。
Gunicorn启动项目之后一定会有一个主进程Master和一个或者多个工作进程。工作进程的数量可以指定。主进程是维护服务器的运行,工作进程是实际处理请求的进程。所有请求和响应均由 Worker 处理。
同步的 Worker 一次处理一个请求。
gunicorn flask 压测对比
测试例子: demo.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return 'hello world!'
if __name__ == '__main__':
app.run()
Flask启动压测
直接运行demo.py,使用flask自带的WSGI
[jian@laptop practics]$ python demo.py
* Serving Flask app "demo" (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
2.使用ab工具进行压测
[jian@laptop practics]$ ab -n 500 -c 500 http://localhost:5000/
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 localhost (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Finished 500 requests
Server Software: Werkzeug/0.16.0
Server Hostname: localhost
Server Port: 5000
Document Path: /
Document Length: 12 bytes
Concurrency Level: 500
Time taken for tests: 0.477 seconds
Complete requests: 500
Failed requests: 0
Total transferred: 83000 bytes
HTML transferred: 6000 bytes
Requests per second: 1049.28 [#/sec] (mean)
Time per request: 476.515 [ms] (mean)
Time per request: 0.953 [ms] (mean, across all concurrent requests)
Transfer rate: 170.10 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 3 4.6 0 11
Processing: 13 111 29.4 122 161
Waiting: 2 110 29.5 121 159
Total: 13 114 26.1 122 164
Percentage of the requests served within a certain time (ms)
50% 122
66% 124
75% 125
80% 128
90% 136
95% 145
98% 153
99% 160
100% 164 (longest request)
上面结果可以得出,同时并发500请求,压测结果是这样:
Requests per second: 1049.28 [#/sec] (mean)
Time per request: 476.515 [ms] (mean)
Time per request: 0.953 [ms] (mean, across all concurrent
Gunicorn启动压测
1.使用gunicorn启动, 这里启动4个进程
其中: -w 为开启n个进程 -b 监听地址
[jian@laptop practics]$ gunicorn -w 4 -b 0.0.0.0:8000 demo:app
[2020-01-10 21:08:56 +0800] [15563] [INFO] Starting gunicorn 19.7.1
[2020-01-10 21:08:56 +0800] [15563] [INFO] Listening at: http://0.0.0.0:8000 (15563)
[2020-01-10 21:08:56 +0800] [15563] [INFO] Using worker: sync
[2020-01-10 21:08:56 +0800] [15670] [INFO] Booting worker with pid: 15670
[2020-01-10 21:08:56 +0800] [15671] [INFO] Booting worker with pid: 15671
[2020-01-10 21:08:56 +0800] [15672] [INFO] Booting worker with pid: 15672
[2020-01-10 21:08:56 +0800] [15675] [INFO] Booting worker with pid: 15675
2.使用ab工具进行压测
[jian@laptop practics]$ ab -n 500 -c 500 http://localhost:8000/
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 localhost (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Finished 500 requests
Server Software: gunicorn/19.7.1
Server Hostname: localhost
Server Port: 8000
Document Path: /
Document Length: 12 bytes
Concurrency Level: 500
Time taken for tests: 0.111 seconds
Complete requests: 500
Failed requests: 0
Total transferred: 86000 bytes
HTML transferred: 6000 bytes
Requests per second: 4522.80 [#/sec] (mean)
Time per request: 110.551 [ms] (mean)
Time per request: 0.221 [ms] (mean, across all concurrent requests)
Transfer rate: 759.69 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 4 6.9 0 16
Processing: 5 21 5.8 22 28
Waiting: 1 21 5.9 22 28
Total: 18 26 4.7 25 41
Percentage of the requests served within a certain time (ms)
50% 25
66% 27
75% 28
80% 28
90% 31
95% 37
98% 40
99% 40
100% 41 (longest request)
上面结果可以得出,同时并发500请求,压测结果是这样:
Requests per second: 4522.80 [#/sec] (mean)
Time per request: 110.551 [ms] (mean)
Time per request: 0.221 [ms] (mean, across all concurrent
可以明显看到Requests per second: 明显比flask自带的要高 而且Time per request 也少了很多
问题
gunicorn并发比flask好的原因
1.单 Worker
只有一个进程在跑所有的请求,而由于实现的简陋性,内置 webserver 很容易卡死。
并且只有一个 Worker 在跑请求。在多核 CPU 下,仅仅占用一核。
当然,其实也可以多起几个进程。
2.缺乏 Worker 的管理
加入负载量上来了,Gunicorn 可以调节 Worker 的数量
flask内置的 Webserver 是不适合做这种事情的
一言以蔽之,太弱,几个请求就打满了
gunicorn和flask通信 流程
nginx<->gunicorn<->flask
gunicorn 几种 worker 性能测试比较
1.Gunicorn目前自带支持几种工作方式:
- sync (默认值) :最简单的同步工作模式
- eventlet :基于Greenlet库,利用python协程实现的
- gevent: 基于Greenlet库,利用python协程实现的
- tornado: 利用python Tornado框架实现
- gaiohttp:利用aiohttp库实现异步I/O,支持web socket
- gthread:线程工作模式,利用线程池管理连接
sync
sync 模式(同步工作模式)
这是最基本的工作模式,也是默认的工作模式,线程为native类型。即请求先来后到,排队模式。
eventlet 模式(协程异步)
eventlet 工作模式是基于eventlet库,利用python协程实现的。
要使用该工作模式的话必须先安装eventlet库,并且版本要大于等于0.24.1
gevent模式(协程异步)
gevent是基于Greentlet库,利用python协程实现的。
Gunicorn允许通过设置对应的worker类来使用这些异步Python库。这里的设置适用于我们想要在单核机器上运行的gevent
tornado模式
tornado利用python Tornado框架来实现。 安装的tornado库的版本要大于等于0.2。
gthread模式
gthread采用的是线程工作模式,利用线程池管理连接,需要安装gthread库。
参数
--worker-class STRTING要使用的工作模式,默认为sync异步
-w INT, --workers INT用于处理工作进程的数量,为正整数,默认为1;
2.安装测试模块
[jian@laptop tmp]$ cat requirements.txt
gunicorn==19.7.1
flask==1.1.1
flask-redis==0.4.0
gevent==1.2.2
tornado==4.5.3
eventlet==0.25.1
#这里要特别注意tornado版本必须是5.0以下,不然gunicorn 在启动会报错:
TypeError: __init__() got an unexpected keyword argument 'io_loop'
[jian@laptop tmp]$ pip install -r requirements.txt
测试例子
测试环境: Fedora 29 x64
需要安装redis , 可以使用下面命令进行安装:
[root@laptop ~]# dnf install redis
开启redis服务:
[root@laptop ~]# /usr/bin/redis-server /etc/redis.conf
测试程序:
from flask import Flask
from flask_redis import FlaskRedis
REDIS_URL = "redis://:@localhost:6379/0"
app = Flask(__name__)
app.config.from_object(__name__)
redis = FlaskRedis(app, True)
@app.route('/')
def index():
redis.incr("hit", 1)
return redis.get("hit")
if __name__ == '__main__':
app.run()
开始测试
分别使用四种方式开启服务
[jian@laptop practics]$ gunicorn -w 4 demo:app --worker-class sync
[jian@laptop practics]$ gunicorn -w 4 demo:app --worker-class gevent
[jian@laptop practics]$ gunicorn -w 4 demo:app --worker-class tornado
[jian@laptop practics]$ gunicorn -w 4 demo:app --worker-class eventlet
使用ab工具,并行500个客户端,发送50000次请求,压测命令:
[jian@laptop practics]$ ab -c 500 -t 30 -r http://localhost:8000/
测试结果
Worker class | Time taken for tests | Complete requests | Failed requests | Requests per second | 用户平均请求等待时间 | 服务器平均处理时间 | 最小连接时间 | 平均连接时间 | 50%的连接时间 | 最大连接时间 |
---|---|---|---|---|---|---|---|---|---|---|
sync | 43.362s | 49719 | 157 | 1146.61 | 436.069ms | 0.872ms | 12ms | 55ms | 25ms | 33574ms |
gevent | 13.062s | 50000 | 0 | 3827.96 | 130.618ms | 0.261ms | 3ms | 129ms | 96ms | 1477ms |
tornado | 27.925s | 50000 | 17 | 1790.50 | 279.252ms | 0.559ms | 16ms | 146ms | 27850ms | 53547ms |
eventlet | 12.601s | 50000 | 0 | 3967.88 | 126.012ms | 0.252ms | 9ms | 125ms | 1377ms | 3123ms |
eventlet 和gevent两种方式效果最好,数据基本差不多.
gunicorn 配置
workers模式
每个worker都是一个加载python应用程序的UNIX进程 worker之间没有共享内存
建议workers 数量是 (2*CPU) + 1
多线程模式
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
建议最大并发数 是(2*CPU) +1
伪线程 gevent (协程)
gunicorn --worker-class=gevent --worker-connections=1000 -w 3 main:app
work-connections 是对gevent worker类的特殊设置
建议workers数量 仍然是 (2*CPU) + 1
在这种情况下,最大的并发请求数 是3000(3个worker * 1000连接/worker)
建议
- IO 受限 -建议使用gevent或者asyncio
- CPU受限 -建议增加workers数量
- 不确定内存占用? -建议使用gthread
- 不知道怎么选择? -建议增加workers数量
其他备注
Gunicorn对静态文件的支持不太好,所以生产环境下常用Nginx作为反向代理服务器。
生产环境都是Nginx + gunicorn + flask
Fastapi 和 gunicorn
fastapi 自带一个叫做 uvicorn的 wsgi 服务器,通常用于开发调试。生产环境中主要使用gunicorn作为wsgi。
生产环境中使用gunicorn的方式如下:
gunicorn -w 1 -k uvicorn.workers.UvicornWorker -c gunicorn_conf.py main:app
fastapi要在工作进程中使用的与gunicorn兼容的工作类。fastapi中需要使用 uvicorn.workers.UvicornWorker
Uvicorn为单进程的ASGI server,而Gunicorn是管理运行多个Uvicorn,以达到并发与并行的最好效果在fastapi中,使用gunicorn管理uvicorn,gunicorn可以启动多个uvicorn进程,并管理这些进程。
gunicorn 高性能wsgi服务器的更多相关文章
- 分享关于搭建高性能WEB服务器的一篇文章
这篇文章主要介绍了Centos5.4+Nginx-0.8.50+UWSGI-0.9.6.2+Django-1.2.3搭建高性能WEB服务器的相关资料,需要的朋友可以参考下(http://m.0813s ...
- Netty实现高性能RPC服务器优化篇之消息序列化
在本人写的前一篇文章中,谈及有关如何利用Netty开发实现,高性能RPC服务器的一些设计思路.设计原理,以及具体的实现方案(具体参见:谈谈如何使用Netty开发实现高性能的RPC服务器).在文章的最后 ...
- SSDB:高性能数据库服务器
SSDB是一个开源的高性能数据库服务器, 使用Google LevelDB作为存储引擎, 支持T级别的数据, 同时支持类似Redis中的zset和hash等数据结构, 在同时需求高性能和大数据的条件下 ...
- NGINX高性能Web服务器详解(读书笔记)
原文地址:NGINX高性能Web服务器详解(读书笔记) 作者:夏寥寥 第4章 Nginx服务器的高级配置 4.1 针对IPv4的内核7个参数的配置优化 说明:我们可以将这些内核参数的值追加到Linu ...
- 高性能图片服务器–ZIMG
2011年李彦宏在百度联盟峰会上就提到过互联网的读图时代已经到来1,图片服务早已成为一个互联网应用中占比很大的部分,对图片的处理能力也相应地变成企业和开发者的一项基本技能.需要处理海量图片的典型应用有 ...
- 高性能Linux服务器 第11章 构建高可用的LVS负载均衡集群
高性能Linux服务器 第11章 构建高可用的LVS负载均衡集群 libnet软件包<-依赖-heartbeat(包含ldirectord插件(需要perl-MailTools的rpm包)) l ...
- 高性能Linux服务器 第10章 基于Linux服务器的性能分析与优化
高性能Linux服务器 第10章 基于Linux服务器的性能分析与优化 作为一名Linux系统管理员,最主要的工作是优化系统配置,使应用在系统上以最优的状态运行.但硬件问题.软件问题.网络环境等 ...
- 高性能Linux服务器 第6章 ext3文件系统反删除利器ext3grep extundelete工具恢复rm -rf 误删除的文件
高性能Linux服务器 第6章 ext3文件系统反删除利器ext3grep extundelete工具恢复rm -rf 误删除的文件 只能用于ext3文件系统!!!!!!!高俊峰(高性能Linux ...
- 优化系统资源ulimit《高性能Linux服务器构建实战:运维监控、性能调优与集群应用》
优化系统资源ulimit<高性能Linux服务器构建实战:运维监控.性能调优与集群应用> 假设有这样一种情况,一台Linux 主机上同时登录了10个用户,在没有限制系统资源的情况下,这10 ...
- 优化Linux内核参数/etc/sysctl.conf sysctl 《高性能Linux服务器构建实战:运维监控、性能调优与集群应用》
优化Linux内核参数/etc/sysctl.conf sysctl <高性能Linux服务器构建实战:运维监控.性能调优与集群应用> http://book.51cto.com/ar ...
随机推荐
- 混合应用与Hybrid App开发上架流程透析
Hybrid App(混合 App)已经成为大家接触最为广泛的 App 形式,不管是我们用到的微信.支付宝还是淘宝.京东等大大小小的应用都非常热衷于Hybrid App 带来的研发效率提升和灵活性. ...
- Codeforces Round #736 (Div. 2). D - Integers Have Friends
原题:D - Integers Have Friends 题意: 给定一个数组,求一个最长子数组满足\(a_i \,\, mod \,\, m \,\, = \,\, a_{i + 1} \,\, m ...
- 哈希表(hash)
散列表(Hash table,也叫哈希表),是根据键(Key)而直接访问在内存储存位置的数据结构.也就是说,它通过计算一个关于键值的函数,将所需查询的数据映射到表中一个位置来访问记录,这加快了查找速度 ...
- 一个简单案例的Vue2.0源码
本文学习vue2.0源码,主要从new Vue()时发生了什么和页面的响应式更新2个维度了解Vue.js的原理.以一个简单的vue代码为例,介绍了这个代码编译运行的流程,在流程中原始DOM的信息会被解 ...
- 搭建 MongoDB (v6.0) 副本集记录
副本集概述 副本集(Replica Set)是一组带有故障转移的 MongoDB 实例组成的集群,由一个主(Primary)服务器和多个从(Secondary)服务器构成.通过Replication, ...
- 总结--flask部分
Flask框架的诞生: Flask诞生于2010年,是Armin ronacher(人名)用Python语言基于Werkzeug工具箱编写的轻量级Web开发框架. Flask本身相当于一个内核,其他几 ...
- 如何在langchain中对大模型的输出进行格式化
简介 我们知道在大语言模型中, 不管模型的能力有多强大,他的输入和输出基本上都是文本格式的,文本格式的输入输出虽然对人来说非常的友好,但是如果我们想要进行一些结构化处理的话还是会有一点点的不方便. 不 ...
- GPTs大受欢迎但问题多,企服软件厂商的AI Agent更被B端客户器重
GPTs大受欢迎但问题多,企服软件厂商的AI Agent更被B端客户器重 比尔盖茨预言智能体是下个平台,超自动化平台的AI Agent更靠谱? 以GPTs为代表的AI Agent只是玩具?揭秘真实可用 ...
- js检测数据类型得四种方式
1.typeof:返回一个字符串,表示操作数的类型. 语法: typeof(变量) //or typeof 变量 示例: console.log(typeof 2)//number c ...
- windows下tomcat开机自启动
在Windows下,可以通过以下步骤将Tomcat设置为开机自启动: 1. 打开Tomcat安装目录:通常情况下,Tomcat的安装目录位于`C:\Program Files\Apache Softw ...