参考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服务器的更多相关文章

  1. 分享关于搭建高性能WEB服务器的一篇文章

    这篇文章主要介绍了Centos5.4+Nginx-0.8.50+UWSGI-0.9.6.2+Django-1.2.3搭建高性能WEB服务器的相关资料,需要的朋友可以参考下(http://m.0813s ...

  2. Netty实现高性能RPC服务器优化篇之消息序列化

    在本人写的前一篇文章中,谈及有关如何利用Netty开发实现,高性能RPC服务器的一些设计思路.设计原理,以及具体的实现方案(具体参见:谈谈如何使用Netty开发实现高性能的RPC服务器).在文章的最后 ...

  3. SSDB:高性能数据库服务器

    SSDB是一个开源的高性能数据库服务器, 使用Google LevelDB作为存储引擎, 支持T级别的数据, 同时支持类似Redis中的zset和hash等数据结构, 在同时需求高性能和大数据的条件下 ...

  4. NGINX高性能Web服务器详解(读书笔记)

    原文地址:NGINX高性能Web服务器详解(读书笔记) 作者:夏寥寥 第4章  Nginx服务器的高级配置 4.1 针对IPv4的内核7个参数的配置优化 说明:我们可以将这些内核参数的值追加到Linu ...

  5. 高性能图片服务器–ZIMG

    2011年李彦宏在百度联盟峰会上就提到过互联网的读图时代已经到来1,图片服务早已成为一个互联网应用中占比很大的部分,对图片的处理能力也相应地变成企业和开发者的一项基本技能.需要处理海量图片的典型应用有 ...

  6. 高性能Linux服务器 第11章 构建高可用的LVS负载均衡集群

    高性能Linux服务器 第11章 构建高可用的LVS负载均衡集群 libnet软件包<-依赖-heartbeat(包含ldirectord插件(需要perl-MailTools的rpm包)) l ...

  7. 高性能Linux服务器 第10章 基于Linux服务器的性能分析与优化

    高性能Linux服务器 第10章    基于Linux服务器的性能分析与优化 作为一名Linux系统管理员,最主要的工作是优化系统配置,使应用在系统上以最优的状态运行.但硬件问题.软件问题.网络环境等 ...

  8. 高性能Linux服务器 第6章 ext3文件系统反删除利器ext3grep extundelete工具恢复rm -rf 误删除的文件

    高性能Linux服务器 第6章  ext3文件系统反删除利器ext3grep  extundelete工具恢复rm -rf 误删除的文件 只能用于ext3文件系统!!!!!!!高俊峰(高性能Linux ...

  9. 优化系统资源ulimit《高性能Linux服务器构建实战:运维监控、性能调优与集群应用》

    优化系统资源ulimit<高性能Linux服务器构建实战:运维监控.性能调优与集群应用> 假设有这样一种情况,一台Linux 主机上同时登录了10个用户,在没有限制系统资源的情况下,这10 ...

  10. 优化Linux内核参数/etc/sysctl.conf sysctl 《高性能Linux服务器构建实战:运维监控、性能调优与集群应用》

    优化Linux内核参数/etc/sysctl.conf  sysctl  <高性能Linux服务器构建实战:运维监控.性能调优与集群应用> http://book.51cto.com/ar ...

随机推荐

  1. Educational Codeforces Round 127 (Rated for Div. 2) E. Preorder

    设\(f[v]\)是以结点\(v\)为根的方案数,设左子树的根为\(x\),右子树的根为\(y\),那么如果左右子树完全相同,那么我们交换左右子树对方案没有任何影响,都是: \[f[v] = f[x] ...

  2. P1029 最大公约数和最小公倍数问题(普及−) 题解

    题目传送门 想要做这题,我们要先了解一下最大公约数. 最大公因数,也称最大公约数.最大公因子,指两个或多 个整数共有约数中最大的一个.a,b的最大公约数记为 (a,b),同样的,a,b,c的最大公约数 ...

  3. 【uniapp】学习笔记day03 | 页面制作【外包杯】

    一.开发层级结构介绍 page.json 对uniapp进行全局配置,决定页面文件的路径.窗口样式.原生的导航栏.底部的原生tabbbar manifest.json 应用的配置文件,指定应用的名称. ...

  4. vertx的学习总结7之用kotlin 与vertx搞一个简单的http

    这里我就简单的聊几句,如何用vertx web来搞一个web项目的 1.首先先引入几个依赖,这里我就用maven了,这个是kotlin+vertx web <?xml version=" ...

  5. .NET Conf 2023 Chengdu - 成都站圆满结束!

    今年的.NET Conf 2023,中国区首次有两个会场举办Local Event,成都会场已于上周六12月9日圆满结束. 本次成都会场共计100+余名.NET开发者报名参与,共计10+名志愿者参与筹 ...

  6. Vue2.0 学习 第三组 条件语句

    本笔记主要参考菜鸟教程和官方文档编写.1.v-if在div或者之类的dom中使用v-if可以控制是否插入该dom,控制由v-if的true和false决定.如:<div id="app ...

  7. 如何通过port-forward命令在本地访问 k8s 集群服务

    公众号「架构成长指南」,专注于生产实践.云原生.分布式系统.大数据技术分享 概述 在我们访问k8s中的pod服务时,一般通过node port映射pod端口进行访问,还有一种是通过ingress或者i ...

  8. 快速上手 dbt 数据转换工具 -- dbt core 命令进阶篇

    引 根据第一篇文章的约定,我想通过接下来的几篇文章带大家进一步了解 dbt 的用法,原计划这篇文章我会介绍 dbt 命令的进阶用法,进一步认识 dbt 的配置以及如何创建增量表等等零零散散十几个方面的 ...

  9. spring与jndi(数据库连接)SpringBoot打war包并整合jsp

    spring与jndi(数据库连接)SpringBoot打war包并整合jsp,这里的jndi指的是jdbc连接,不是其他的.有传统servlet+spring和springboot的jndi连接操作 ...

  10. 调用含有header的WebService时,跳过证书验证

    最近在做Webservice的接口调用,header的用户名和密码都是正确的,地址也是对的,但一直提示:基础连接已关闭,未能与SSL/TLS安全通道建立信任关系. 解决方案: 请求之前加上下面得代码即 ...