参考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. win10安装WSL2

    什么是WSL2 首先我们理解一下什么是WSL Windows Subsystem for Linux(简称WSL)是一个在Windows 10\11上能够运行原生Linux二进制可执行文件(ELF格式 ...

  2. shell 语法介绍

    大家好,我是蓝胖子,在日常开发中或多或少都会接触到shell脚本,可以说会shell脚本是一位后端开发的基本功,今天我将会花上一篇文章总结下常见的shell的语法,学完本篇,相信简单的shell脚本就 ...

  3. Vivado生成bitstream时报错[Opt 31-67] Problem: A LUT3 cell in the design is missing a connection on input pin I1, which is used by the LUT equation

    这个原因主要是因为有一个引脚没有用到,解决方法. 1.打开Schematic. 2.根据提示的模块去找,比如说我的报错. [Opt 31-67] Problem: A LUT3 cell in the ...

  4. hive报错Execution Error, return code 2 from org.apache.hadoop.hive.ql.exec.mr.MapRedTask[已解决]

    我的报错信息 Execution Error, return code 2 from org.apache.hadoop.hive.ql.exec.mr.MapRedTask 解决1(可行):不走ya ...

  5. Ingress & Ingress Controller & API Gateway

    Ingress Ingress 内部服务如何暴露给集群外部访问 使用NodePort类型的service 将k8s集群中的服务暴露给集群外部访问,最简单的方式就是使用NodePort,类似在docke ...

  6. 汇报工作与众不同:在PPT中展示Datainside动态图表

    题目要求了解在PPT中展示Datainside动态图表,下面是关于该主题的详细介绍. 内容可视化:概念与定义 内容可视化(Data Visualization)是将数据以图形或其他视觉形式呈现的过程, ...

  7. ARM汇编指令实验

    题目 地址为0x40008000起始的内存中存放了20个无符号的8位整数,请编写ARM汇编程序实现如下功能: 采用冒泡法将以上内存中的数据按照从小到大的顺序排列. 注意:在验收实验时,需要自己把具体的 ...

  8. SQL动态化多个分组查询

    现有以下三张表,分别为:diqu(地区表),zhiye(职业表),info(信息表) 最基本的分组查询 1 select dqID,jbID,COUNT(1) from info group by d ...

  9. IoC入门案例

    1.管理什么?(Service和Dao) 2.如何将被管理的对象告知IoC容器?(配置) 3.被管理的对象交给IoC容器,如何获取IoC容器?(接口) 4.IoC容器得到后,如何从容器中获取到bean ...

  10. Mybatis-Flex核心功能之@Id

    1.是什么? 在 Entity 类中,MyBatis-Flex 是使用 @Id 注解来标识主键的 2.怎么玩? public @interface Id { /** * ID 生成策略,默认为 non ...