共计 5007 个字符,预计需要花费 13 分钟才能阅读完成。
在 PHP 里,最方便的就是 deployment 了,只要把 php 文件丢到支持 PHP 的路径里面,然后访问那个路径就能使用了;无论给主机添加多少 PHP 应用,只要把目录改好就没你的事了,完全不用关心 php-cgi 运行得如何,deployment 极为方便。
反观 Python,部属起来真是头痛,常见的部署方法有:
◆fcgi:用 spawn-fcgi 或者框架自带的工具对各个 project 分别生成监听进程,然后和 http 服务互动。
◆wsgi:利用 http 服务的 mod_wsgi 模块来跑各个 project。
无论哪种都很麻烦,apache 的 mod_wsgi 配置起来很麻烦,内存占用还大,如果要加上 nginx 作为静态页面的服务器那就更麻烦了;我的应用基本上到后来都是是各个 project 各自为战,且不说管理上的混乱,这样对负载也是不利的,空闲的 project 和繁忙的 project 同样需要占用内存。
如果 Python 中能有个什么东西像 php-cgi 一样监听同一端口,进行统一管理和负载平衡,那真是能省下大量的部署功夫。偶然看到了 uWSGI,才发现居然一直不知道有那么方便地统一部署工具。uWSGI,既不用 wsgi 协议也不用 fcgi 协议,而是自创了一个 uwsgi 的协议,据说该协议大约是 fcgi 协议的 10 倍那么快,有个比较见下图:
uWSGI 的主要特点如下:
◆超快的性能。
◆低内存占用(实测为 apache2 的 mod_wsgi 的一半左右)。
◆多 app 管理。
◆详尽的日志功能(可以用来分析 app 性能和瓶颈)。
◆高度可定制(内存大小限制,服务一定次数后重启等)。
正式开工
uwsgi 的文档虽然很多也很详细,这里是 uwsgi 的官方文档:http://projects.unbit.it/uwsgi/wiki/Doc。
1. 安装 uwsgi
Ubuntu 有 uwsgi 的 ppa:
- add-apt-repository ppa:stevecrozz/ppa
- apt-get update
- apt-get install uwsgi
2. 用 uwsgi 代替 mod_wsgi
Nginx 的整体配置说来话长,这里不再多说,假设已经明白 Nginx 的基本配置,那么 uwsgi 就类似这么配置:
- location / {
- include uwsgi_params
- uwsgi_pass 127.0.0.1:9090
- }
这就是把所有 url 传给 9090 端口的 uwsgi 协议程序来互动。再到 project 目录建立 myapp.py,使得 application 调用框架的 wsgi 接口,比如 web.py 就是:
- ……
- app = web.application(urls, globals())
- appapplication = app.wsgifunc()
再比如 django 就是:
- …….
- from django.core.handlers.wsgi import WSGIHandler
- application = WSGIHandler()
然后运行 uwsgi 监听 9090,其中 - w 后跟模块名,也就是刚才配置的 myapp
- uwsgi -s :9090 -w myapp
运行网站发现已经部署完成了。
3.uwsgi 的参数
以上是单个 project 的最简单化部署,uwsgi 还是有很多令人称赞的功能的,例如:
并发 4 个线程:
- uwsgi -s :9090 -w myapp -p 4
主控制线程 + 4 个线程:
- uwsgi -s :9090 -w myapp -M -p 4
执行超过 30 秒的 client 直接放弃:
- uwsgi -s :9090 -w myapp -M -p 4 -t 30
限制内存空间 128M:
- uwsgi -s :9090 -w myapp -M -p 4 -t 30 –limit-as 128
服务超过 10000 个 req 自动 respawn:
- uwsgi -s :9090 -w myapp -M -p 4 -t 30 –limit-as 128 -R 10000
后台运行等:
- uwsgi -s :9090 -w myapp -M -p 4 -t 30 –limit-as 128 -R 10000 -d uwsgi.log
4. 为 uwsgi 配置多个站点
为了让多个站点共享一个 uwsgi 服务,必须把 uwsgi 运行成虚拟站点:去掉“-w myapp”加上”–vhost”:
- uwsgi -s :9090 -M -p 4 -t 30 –limit-as 128 -R 10000 -d uwsgi.log –vhost
然后必须配置 virtualenv,virtualenv 是 Python 的一个很有用的虚拟环境工具,这样安装:
- apt-get install Python-setuptools
- easy_install virtualenv
然后设置一个 / 多个 app 基准环境:
- virtualenv /var/www/myenv
应用环境,在此环境下安装的软件仅在此环境下有效:
- source /var/www/myenv/bin/activate
- pip install django
- pip install mako
- …
最后配置 nginx,注意每个站点必须单独占用一个 server,同一 server 不同 location 定向到不同的应用不知为何总是失败,估计也算是一个 bug。
- server {
- listen 80;
- server_name app1.mydomain.com;
- location / {
- include uwsgi_params;
- uwsgi_pass 127.0.0.1:9090;
- uwsgi_param UWSGI_PYHOME /var/www/myenv;
- uwsgi_param UWSGI_SCRIPT myapp1;
- uwsgi_param UWSGI_CHDIR /var/www/myappdir1;
- }
- }
- server {
- listen 80;
- server_name app2.mydomain.com;
- location / {
- include uwsgi_params;
- uwsgi_pass 127.0.0.1:9090;
- uwsgi_param UWSGI_PYHOME /var/www/myenv;
- uwsgi_param UWSGI_SCRIPT myapp2;
- uwsgi_param UWSGI_CHDIR /var/www/myappdir2;
- }
- }
这样,重启 nginx 服务,两个站点就可以共用一个 uwsgi 服务了。
5. 实战应用
最初的设置完毕以后,再添加的应用,只需要在 Nginx 里面进行少量修改,无需重启 uwsgi,就能立刻部署完毕。uwsgi 自带了基于 django 的监控 uwsgi 运行状态的工具,就拿它来部署好了:
- server {
- listen 80;
- root /var/www/django1.23;
- index index.html index.htm;
- server_name uwsgiadmin.django.obmem.info;
- access_log /var/log/nginx/django.access.log;
- location /media/ {
- root /var/www/django1.23/adminmedia;
- rewrite ^/media/(.*)$ /$1 break;
- }
- location / {
- include uwsgi_params;
- uwsgi_pass 127.0.0.1:9090;
- uwsgi_param UWSGI_PYHOME /var/www/django1.23/vtenv;
- uwsgi_param UWSGI_CHDIR /var/www/django1.23/uwsgiadmin;
- uwsgi_param UWSGI_SCRIPT uwsgiadmin_wsgi;
- }
- }
于是 uwsgi 的监控信息可以在 http://uwsgiadmin.django.obmem.info 看到(用户名密码都是 admin)。再比如 LBForum 论坛程序的部署:根据安装说明安装完���,再按部署说明修改完配置文件,然后只需修改 nginx 配置文件:
- server {
- listen 80;
- root /var/www/django1.23;
- index index.html index.htm;
- server_name lbforum.django.obmem.info;
- access_log /var/log/nginx/django.access.log;
- location / {
- include uwsgi_params;
- uwsgi_pass 127.0.0.1:9090;
- uwsgi_param UWSGI_PYHOME /var/www/django1.23/vtenv;
- uwsgi_param UWSGI_CHDIR /var/www/django1.23/LBForum/sites/default;
- uwsgi_param UWSGI_SCRIPT lbforum_wsgi;
- }
- }
于是 http://lbforum.django.obmem.info 就是论坛程序了。
后记
虽然写出来寥寥几行,配置的时候我可吃尽了 uwsgi 的苦头,有些想当然的用法完全不能成立,–no-site 参数一加上去其他都好使 LBForum 怎么都部署不了,一开始多站点公用 uwsgi 怎么都成功不了等等。
Python 世界很有趣,一直会发现有趣的东西,但是 Python 世界也很折腾人,大部分东西都是 dev 版本,文档缺失,各种兼容问题。
更多参考
Nginx+uWSGI+Supervisor 在 Ubuntu 上部署 Flask 应用 http://www.linuxidc.com/Linux/2016-07/133064.htm
Ubuntu Server 12.04 安装 Nginx+uWSGI+Django 环境 http://www.linuxidc.com/Linux/2012-05/60639.htm
Django+Nginx+uWSGI 部署 http://www.linuxidc.com/Linux/2013-02/79862.htm
Nginx+uWSGI+Django+Python 应用架构部署 http://www.linuxidc.com/Linux/2015-10/124183.htm
Ubuntu Server 14.04.2 LTS 配置 Nginx + Uwsgi + Django http://www.linuxidc.com/Linux/2015-04/116397.htm
Flask+uWSGI+Nginx+Ubuntu 部署教程 http://www.linuxidc.com/Linux/2016-06/132690.htm
Ubuntu 16.04 下安装部署 Nginx+uWSGI+Django1.9.7 http://www.linuxidc.com/Linux/2016-07/133484.htm
Nginx+uWSGI+Django 在 Ubuntu 下的部署 http://www.linuxidc.com/Linux/2016-07/133490.htm
Linux 上利用 Nginx 代理 uWSGI 处理 Flask Web 应用 http://www.linuxidc.com/Linux/2016-08/134164.htm
本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-12/137830.htm