相比于PHP,Python應用的部署很麻煩,比較常用的方法有fcgi與 wsgi,然而這兩種都很讓人頭痛。文章介紹了Nginx+uwsgi的簡便方法,來快速的部署Python應用。
反觀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
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 {
server_name app2.mydomain.com;
uwsgi_param UWSGI_SCRIPT myapp2;
uwsgi_param UWSGI_CHDIR /var/www/myappdir2;
}
這樣,重新開機nginx服務,兩個站點就可以共用一個uwsgi服務了。
5.實戰應用
最初的設定完畢以後,再添加的應用,隻需要在Nginx裡面進行少量修改,無需重新開機uwsgi,就能立刻部署完畢。uwsgi自帶了基于 django的監控uwsgi運作狀态的工具,就拿它來部署好了:
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_name lbforum.django.obmem.info;
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版本,文檔缺失,各種相容問題。
原文位址:http://obmem.info/?p=703
uwsgi官網:http://projects.unbit.it/uwsgi/