相信用过 Django 的同学一定会被 “Very easy to setup” 惊艳到。只要一行命令,就可以在 admin 界面看到一个完整的登陆注册。但是到了部署的时候,你一定会被网上复杂的部署教程搞的头晕,为啥本地开发这么简单,到了服务器却需要又是 Nginx,又是 uWSGI 这种东西呢?
摘自The Full Stack Python Guide to Deployments 一书
本文试图解释这些程序在一个 Web 服务中扮演的角色,为什么部署 Python web程序需要它们。本文不介绍如何部署 Django 应用等,这一类教程网上有很多,读者可自行搜索。其中 Nginx 和 Apache 算是一类的,可以替换。Gunicorn 和 uWSGI 的角色是类似的。同理最后端的 Web 框架是一类的,比如 Django 和 Flask。本文的内容替换以上任意一个应该也适用。
如果你读了网上任意一篇教程,你应该知道一个完整的部署应该类似这样:
HTTP Server <-----> WSGI <-----> App
最后后面的 App 我们知道,只要 runserver 就可以访问了,但是 Django 的文档明确说明:
DO NOT USE THIS SERVER IN A PRODUCTION SETTING. It has not gone through security audits or performance tests. (And that’s how it’s gonna stay. We’re in the business of making Web frameworks, not Web servers, so improving this server to be able to handle a production environment is outside the scope of Django.)
即 Django 做的事情只是一个框架,不会去关心一些安全问题、HTTP 的性能问题等。所以我们需要一个专业的 HTTP 服务器。这就出现了 Nginx 或 Apache。那么如何将 HTTP 服务器和我们的应用连接起来呢?动态网站问世的时候,就出现了 CGI 协议。注意这是一个协议,定义了HTTP 服务器如何通过后端的应用获取动态内容。可以简单的理解成 HTTP 服务器通过CGI 协议调用后端应用吧!WSGI 可以理解成 Python 的 CGI。uWSGI 和 Gunicorn 是这种 WSGI 的一些实现。这样,就出现了上面提到的三层的部署。
但是,为什么我们还需要 Nginx 呢?这些 WSGI 程序本身不是也提供访问吗?
uWSGI 和 Gunicorn 本身就是一个便携的 web 服务器了,Nginx 作为一个经过更长时间验证的 HTTP 服务器来说,它有很多 uWSGI 没有支持的 feature。比如:
此外,这样分开的好处还是得,到达 uWSGI 和 Gunicorn 的请求的情况变得简单了很多,Nginx 处理了一层,将过滤和处理之后的请求交给 uWSGI 或 Gunicorn。这使得这些 WSGI 程序的实现简单了一些,简化了开发的工作。专业的事情交给专业的人去做。
当然,并不是所有的项目都需要这么复杂的部署,有一个可选的是将 WSGI 程序嫁接到 HTTP 服务器上,比如 Apache httpd + mod_wsgi, Nginx + mod_uwsgi 等。