原文来自:
http://www.oschina.net/question/54100_30386
常见的django
webapp 部署方式采用FCGI
或 WSGI
的方式部署,今天我这备忘下采用uWSGI
的部署方式。 目前我这博客就是采用 Nginx + uWSGI + Python + Django 构建的,部署虽没有php那样扔到目录那么方便,但是并发和性能消耗还是非常不错的。这里不想赘述关于FCGI
, WSGI
,uWSGI
之间的比较,网上关于这样的对比测试也有很多。这里说下部署过程。 uWSGI 的官方网站 http://projects.unbit.it/uwsgi/ wiki介绍的很详细。 Nginx关于HttpUwsgiModule的介绍http://wiki.nginx.org/HttpUwsgiModule.有这些资料参考,安装部署是很容易的事情。
uWSGI的安装
下载uWSGI的最新版
1 |
wget http://projects.unbit.it/downloads/uwsgi-0.9.9.2. tar .gz |
因为我最后采用xml配置django app 的部署,所以编译 uWSGI 时候需要把libxml编译进去
1 |
sudo apt-get install libxml2-dev |
剩下的就简单了
1 |
tar zxvf uwsgi-0.9.9.2. tar .gz |
2 |
cd uwsgi-0.9.9.2 |
3 |
make -f Makefile.Py26 #指定你python的版本,如果你的python是2.7 就应该是 make -f Makefile.Py27 |
4 |
cp uwsgi /usr/sbin/uwsgi |
至此 uWSGI 就算是安装完成了,下一步安装 Nginx > 0.8 的版本,因为只有Nginx > 0.8 的版本才支持wsgi
Nginx 安装
Ubuntu 默认源里面的Nginx版本比较旧,这里需要先添加一个Nginx的源,来通过apt-get安装新版本的Nginx
1 |
sudo add-apt-repository ppa:nginx/stable |
2 |
apt-get update |
3 |
apt-get install nginx |
接下来配置Nginx 和 uWSGI部署Django App 了. 首先我们在Nginx中新建一个站点配置文件:
1 |
sudo vi /etc/nginx/sites-enabled/blog.hysia.com |
内容如下:
01 |
server { |
02 |
listen 80; ## listen for ipv4; this line is default and implied |
03 |
#listen [::]:80 default ipv6only=on; ## listen for ipv6 |
04 |
05 |
server_name blog.hysia.com; |
06 |
07 |
access_log /var/log/nginx/blog.hysia.com-access.log ; |
08 |
error_log /var/log/nginx/blog.hysia.com-error.log ; |
09 |
10 |
location / { |
11 |
uwsgi_pass 127.0.0.1:8630; |
12 |
include uwsgi_params; |
13 |
} |
14 |
15 |
} |
这样Nginx算是配置完了,现在看我们的Django app如何配置。
配置Django app
配置很简单,几乎不用改动你app的任何文件。
首先在你的app目录创建个wsgi.py 文件,内容如下:
1 |
import os,sys |
2 |
3 |
if not os.path.dirname(__file__) in sys.path[: 1 ]: |
4 |
sys.path.insert( 0 , os.path.dirname(__file__)) |
5 |
os.environ[ 'DJANGO_SETTINGS_MODULE' ] = 'settings' |
6 |
7 |
from django.core.handlers.wsgi import WSGIHandler |
8 |
application = WSGIHandler() |
1 |
< uwsgi > |
2 |
< socket >127.0.0.1:8630</ socket > |
3 |
< chdir >/home/hysia/website/blog</ chdir > |
4 |
< pythonpath >..</ pythonpath > |
5 |
< module >wsgi</ module > |
6 |
</ uwsgi > |
最后一步,运行 uWSGI 就行了,如下:
1 |
uwsgi -x /home/hysia/website/blog/django.xml |
就这样你的Django app 就用 uWSGI hold住了。当然django.xml的配置远不止这些,比如log文件,内存限制等等,具体的大家可以参看 http://projects.unbit.it/uwsgi/wiki/Example uWSGI handle 多个 Django app 的时候性能更出众,更多的探索自己去动手实践吧。
个人觉得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同样需要占用内存,很容易出现站着茅坑不拉屎的现象。
如果有个啥东东能像php-cgi一样监听同一端口,进行统一管理和负载平衡,那真是能省下大量的部署功夫。偶然看到了uWSGI,才发现居然一直不知道有那么方便地统一部署工具。
uWSGI,既不用wsgi协议也不用fcgi协议,而是自创了一个uwsgi的协议,据说该协议大约是fcgi协议的10倍那么快,有个比较见下图
uWSGI的主要特点如下,其中一些功能让我感动得泪流满面
- 超快的性能
- 低内存占用(实测为apache2的mod_wsgi的一半左右)
- 多app管理(终于不用冥思苦想下个app用哪个端口比较好了-.-)
- 详尽的日志功能(可以用来分析app性能和瓶颈)
- 高度可定制(内存大小限制,服务一定次数后重启等)
总而言之uwgi是个部署用的好东东,正如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.
正式开工
uwsgi的文档虽然蛮多也很详细,但是他们网站的排版真是让人无语,粗粗看上去根本不知道文档在哪里。其实是在这里:http://projects.unbit.it/uwsgi/wiki/Doc
0.安装uwsgi
ubuntu有uwsgi的ppa
add-apt-repository ppa:stevecrozz/ppa apt-get update apt-get install uwsgi
1. 用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()) application = app.wsgifunc()
再比如django就是
....... from django.core.handlers.wsgi import WSGIHandler application = WSGIHandler()
然后运行uwsgi监听9090,其中-w后跟模块名,也就是刚才配置的myapp
uwsgi -s :9090 -w myapp
运行网站发现已经部署完成了。
2. 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
更多用法见文档:http://projects.unbit.it/uwsgi/wiki/Doc
3.为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服务了。
4.实战应用
最初的设置完毕以后,再添加的应用,只需要在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版本,文档缺失,各种兼容问题……大约是因为在python中,有个idea到实现出来实在是太过高效的关系吧,唉,被折腾死了。
回去试试。python的部署一直没有看懂,希望这次可以搞定。
谢谢!
哈哈,你的VPS能折腾脚本程序啦?
请问SimpleCD不更新了吗?
这个还在搬家中,并且计划重写一遍,到时候再更新吧
我一直用的simplecd,因为你抓vc的时候,vc里面很多资源还没有审核删除掉,现在vc很多资源都是“因为版权问题,资源已被删除!”,所以,simplecd保留了很多原汁原味的好资源,呵呵。希望能一直保留下去。
印证了simplecd的初衷是相当的有先见之明啊
好文章,回去啃啃。。。
Pingback: MoinMoin 与 Nginx, fastcgi 与 uwgi 的配置 | apt-blog.net IT民工养成计划 PT博客
博主文章都很好啊,前段时间在百毒中看到几篇文章,发现是obmem.com这个域名的文字,com域名访问时发现在墙外?: O
http://developer.51cto.com/art/201010/229615.htm
文章被偷了。
给出处了,51cto这么做已经是我见过最厚道得了
[emerg]: open() “/usr/local/nginx/conf/uwsgi_params” failed (2: No such file or directory) in /usr/local/nginx/conf/nginx.conf:68
configuration file /usr/local/nginx/conf/nginx.conf test failed
这是为啥?。。求救~
看nginx.conf文件第68行哪里写错了,你就这么问我我也不知道啊
include uwsgi_params
他提示没 uwsgi_params 这个文件啊啊。
在uwsgi的安装目录/源码中找到这个文件,放到nginx配置目录下就行了
哈咯大大~~
话说找你有点事情嘛
想做一个非营利的视频站
我想跟你好好研究研究嘛 留个电子邮箱地址或者发个邮件给我吧
求你了 ~~~~(>_<)~~~~
抱歉,暂时还是没时间折腾,搞回网站弄完simplecd已经是极限了
折腾了几天了,比较菜,百度GG了好多次…无果…汗,按上面说都安装好后,在django建的project建立了myapp
也执行了 uwsgi -s :9090 -w myapp
然后怎么处理project里的程序? 这时访问时候是不是会处理urls.py啊?..
为什么会出现502呢..
502错误就是nginx请求9090端口没有得到回应的错误
1.用netstat -pan | grep 9090检查9090端口是否已被正确监听
2.检查nginx配置的端口是否正确
PS:uwsgi -s :9090 -w myapp 这一步要在myapp.py所在目录下执行才有效
整个流程是这样:web请求->nginx->nginx根据配置把动态请求pass给后台uwsgi->uwsgi接受到请求执行wsgi的app->django自己折腾完毕返回给uwsgi->uwsgi把处理结果返回给nginx->nginx把处理结果返回给用户
ImportError: Settings cannot be imported, because environment variable DJANGO_SETTINGS_MODULE is undefined.
> <怎么弄呢。
在myapp加入了得出下面的结果
os.environ['DJANGO_SETTINGS_MODULE'] = ‘settings’
提示页也从502变了另外Django的提示页
uwsgi.applications dictionary is not defined, trying with the “applications” one…
applications dictionary is not defined, trying with the “application” callable.
application 0 () ready
变了这个 http://184.82.62.208/
看了一下你的出错信息,你django目录没添加到系统目录啊,算了给你一个完整的django myapp.py的样板吧,你自己看着玩吧
这个是一个叫techblog的开源djangoblog程序的配置,目录在/var/www/django1.23/techblog
import os,sys
from os.path import abspath, dirname, join
from site import addsitedir
sys.path.insert(0, abspath(join(dirname(__file__), "../")))
from django.conf import settings
os.environ["DJANGO_SETTINGS_MODULE"] = "techblog.settings"
sys.path.insert(0, join("/var/www/django1.23/techblog", "apps"))
from django.core.handlers.wsgi import WSGIHandler
application = WSGIHandler()
谢谢谢!
请问能不能 一个站点,开一个uwsgi, 不公用,端口不通,这样貌似配置更方便?
是不是性能上有损失?
端口不同,笔误了
性能上当然没啥损失;而且本来就是那么配的,都按第一步配不就行了?
这篇文章我的原创之处就在于公用端口,这方面你连e文的资料都找不到,官方文档都语焉不详,是我自己摸索的,这个得意之处被你华丽丽地无视了,呵呵。
关键在于,你应用如果比较多,有些应用只属于玩票性质的,但又需要它存在着,多个应用多占内存,而且多个端口各种配置很麻烦啊,想想看你有20多个应用,分别占用9001-9020那么多端口,时间一长你知道哪个是哪个不?多麻烦啊。
用/dev/shm/uwsgi.sock这样子使用就可以很清楚看到站点使用那个接口
了解了:)
等我应用多了,就按你的方法配置了,哈哈,thanks a lot
问下,这个uwsgi有没有windows版本的,我试着在windows下编译,但没成功。提示
Traceback (most recent call last):
File “uwsgiconfig.py”, line 54, in
uwsgi_os = os.uname()[0]
AttributeError: ‘module’ object has no attribute ‘uname’
看到windows版的nginx里面也有uwsgi所以就想试一下。似乎找不到这方面的资料。
现在一直在用tornado web server。
不太清楚,可能没有,不过windows下有cygwin这种大招,应该没啥问题的。
我最近就想怎么在Windows编译uwsgi出来,安装了cygwin之后发觉不知如何做起…请教下博主~
问一下,我启动uwsgi,他绑定的是0.0.0.0:9000不是127.0.0.1的,怎么回事呀
nginx的配置能否注释一下各行,我配置了django但是后台管理页面有问题如图http://weibo.com/1659487382/l4ETwjDKv
一个站点只能部署一个的原因是因为,uwsgi使用SERVER_NAME|SCRIPT_NAME来计算应用的。你又没改过SCRIPT_NAME ,同一个SERVER_NAME当然只能部署一个。解决方法也很简单,在locateion里面自定义一个SERVER_NAME就可以了。
另外,virtualenv也不是非用不可。下面是一个web.py和mercurial混合部署的例子中,hg的部分。自定义了SERVER_NAME,并且没用virtualenv。
location /hg {
include uwsgi_params;
uwsgi_param UWSGI_PYHOME /usr;
uwsgi_param UWSGI_CHDIR /var/web/hg;
uwsgi_param UWSGI_SCRIPT hgweb;
uwsgi_param SCRIPT_NAME /;
uwsgi_param SERVER_NAME hgweb;
uwsgi_pass unix:/tmp/uwsgi.socket;
}
实话说,我也写了篇东西,还参考了你的。在这里(http://shell909090.com/blog/?p=1811),不过怎么做引用阿。
这样写不行啊, 我试了, 访问后一个还是会冲掉前面的
能够告诉我, 你的uwsgi启动的参数吗?
不知道有没有人成功地把uwsgi+virualenv+flask配置成功阿?我这边死活不好使呢奇怪
Pingback: 我的那些花儿 » Howto Deploy MoinMoin via Nginx and uWSGI
Pingback: 我的那些花儿 » 20110328
Pingback: 我的那些花儿 » Howto Deploy OSQA via Nginx and uWSGI
请教一下, uwsgi有没有支持web应用热部署的特性?
Pingback: uWSGI配置文件 | 工具牛
Hi, 我在自己配置多站点的时候, 启动uwsgi的参数里加上了–vhost, 但是什么访问第二个网站后, 第一个网站的内容, 也就跟第二个相同了呢?
我的启动参数如下:
uwsgi-2.6 -s /tmp/uwsgi.sock -C -M -d uwsgi.log –vhost -t 30
我没有使用virtualenv, 是不是这个必须用上才行呢?
Pingback: 在免费亚马逊EC2上编译安装nginx+uwsgi+bottle
Pingback: vps部署nginx+FastCGI+web.py环境 | A Nerd or A Geek
学习一门技术,花在配置环境上的时间太多了…
感谢你的教程啊.
Python提倡简单是美,结果是在web开发上,却不见得比PHP简单多少~~