Django + uWSGI + Nginx 生产环境部署
官方文档:https://uwsgi-docs.readthedocs.io/en/latest/Options.html
背景
如何在生产上部署 Django?
Django的部署可以有很多方式,采用 Nginx+uwsgi 的方式是其中比较常见的一种方式。
概念介绍
为什么需要web协议
开发出的应用程序需要和服务器程序配合,才能为用户提供服务。但是不同的框架有不同的开发方式,需要有一种协议来规范不同的框架,这就是web 协议。
web 协议本质:就是定义了 Web 服务器和 Web 应用程序或框架的一种简单而普通的接口规范。
Web协议出现顺序:CGI -> FCGI -> WSGI -> uwsgi
- CGI:最早的协议
- FCGI:比CGI快
- WSGI:Python 专用的协议
- uwsgi:比 FCGI 和 WSGI 快,是 uWSGI 项目自有的协议,主要特征是采用二进制来存储数据,其他协议都是使用字符串,所以在存储空间和解析速度上,都优于字符串型协议。
WSGI 是什么?
- WSGI 是一种规范,它定义了使用 Python 编写的 web app(Django) 与 web server(uWSGI) 之间接口格式,实现 web app 与 web server 间的解耦。
- WSGI 没有官方的实现,因为 WSGI 更像一个协议,只要遵照这些协议,WSGI 应用(Application)都可以在任何服务器(Server)上运行。
- WSGI 实质:WSGI 是一种描述 web 服务器(如 Nginx、uWSGI 等服务器)如何与 web 应用程序(如用 Django、Flask 框架写的程序)通信的规范、协议。
uwsgi 是什么?
- 它是一个二进制协议,可以携带任何类型的数据。
- 一个 uwsgi 分组的4个字节描述了这个分组包含的数据类型。
- uwsgi 是一种线路协议而不是通信协议,在此常用于在 uWSGI 服务器与其他网络服务器的数据通信;
uwsgi 性能非常高
uWSGI 是什么?(web 服务器 和 Nginx 类似)
- uWSGI 是一个全功能的HTTP服务器,实现了 WSGI协议,uWSGI协议,HTTP协议 等。Nginx 中 HttpUwsgiModule 的作用是与 uWSGI 服务器进行交换。
- uWSGI 作用:它要做的就是把 HTTP 协议转化成语言支持的网络协议,比如把 HTTP 协议转化成 WSGI 协议,让 Python 可以直接使用。
- uWSGI 特点:轻量级,易部署,性能比 Nginx 差很多。
注:
- 如果架构是 Nginx+uWSGI+APP,uWSGI 是一个中间件。
- 如果架构是 uWSGI+APP,uWSGI 是一个服务器。
uWSGI 的主要特点如下
- 超快的性能。
- 低内存占用(实测为 apache2 的 mod_wsgi 的一半左右)。
- 多app管理(终于不用冥思苦想下个app用哪个端口比较好了-.-)。
- 详尽的日志功能(可以用来分析app性能和瓶颈)。
- 高度可定制(内存大小限制,服务一定次数后重启等)。
总而言之 uWSGI 是个部署用的好东东,正如 uWSGI 作者所吹嘘的:
If you are searching for a simple wsgi-only server, uWSGI is not for you, but if you are building a real (production-ready) app that need to be rock-solid, fast and easy to distribute/optimize for various load-average, you will pathetically and morbidly fall in love (we hope) with uWSGI.
总结:WSGI / uwsgi / uWSGI 这三个概念的区分
- WSGI 是一种通信协议,通常用于户 Django 框架和 uWSGI 服务器之间通信。(如果说的更细致的话就是用来和 Python WSGI model通信)
- uwsgi 是一种线路协议而不是通信协议,在此常用于在 uWSGI 服务器与其他网络服务器的数据通信。
- 而 uWSGI 是实现了uwsgi 和 WSGI 等协议的 Web 服务器
Django 是什么?
Django 是一个 Web 框架,框架的作用在于处理 request 和 reponse,其他的不是框架所关心的内容。
所以如何部署 Django 不是 Django 所需要关心的。
请求处理整体流程
Nginx 接收到浏览器发送过来的 HTTP 请求,将包进行解析,分析 url。
静态文件请求:就直接访问用户给 Nginx 配置的静态文件目录,直接返回用户请求的静态文件。
动态接口请求:那么 Nginx 就将请求转发给 uWSGI,最后到达 Django 处理。
各模块作用
- Nginx:是对外的服务器,外部浏览器通过url访问 Nginx, Nginx 主要处理静态请求。
- uWSGI:是对内的服务器,主要用来处理动态请求。
- uwsgi:是一种 web 协议,接收到请求之后将包进行处理,处理成 WSGI 可以接受的格式,并发给 WSGI 服务器。
- WSGI:是 Python 专用的 web 协议,根据请求调用应用程序(Django)的某个文件,某个文件的某个函数。
- Django:是真正干活的,查询数据等资源,把处理的结果再次返回给 WSGI,WSGI 将返回值进行打包,打包成 uWSGI 能够接收的格式。
- uWSGI 接收发送的请求,并转发给 Nginx,Nginx 最终将返回值返回给浏览器。
Django + uWSGI 方案
没有 Nginx 而只有 uWSGI 的服务器,则是 Internet 请求直接由 uWSGI 处理,并反馈到 web 项目中。
Nginx 可以实现安全过滤,防 DDOS 等保护安全的操作,并且如果配置了多台服务器, Nginx 可以保证服务器的负载相对均衡.
而 uWSGI 则是一个 web 服务器,它可以接收和处理请求,发出响应等。所以只用 uWSGI 也是可以的。
Nginx 和 uWSGI 特点
Nginx 的作用
- 反向代理,可以拦截一些 web 攻击,保护后端的 web 服务器
- 负载均衡,根据轮询算法,分配请求到多节点 web 服务器
- 缓存静态资源,加快访问速度,释放 web 服务器的内存占用专项专用
uWSGI 的适用
- 单节点服务器的简易部署
- 轻量级,好部署
uWSGI 安装使用
安装
1 |
|
基本测试
1 |
|
uWSGI 参数解析
常用参数如下
http
: 协议类型和端口号,例如--http 127.0.0.1:8080
socket
: 指定 uWSGI 的客户端将要连接的 socket 的路径(使用UNIX socket的情况)或者地址(使用网络地址的情况)。你最多可以同时指定 8 个socket选项。当使用命令行变量时,可以使用“-s”这个缩写- 例如:
--socket /tmp/uwsgi.sock
--socket 127.0.0.1:8080
- 例如:
processes
: 开启的进程数量,等同于 workers(官网:spawn the specified number ofworkers / processes)workers
: 开启的进程数量,等同于 processes(官网:spawn the specified number ofworkers / processes)- 要根据代码实际运行情况来定夺, 通常为
cpu * 2
- 引用官网:There is no magic rule for setting the number of processes or threads to use. It is very much application and system dependent. Simple math like processes = 2 * cpucores will not be enough. You need to experiment with various setups and be prepared constantly monitor your apps. uwsgitop could be a great tool to find the best values.
- 要根据代码实际运行情况来定夺, 通常为
threads
: 每个 process 开启的线程。由于 GIL 的存在,我觉得这个没啥用。(官网:run each worker in prethreaded mode with the specified number of threads)chdir
: 指定运行目录(官网:chdir to specified directory before apps loading)wsgi-file
: 载入 wsgi-file(load .wsgi file)module
: 载入 wsgi-file(load .wsgi file),和 wsgi-file 配置一个就行master
: 允许主进程存在(enable master process)daemonize
: 使进程在后台运行,并将日志打到指定的日志文件或者udp服务器。实际上最常用的,还是把运行记录输出到一个本地文件上。vacuum
: 当服务器退出的时候自动清理环境,删除unix socket文件和pid文件(try to remove all of the generated file/sockets)post-buffering
: 启用post缓冲,如果一个HTTP请求有一个主体(像一个表单生成的post请求),你必须在你的应用程序中读取(消费)它。如果不这样做,与web服务器的通信套接字可能会被破坏。如果你比较懒,你可以使用post-buffering选项,它会自动为你读取数据。对于机架应用程序,这是自动启用的。buffer-size
: 设置用于 uWSGI 包解析的内部缓存区大小。默认是 4k。- 如果你打算接受一个拥有很多请求头的大请求,你可以增加这个值到 64k。
--buffer-size 32768
- 如果你打算接受一个拥有很多请求头的大请求,你可以增加这个值到 64k。
max-requests
: reload workers after the specified amount of managed requests。一个 worker 完成多少个请求以后就重启。可以使用这个选项来默默地对抗内存泄漏(尽管这类情况使用 reload-on-as 和 reload-on-rss 选项更有用)max-requests 100000
disable-logging
: disable request logging,禁掉请求的系统日志,不记录请求信息的日志。只记录错误以及uWSGI内部消息到日志中,调试模式下要打开,生产环境注意关闭,这个东西很影响效率stats 监控程序的url
: 在指定的地址上,开启状态服务,只有设置了这个参数以后才能用 uwsgitop ip:port 来观看监控,类似于 linux 的 top 命令- 引用官网:enable the stats server on the specified address)
- 示例:
state=127.0.0.1:1717
listen
: 设置 socket 的监听队列大小(默认:100)。每一个 socket 都有一个相关联的队列,请求会被放入其中等待进程来处理。当这个队列满的时候,新来的请求就会被拒绝。队列大小的最大值依赖于系统内核。- 这个值要可以稍大一点
--listen 8192
- 这个值要可以稍大一点
每一个选项都可以使用在任何一种支持的配置方式里(如命令行参数、环境变量、xml文件、ini文件、yaml格式文件以及LDAP)。有些选项的使用需要某些插件的支持。当使用某一种配置风格或者将一种风格转换另一个风格时,需要注意以下规则:
命令行参数(command line args):需要给选项增加
--
前缀。- 例如 socket 选项:
--socket
- 例如 socket 选项:
环境变量(environment variable):选项名都要换成大写,并且加上
UWSGI_
前缀,所有原来选项名中的-
都要换成下划线_
- 例如max-vars选项将变成:
UWSGI_MAX_VARS=""
- 例如max-vars选项将变成:
xml文件:xml文件中的根结点应该是,所有的选项值是作为文本节点。标识符类型的选项可以没有对应的值。
- socket选项和master选项可以如下配置:
1
2
3
4<uwsgi>
<socket>127.0.0.1:3031</socket>
<master/>
</uwsgi>
- socket选项和master选项可以如下配置:
ini文件:配置域应该是 uwsgi,标识符类型的选项的值可以设为 true 或者 1。
- socket 选项和 master 选项可以如下配置:
1
2
3[uwsgi]
socket =127.0.0.1:3031
master =true
- socket 选项和 master 选项可以如下配置:
yaml 格式文件:根元素需要设置为 uwsgi,标识符类型的选项的值可以设为 true 或者 1。
- socket 选项和 master 选项可以如下配置:
1
2
3uwsgi:
socket:127.0.0.1
master:1
- socket 选项和 master 选项可以如下配置:
lda 格式:这个格式比较复杂,你应该查阅专门的wiki文档。见 useLDAP。
一些配置文件
配置1
1 |
|
配置2
1 |
|
uWSGI 命令
1 |
|
uwsgitop
只需要简单的在 uwsgi 的运行参数里加上:--stats /tmp/stats.socket
或者 --stats 127.0.0.1:1717
1 |
|
安装 uwsgitop
uwsgitop 是其他 top 类似,使用状态服务来获取服务数据。在 PyPI 上有 uwsgitop,所以可以通过 pip 或者 easy_install 安装。
1 |
|
使用 uwsgitop
1 |
|
Nginx 配置文件
1 |
|
静态文件
在运行 Nginx 之前,你必须将所有的 Django 静态文件收集到静态文件夹中。首先,你必须编辑 mysite/settings.py 添加:
1 |
|
在项目目录下迁移静态文件
1 |
|
此时启动Nginx 和Uwsgi,你的Django项目就可以实现高并发啦!
异常处理
socket 配置不一致
1 |
|
uwsgi.ini 文件中的 socket = 127.0.0.1:8001 配置一定要和 Nginx 中的配置相匹配,不匹配会出现上述报错
uwsgi 出现 invalid request block size: 21573 (max 4096)…skip
uwsgi 内部解析的数据包大小,默认 4k。如果准备接收大请求,你可以增长到 64k。可以设置 uwsgi.ini 参数解决
1 |
|
uwsgi_temp Permission denied
1 |
|
解决方案一:
uwsgi_temp 目录及上层目录 增加 x 权限
解决方案二:
1 |
|
socket Permission denied
1 |
|
解决办法:
Nginx 启动的用户(一般是nobody)需要对 socket 文件具有 x 权限
参考
Django 中 settings.py 中的五个设置参数的一些故事:
1 |
|