梳理Python WSGI与WSGI服务器等概念

经常接触Django,问自己一个问题:Django项目中与setttings文件同目录的wsgi.py是干什么用的?这个问题熟悉而又陌生,wsgi.py这个文件可以说无时无刻不在我们眼皮底下出现,但又对它真正的功能作用知之甚少。更早的时候,将Django部署在Apache上会用到mod-wsgi,这是两者之间通信的媒介。忙碌中整理一些概念与教程来梳理这些概念,解惑也。

1. 首先弄清下面几个概念

WSGI:全称是Web Server Gateway Interface,WSGI不是服务器,python模块,框架,API或者任何软件,只是一种规范,描述web server如何与web application通信的规范。server和application的规范在PEP 3333中有具体描述。要实现WSGI协议,必须同时实现web server和web application,当前运行在WSGI协议之上的web框架有Bottle, Flask, Django。

WSGI存在的目的有两个:

  1. 让Web服务器知道如何调用Python应用程序,并且把用户的请求告诉应用程序。
  2. 让Python应用程序知道用户的具体请求是什么,以及如何返回结果给Web服务器。

uwsgi:与WSGI一样是一种通信协议,是uWSGI服务器的独占协议,用于定义传输信息的类型(type of information),每一个uwsgi packet前4byte为传输信息类型的描述,与WSGI协议是两种东西,据说该协议是fcgi协议的10倍快。

uWSGI:是一个web服务器,实现了WSGI协议、uwsgi协议、http协议等。

WSGI协议主要包括server(或者gateway)和application(或者framework)两部分:

  • WSGI server负责从客户端接收请求,将request转发给application,将application返回的response返回给客户端;

  • WSGI application接收由server转发的request,处理请求,并将处理结果返回给server。application中可以包括多个栈式的中间件(middlewares),这些中间件需要同时实现server与application,因此可以在WSGI服务器与WSGI应用之间起调节作用:对服务器来说,中间件扮演应用程序,对应用程序来说,中间件扮演服务器

​ WSGI Middleware(中间件)也是WSGI规范的一部分。上一章我们已经说明了WSGI的两个角色:server和application。那么middleware是一种运行在server和application中间的应用(一般都是Python应用)。middleware同时具备server和application角色,对于server来说,它是一个application;对于application来说,它是一个server。middleware并不修改server端和application端的规范,只是同时实现了这两个角色的功能而已。

middleware

WSGI协议其实是定义了一种server与application解耦的规范,即可以有多个实现WSGI server的服务器,也可以有多个实现WSGI application的框架,那么就可以选择任意的server和application组合实现自己的web应用。例如uWSGI和Gunicorn都是实现了WSGI server协议的服务器,Django,Flask是实现了WSGI application协议的web框架,可以根据项目实际情况搭配使用,详细的我们后面说。

2. WSGI实现原理以及”兄弟”CGI FastCGI?

WSGI原理的内部实现,说简单不简单说复杂却不复杂,这里不细说,我们可以**用简单实例来理解Python WSGI **

那么CGI FastCGI又是什么?是不是跟WSGI有什么关系?我们可以翻阅下CGI FastCGI WSGI 学习笔记 就会豁然开朗了

3. WSGI服务器的选择?

上面提到uWSGI和Gunicorn都是实现了WSGI server协议的服务器,还有我之前用过的部署在Apache上mod_wsgi, 那么对于这些东西,为什么需要一个?我应该选择哪一个?

django自带的web server目的是方便开发,不是能直接放到生产环境的,直接引用django的文档。It’s intended only for use while developing. (We’re in the business of making Web frameworks, not Web servers.)

使用Gunicorn,除非你在Windows上部署,在这种情况下使用mod_wsgi。

which_server

具体的解释我这里用这篇英文原文Which WSGI server should I use? 翻译一下来回答。

如图所示(我们可以暂时忽略掉图中的Web Server,这是下一小节要说的),Web浏览器与Web服务器通信,Web服务器又与WSGI服务器通信。该WSGI服务器不会直接与你的Django项目通信,而是导入 Django项目。它是这么做的:

