web与服务端:第三篇 gunicorn的功能及使用方法
为了处理多并发请求,我们设计了CGI通讯的方式,使用多进程来处理请求,但是CGI的实现也分成了很多种。所以为了统一接口规范,Python定义了WSGI协议之后,出现了很多基于这个协议的应用,常用的WSGI容器有Gunicorn和uWSGI,但Gunicorn直接用命令启动,不需要编写配置文件,相对uWSGI要容易很多。
Gunicorn 简介
Gunicorn使用pre-fork worker模型,简单来说就是为了提高CGI的响应速度,先从master进程中预先fork出一些进程,这样当请求到来的时候就可以快速响应。
当然了,Gunicorn是WSGI的实现,但同时也自带web server,能直接对外提供web服务。包括大部分的web app框架比如Flask和Django也都带有web server。不过,在真正的生产环境的部署中,它们还是各司其职,Flask/Django只用于写app、Gunicorn只用于运行和管理Python web app,而在它们前面有专门的web server,比如Nginx。
安装Gunicorn
1 | pip install gunicorn |
启动 Gunicorn
首先新建一个简单的web实例应用
1 | from flask import Flask |
然后使用一个简单的命令启动Gunicorn
1 | gunicorn --worker=3 main:app -b 0.0.0.0:8080 |
当然,这个时候就会有小伙伴要问了,flask也有WSGI协议的实现,和Gunicorn的有什么区别呢?
这里做一个简单的压力测试,首先直接运行flask,python main.py
,然后使用ab工具进行500次访问的压力测试。
测试结果如下所示:
1 | This is ApacheBench, Version 2.3 <$Revision: 1843412 $> |
可以看到,具体的结果是这样的,500次并发请求的结果:
1 | Time per request: 413.630 [ms] (mean) |
同样的,使用Gunicorn之后,再测试一次,结果如下:
1 | Time per request: 66.469 [ms] (mean) |
可以看到,性能上有了大大的提升,轻松应对500次并发请求。
应用场景
在实际的应用当中,Gunicorn对于静态文件的支持比较差,所以一般会使用Nginx做反向代理服务器,然后由gunicorn做中间人来连接flask和nginx。
具体的架构如下所示:
由客户端发起请求,然后Nginx代理服务器将请求转发给Gunicorn,由Gunicorn的worker管理处理请求的进程,再将请求发送给Flask,然后Flask进行响应静态页面。
后话
当然我这里只是粗略的介绍了一下Gunicorn的使用和简单的工作原理,要深入了解的话可以看一下其他的资料,就不再展开赘述了。
当然,随着Python的不断发展,多线程领域也是遍地开花,也出现了很多处理多并发的应用,但是并没有WSGI这么好使,所以这里也不展开,按理来说,通过多线程和多进程的方式,我们基本上可以处理大部分的应用场景了。但是,进入21世纪以来,随着互联网的飞速发展,C10K的问题到来了,服务器的资源又不够了,能开的进程终究是有上限的,我们需要寻找别的方式来处理请求了。
什么是C10K问题?Python服务器又是怎么处理高并发的呢?且听下回分解。