快速部署Python應(yīng)用:Nginx+uWSGI配置詳解
在PHP里,最方便的就是deployment了,只要把php文件丟到支持PHP的路徑里面,然后訪問(wèn)那個(gè)路徑就能使用了;無(wú)論給主機(jī)添加多少PHP應(yīng)用,只要把目錄改好就沒(méi)你的事了,完全不用關(guān)心php-cgi運(yùn)行得如何,deployment極為方便。
反觀Python,部屬起來(lái)真是頭痛,常見(jiàn)的部署方法有:
◆fcgi:用spawn-fcgi或者框架自帶的工具對(duì)各個(gè)project分別生成監(jiān)聽(tīng)進(jìn)程,然后和http服務(wù)互動(dòng)。
◆wsgi:利用http服務(wù)的mod_wsgi模塊來(lái)跑各個(gè)project。
無(wú)論哪種都很麻煩,apache的mod_wsgi配置起來(lái)很麻煩,內(nèi)存占用還大,如果要加上nginx作為靜態(tài)頁(yè)面的服務(wù)器那就更麻煩了;我的應(yīng)用基本上到后來(lái)都是是各個(gè)project各自為戰(zhàn),且不說(shuō)管理上的混亂,這樣對(duì)負(fù)載也是不利的,空閑的project和繁忙的project同樣需要占用內(nèi)存。
如果Python中能有個(gè)什么東西像php-cgi一樣監(jiān)聽(tīng)同一端口,進(jìn)行統(tǒng)一管理和負(fù)載平衡,那真是能省下大量的部署功夫。偶然看到了uWSGI,才發(fā)現(xiàn)居然一直不知道有那么方便地統(tǒng)一部署工具。uWSGI,既不用wsgi協(xié)議也不用fcgi協(xié)議,而是自創(chuàng)了一個(gè)uwsgi的協(xié)議,據(jù)說(shuō)該協(xié)議大約是fcgi協(xié)議的10倍那么快,有個(gè)比較見(jiàn)下圖:
uWSGI的主要特點(diǎn)如下:
◆超快的性能。
◆低內(nèi)存占用(實(shí)測(cè)為apache2的mod_wsgi的一半左右)。
◆多app管理。
◆詳盡的日志功能(可以用來(lái)分析app性能和瓶頸)。
◆高度可定制(內(nèi)存大小限制,服務(wù)一定次數(shù)后重啟等)。
正式開(kāi)工
uwsgi的文檔雖然很多也很詳細(xì),這里是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的整體配置說(shuō)來(lái)話長(zhǎng),這里不再多說(shuō),假設(shè)已經(jīng)明白Nginx的基本配置,那么uwsgi就類(lèi)似這么配置:
- location / {
- include uwsgi_params
- uwsgi_pass 127.0.0.1:9090
- }
這就是把所有url傳給9090端口的uwsgi協(xié)議程序來(lái)互動(dòng)。再到project目錄建立myapp.py,使得application調(diào)用框架的wsgi接口,比如web.py就是:
- ......
- app = web.application(urls, globals())
- appapplication = app.wsgifunc()
再比如django就是:
- .......
- from django.core.handlers.wsgi import WSGIHandler
- application = WSGIHandler()
然后運(yùn)行uwsgi監(jiān)聽(tīng)9090,其中-w后跟模塊名,也就是剛才配置的myapp
- uwsgi -s :9090 -w myapp
運(yùn)行網(wǎng)站發(fā)現(xiàn)已經(jīng)部署完成了。
3.uwsgi的參數(shù)
以上是單個(gè)project的最簡(jiǎn)單化部署,uwsgi還是有很多令人稱(chēng)贊的功能的,例如:
并發(fā)4個(gè)線程:
- uwsgi -s :9090 -w myapp -p 4
主控制線程+4個(gè)線程:
- uwsgi -s :9090 -w myapp -M -p 4
執(zhí)行超過(guò)30秒的client直接放棄:
- uwsgi -s :9090 -w myapp -M -p 4 -t 30
限制內(nèi)存空間128M:
- uwsgi -s :9090 -w myapp -M -p 4 -t 30 --limit-as 128
服務(wù)超過(guò)10000個(gè)req自動(dòng)respawn:
- uwsgi -s :9090 -w myapp -M -p 4 -t 30 --limit-as 128 -R 10000
后臺(tái)運(yùn)行等:
- uwsgi -s :9090 -w myapp -M -p 4 -t 30 --limit-as 128 -R 10000 -d uwsgi.log
4.為uwsgi配置多個(gè)站點(diǎn)
為了讓多個(gè)站點(diǎn)共享一個(gè)uwsgi服務(wù),必須把uwsgi運(yùn)行成虛擬站點(diǎn):去掉“-w myapp”加上”–vhost”:
- uwsgi -s :9090 -M -p 4 -t 30 --limit-as 128 -R 10000 -d uwsgi.log --vhost
然后必須配置virtualenv,virtualenv是Python的一個(gè)很有用的虛擬環(huán)境工具,這樣安裝:
- apt-get install Python-setuptools
- easy_install virtualenv
然后設(shè)置一個(gè)/多個(gè)app基準(zhǔn)環(huán)境:
- virtualenv /var/www/myenv
應(yīng)用環(huán)境,在此環(huán)境下安裝的軟件僅在此環(huán)境下有效:
- source /var/www/myenv/bin/activate
- pip install django
- pip install mako
- ...
最后配置nginx,注意每個(gè)站點(diǎn)必須單獨(dú)占用一個(gè)server,同一server不同location定向到不同的應(yīng)用不知為何總是失敗,估計(jì)也算是一個(gè)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服務(wù),兩個(gè)站點(diǎn)就可以共用一個(gè)uwsgi服務(wù)了。
#p#
5.實(shí)戰(zhàn)應(yīng)用
最初的設(shè)置完畢以后,再添加的應(yīng)用,只需要在Nginx里面進(jìn)行少量修改,無(wú)需重啟uwsgi,就能立刻部署完畢。uwsgi自帶了基于django的監(jiān)控uwsgi運(yùn)行狀態(tài)的工具,就拿它來(lái)部署好了:
- 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的監(jiān)控信息可以在http://uwsgiadmin.django.obmem.info看到(用戶名密碼都是admin)。再比如LBForum論壇程序的部署:根據(jù)安裝說(shuō)明安裝完畢,再按部署說(shuō)明修改完配置文件,然后只需修改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就是論壇程序了。
后記
雖然寫(xiě)出來(lái)寥寥幾行,配置的時(shí)候我可吃盡了uwsgi的苦頭,有些想當(dāng)然的用法完全不能成立,–no-site參數(shù)一加上去其他都好使LBForum怎么都部署不了,一開(kāi)始多站點(diǎn)公用uwsgi怎么都成功不了等等。
Python世界很有趣,一直會(huì)發(fā)現(xiàn)有趣的東西,但是Python世界也很折騰人,大部分東西都是dev版本,文檔缺失,各種兼容問(wèn)題。
原文地址:http://obmem.info/?p=703
uwsgi官網(wǎng):http://projects.unbit.it/uwsgi/
【編輯推薦】