通過Python/WSGI應(yīng)用快速入門解說,說是uwsgi入門,真的入門了嘛?
從第一個WSGI應(yīng)用說到并發(fā)性和魯棒性
1. 啟動方式
方式1(http路由):uwsgi --http :9090 --wsgi-file foobar.py
uWSGI默認(rèn)以單進(jìn)程單線程方式啟動,但在這前端還有1個進(jìn)程監(jiān)聽http端口9090,即一個HTTP路由,路由將9090端口的請求傳遞到WSGI應(yīng)用進(jìn)程? (worker),進(jìn)程管理它并把響應(yīng)發(fā)送回HTTP路由器 (接著路由器發(fā)送回客戶端)。啟動同時uWSGI Python加載器搜索指定wsgi-file文件的默認(rèn)函數(shù)application。
方式2(非http路由):uwsgi --http-socket :9090 --wsgi-file? foobar.py或uwsgi --socket :9090? --wsgi-file? foobar.py
uWSGI默認(rèn)以單進(jìn)程單線程方式啟動,監(jiān)聽http端口9090,請求直接傳遞到WSGI應(yīng)用進(jìn)程 (worker),返回響應(yīng)給客戶端。啟動同時uWSGI Python加載器搜索指定wsgi-file文件的默認(rèn)函數(shù)application。
2. 并發(fā)性
單進(jìn)程單線程滿足不了增長的業(yè)務(wù)并發(fā),uwsgi支持多線程、多進(jìn)程或各種異步模式為你的應(yīng)用提供并發(fā)性。
要擁有額外的線程,用--threads:uwsgi --http :9090 --wsgi-file foobar.py --threads 3
要擁有額外的進(jìn)程,用--processes:uwsgi --http :9090 --wsgi-file foobar.py --processes 3
要擁有額外的進(jìn)程和線程(3個進(jìn)程每個進(jìn)程下3個線程):uwsgi --http :9090 --wsgi-file foobar.py --processes 3 --threads 3
perl世界中一個非常常見的非阻塞/協(xié)程庫是Coro::AnyEvent,簡稱coroae插件。要構(gòu)建一個帶 coroae 支持的uWSGI二進(jìn)制文件curl http://uwsgi.it/install | bash -s coroae? /tmp/uwsgi。4個進(jìn)程每個進(jìn)程下100個協(xié)程:uwsgi --http :9090 --wsgi-file? foobar.py --coroae? 100 --processes 4
3. 魯棒性
在生產(chǎn)環(huán)境上高度推薦應(yīng)用總是運(yùn)行master進(jìn)程。它將不斷監(jiān)控你的進(jìn)程/線程,并且會添加有趣的特性,例如 uWSGI Stats服務(wù)器
增加魯棒性啟用master:uwsgi --http? :9090? --wsgi-file foobar.py --processes 3? --threads? 3? --master
多個進(jìn)程fork()問題
當(dāng)你開始學(xué)習(xí)uWSGI的時候,你會面對的其中一個“問題”是它的 fork() 使用。默認(rèn)情況下,uWSGI在第一個生成的進(jìn)程中加載應(yīng)用,然后多次 fork() 自身。這意味著應(yīng)用被單次加載,然后被拷貝。
雖然這個方法加速了服務(wù)器的啟動,但是有些應(yīng)用在這項(xiàng)技術(shù)下會出問題 (特別是那些在啟動時初始化db連接的應(yīng)用,因?yàn)閷谧舆M(jìn)程中繼承連接的文件描述符)。
如果對uWSGI使用的粗暴的preforking不確定,那么只需使用 --lazy-apps 選項(xiàng)來禁用它。它將會強(qiáng)制uWSGI在每個進(jìn)程worker中完全加載你的應(yīng)用一次。
uwsgi在web服務(wù)器中
一般情況下通用的架構(gòu):負(fù)載均衡器/http路由<=協(xié)議=>uwsgi<=協(xié)議=>web服務(wù)器。
場景0(不帶負(fù)載均衡/http路由器):uwsgi --socket :9090? --wsgi-file? foobar.py
場景1(uwsgi自帶的http路由方式):uwsgi --http :9090 --wsgi-file foobar.py
場景2(nginx+uwsgi,--socket告知uwsgi使用uwsgi協(xié)議):uwsgi --socket :9090? --wsgi-file? foobar.py
一個常用的nginx配置,nginx傳遞每個請求到9090端口且使用uwsgi協(xié)議的服務(wù)器。
location / {
? ? include uwsgi_params;
? ? uwsgi_pass 127.0.0.1:9090;
}
場景3(http協(xié)議的負(fù)載均衡/路由器+uwsgi +http協(xié)議的web服務(wù)器, --http-socket告知uwsgi使用協(xié)議是http):uwsgi --http-socket :9090? --wsgi-file? foobar.py
場景4(最常見的nginx+uwsgi+django,--socket告知uwsgi使用uwsgi協(xié)議):uwsgi? ? --socket? 127.0.0.1:3031 --chdir? /home/foobar/myproject/ --wsgi-file? myproject/wsgi.py --master --processes 4? ? --threads 2 --stats 127.0.0.1:9191
使用--chdir指定Django工程來正確加載模塊
場景5(nginx+uwsgi+flask,--socket告知uwsgi使用uwsgi協(xié)議):uwsgi --socket? 127.0.0.1:3031 --wsgi-file myflaskapp.py? ? ? --callable app --processes 4 --threads 2
--callable 選項(xiàng),告知uwsgi去web服務(wù)器上找一個叫”app”的函數(shù)。Flask將其WSGI函數(shù) 導(dǎo)出為”app”(在這個快速入門開始的地方我們稱為”application”的函數(shù)),myflaskapp.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
? ? return "<span style='color:red'>I am app 1</span>"
簡單總結(jié)下
uwsgi意在為托管服務(wù)而開發(fā)全棧。
uwsgi作為http路由器:uWSGI支持各種的語言和平臺。當(dāng)uwsgi接收到一個請求,怎么知道“路由”到哪里?每個uWSGI插件都被分配了一個數(shù)字 (modifier),通過–http-modifier1? 5”路由到psgi插件”。
perl/psgi分配到的是5,ruby/rack的是7。
uwsgi --plugins http,psgi --http :8080 --http-modifier1 5 --psgi myapp.pl
uwsgi支持的協(xié)議:與nginx通信,uWSGI可以使用各種協(xié)議:http, uwsgi, fastcgi, scgi...。最有效的是uwsgi,Nginx默認(rèn)支持uwsgi協(xié)議。
疑問:nginx自身怎么知道使用http還是uwsgi協(xié)議和uwsgi通信呢?
location / {
? ? include uwsgi_params;
? ? uwsgi_pass 127.0.0.1:3031;
? ? uwsgi_modifier1 5;
}
注意:不需要配置uWSGI指定的modifier,nginx將會使用 uwsgi_modifier1 5; 指令。
uWSGI項(xiàng)目是由許多插件注冊的。你可以選擇構(gòu)建服務(wù)器核心,并為每個特性使用一個插件(需要時加載)。
uwsgi選項(xiàng)參數(shù),先暫存一下。