1
2
from django_project.wsgi import application
application(args)

因此,从操作系统的角度来看,你的Django项目将成为WSGI服务器的一部分; 这是同一个过程。调用**application()**的方式由WSGI规范标准化。这个函数的接口是标准化的,这使得你可以在许多不同的WSGI服务器(如Gunicorn,uWSGI或mod_wsgi)之间进行选择,以及为什么每个服务器都可以与许多Python应用程序框架(如Django或Flask)进行交互。

mod_wsgi仅适用于Apache,我更偏向于可与Apache或nginx一起使用的方法。这样的话,使更改Web服务器变得更容易。我也发现Gunicorn更容易设置和维护。

我使用了uWSGI几年,并且被它的功能所震撼。其中许多都复制了Apache或nginx或堆栈其他部分中已存在的功能,因此很少需要它们。它的文档有点混乱。开发人员自己承认:“我们尽力提供良好的文档,但这是一项艰苦的工作。对不起。“我记得每周都会遇到问题并且每次花费数小时来解决问题。

另一方面,Gunicorn正是你想要的恰到好处的功能。它很简单,工作正常。所以我推荐它,除非在你的特殊情况下有一个令人信服的理由使用其中一个。

uWSGI和Gunicorn没法在Windows中运行,因此如果你在Windows上部署那就使用Apache + mod_wsgi。

4. 既然有了WSGI Server,为什么我们还需要Nginx(Web Server)?

如果只有一个应用,不需要负载均衡;只提供api服务,没有静态文件;不需要额外的访问控制等功能这样是不是就不需要nginx等反向代理?答案是需要。nginx可以缓冲请求和响应。如果让Gunicorn直接提供服务,浏览器发起一个请求,鉴于浏览器和网络情况都是未知的,http请求的发起过程可能比较慢,而Gunicorn只能等待请求发起完成后,才去真正处理请求,处理完成后,等客户端完全接收请求后,才继续下一个。nginx缓存客户端发起的请求,直到收完整个请求,转发给Gunicorn,等Gunicorn处理完成后,拿到响应,再发给客户端,这个流程是nginx擅长处理,而Gunicorn不擅长处理的。因此将Gunicorn置于nginx后面,可以有效提高Gunicorn的处理能力。 ——摘自知乎Nginx、Gunicorn在服务器中分别起什么作用? 某回答

nginx+gunicorn

当我们为Gunicorn运行我们的django应用程序而开心时,然而,最后,我们看到管理面板的样式已经消失了。原因是Gunicorn是一个应用程序服务器,只运行应用程序(在我们的例子中是django app)和django,正如我们所知,除了开发之外,它不提供静态文件。Nginx来救援!它将是Gunicorn的反向代理。到底是什么反向代理?好问题!我们都知道VPN是什么,对吧?我们使用它们访问某些因某种原因被阻止的网站。在这种情况下,我们通过VPN访问该网站:我们 - > VPN - >某些网站。这种代理称为正向代理。至于反向代理,可以将它们视为强制代理。例如,用户正在尝试访问我们在gunicorn中运行的django应用程序。它认为它正在直接访问该应用程序。然而,真正的过程是它首先访问Nginx服务器,该服务器决定下一步该做什么,如果用户正在访问静态文件,Nginx服务器将自行提供服务。否则,它会将其重定向到Gunicorn。简单来说,http请求将由Gunicorn处理,而静态处理则由Nginx处理。这就是我们需要Nginx的原因
除此之外,Nginx还提高了性能,可靠性,安全性和规模

5. 总结

这几天晚上睡觉前花了一点时间来对这些概念进行了一些整理,收获颇多。要想真正的成为一名Web开发,并不是简单的套用框架写写逻辑层,而是框架背后的原理与流程,这才是重中之重,了解了这些,所有的类似框架以后上手都能快半分。接下去,会对Gunicorn,Nginx的配置文件做个记录(这中间也踩了点坑),再往后就是Nginx与docker的理解与实践了,加油~