?? 學過PHP的都了解,php的正式環(huán)境部署非常簡單泥技,改幾個文件就OK浆兰,用FastCgi方式也是分分鐘的事情磕仅。相比起來珊豹,Python在web應(yīng)用上的部署就繁雜的多,主要是工具繁多榕订,主流服務(wù)器支持不足店茶,在了解Python的生產(chǎn)環(huán)境部署方式之前,先明確一些概念劫恒!很重要贩幻!
CGI:
?? CGI即通用網(wǎng)關(guān)接口(Common?Gateway?Interface)轿腺,是外部應(yīng)用程序(CGI程序)與Web服務(wù)器之間的接口標準,是在CGI程序和Web服務(wù)器之間傳遞信息的規(guī)程丛楚。CGI規(guī)范允許Web服務(wù)器執(zhí)行外部程序族壳,并將它們的輸出發(fā)送給Web瀏覽器,CGI將Web的一組簡單的靜態(tài)超媒體文檔變成一個完整的新的交互式媒體趣些。通俗的講CGI就像是一座橋仿荆,把網(wǎng)頁和WEB服務(wù)器中的執(zhí)行程序連接起來,它把HTML接收的指令傳遞給服務(wù)器的執(zhí)行程序坏平,再把服務(wù)器執(zhí)行程序的結(jié)果返還給HTML頁拢操。CGI 的跨平臺性能極佳,幾乎可以在任何操作系統(tǒng)上實現(xiàn)舶替。
?? CGI方式在遇到連接請求(用戶請求)先要創(chuàng)建cgi的子進程令境,激活一個CGI進程,然后處理請求顾瞪,處理完后結(jié)束這個子進程舔庶。這就是fork-and-execute模式。所以用cgi方式的服務(wù)器有多少連接請求就會有多少cgi子進程玲昧,子進程反復加載是cgi性能低下的主要原因栖茉。當用戶請求數(shù)量非常多時,會大量擠占系統(tǒng)的資源如內(nèi)存孵延,CPU時間等吕漂,造成效能低下。
CGI腳本工作流程:
瀏覽器通過HTML表單或超鏈接請求指向一個CGI應(yīng)用程序的URL尘应。
服務(wù)器執(zhí)行務(wù)器收發(fā)到請求惶凝。所指定的CGI應(yīng)用程序。
CGI應(yīng)用程序執(zhí)行所需要的操作犬钢,通常是基于瀏覽者輸入的內(nèi)容苍鲜。
CGI應(yīng)用程序把結(jié)果格式化為網(wǎng)絡(luò)服務(wù)器和瀏覽器能夠理解的文檔(通常是HTML網(wǎng)頁)。
網(wǎng)絡(luò)服務(wù)器把結(jié)果返回到瀏覽器中玷犹。
python有cgi模塊可支持原生cgi程序
FastCGI:
?? FastCGI是一個可伸縮地混滔、高速地在HTTP?server和動態(tài)腳本語言間通信的接口。多數(shù)流行的HTTP server都支持FastCGI歹颓,包括Apache坯屿、Nginx和lighttpd等,同時巍扛,F(xiàn)astCGI也被許多腳本語言所支持领跛,其中就有Python。FastCGI是從CGI發(fā)展改進而來的撤奸。傳統(tǒng)CGI接口方式的主要缺點是性能很差吠昭,因為每次HTTP服務(wù)器遇到動態(tài)程序時都需要重新啟動腳本解析器來執(zhí)行解析喊括,然后結(jié)果被返回給HTTP服務(wù)器。這在處理高并發(fā)訪問時矢棚,幾乎是不可用的郑什。FastCGI像是一個常駐(long-live)型的CGI,它可以一直執(zhí)行著蒲肋,只要激活后蹦误,不會每次都要花費時間去fork一次(這是CGI最為人詬病的fork-and-execute 模式)。CGI 就是所謂的短生存期應(yīng)用程序肉津,F(xiàn)astCGI 就是所謂的長生存期應(yīng)用程序强胰。由于 FastCGI 程序并不需要不斷的產(chǎn)生新進程,可以大大降低服務(wù)器的壓力并且產(chǎn)生較高的應(yīng)用效率妹沙。它的速度效率最少要比CGI 技術(shù)提高 5 倍以上偶洋。它還支持分布式的運算, 即 FastCGI 程序可以在網(wǎng)站服務(wù)器以外的主機上執(zhí)行并且接受來自其它網(wǎng)站服務(wù)器來的請求。
?? FastCGI是語言無關(guān)的距糖、可伸縮架構(gòu)的CGI開放擴展玄窝,其主要行為是將CGI解釋器進程保持在內(nèi)存中并因此獲得較高的性能。眾所周知悍引,CGI解釋器的反復加載是CGI性能低下的主要原因恩脂,如果CGI解釋器保持在內(nèi)存中并接受FastCGI進程管理器調(diào)度,則可以提供良好的性能趣斤、伸縮性俩块、Fail-Over特性等等。FastCGI接口方式采用C/S結(jié)構(gòu)浓领,可以將HTTP服務(wù)器和腳本解析服務(wù)器分開玉凯,同時在腳本解析服務(wù)器上啟動一個或者多個腳本解析守護進程。當HTTP服務(wù)器每次遇到動態(tài)程序時联贩,可以將其直接交付給FastCGI進程來執(zhí)行漫仆,然后將得到的結(jié)果返回給瀏覽器。這種方式可以讓HTTP服務(wù)器專一地處理靜態(tài)請求或者將動態(tài)腳本服務(wù)器的結(jié)果返回給客戶端泪幌,這在很大程度上提高了整個應(yīng)用系統(tǒng)的性能盲厌。
FastCGI的工作流程:
? Web Server啟動時載入FastCGI進程管理器(PHP-CGI或者PHP-FPM或者spawn-cgi)
FastCGI進程管理器自身初始化,啟動多個CGI解釋器進程(可見多個php-cgi)并等待來自Web Server的連接祸泪。
當客戶端請求到達Web Server時吗浩,F(xiàn)astCGI進程管理器選擇并連接到一個CGI解釋器。Web server將CGI環(huán)境變量和標準輸入發(fā)送到FastCGI子進程php-cgi浴滴。
FastCGI子進程完成處理后將標準輸出和錯誤信息從同一連接返回Web Server拓萌。當FastCGI子進程關(guān)閉連接時岁钓,請求便告處理完成升略。FastCGI子進程接著等待并處理來自FastCGI進程管理器(運行在Web Server中)的下一個連接微王。 在CGI模式中,php-cgi在此便退出品嚣。
FastCGI 的特點:
打破傳統(tǒng)頁面處理技術(shù)炕倘。傳統(tǒng)的頁面處理技術(shù),程序必須與 Web 服務(wù)器或Application?服務(wù)器處于同一臺服務(wù)器中翰撑。這種歷史已經(jīng)早N年被FastCGI技術(shù)所打破罩旋,F(xiàn)astCGI技術(shù)的應(yīng)用程序可以被安裝在服務(wù)器群中的任何一臺服務(wù)器,而通過 TCP/IP 協(xié)議與 Web 服務(wù)器通訊眶诈,這樣做既適合開發(fā)大型分布式 Web 群涨醋,也適合高效數(shù)據(jù)庫控制。
明確的請求模式逝撬。CGI 技術(shù)沒有一個明確的角色浴骂,在 FastCGI 程序中,程序被賦予明確的角色(響應(yīng)器角色宪潮、認證器角色溯警、過濾器角色)。
WSGI:
Python Web服務(wù)器網(wǎng)關(guān)接口(Python Web Server?Gateway?Interface狡相,縮寫為WSGI)是為Python語言定義的Web服務(wù)器和Web應(yīng)用程序或框架之間的一種簡單而通用的接口梯轻。自從WSGI被開發(fā)出來以后,許多其它語言中也出現(xiàn)了類似接口尽棕。WSGI是作為Web服務(wù)器與Web應(yīng)用程序或應(yīng)用框架之間的一種低級別的接口喳挑,以提升可移植Web應(yīng)用開發(fā)的共同點。WSGI是基于現(xiàn)存的CGI標準而設(shè)計的滔悉。
WSGI區(qū)分為兩個部份:一為“服務(wù)器”或“網(wǎng)關(guān)”蟀悦,另一為“應(yīng)用程序”或“應(yīng)用框架”。在處理一個WSGI請求時氧敢,服務(wù)器會為應(yīng)用程序提供環(huán)境上下文及一個回調(diào)函數(shù)(Callback Function)日戈。當應(yīng)用程序完成處理請求后,透過先前的回調(diào)函數(shù)孙乖,將結(jié)果回傳給服務(wù)器浙炼。所謂的 WSGI 中間件同時實現(xiàn)了API的兩方,因此可以在WSGI服務(wù)和WSGI應(yīng)用之間起調(diào)解作用:從WSGI服務(wù)器的角度來說唯袄,中間件扮演應(yīng)用程序弯屈,而從應(yīng)用程序的角度來說,中間件扮演服務(wù)器恋拷∽世鳎“中間件”組件可以執(zhí)行以下功能:
重寫環(huán)境變量后,根據(jù)目標URL蔬顾,將請求消息路由到不同的應(yīng)用對象宴偿。
允許在一個進程中同時運行多個應(yīng)用程序或應(yīng)用框架湘捎。
負載均衡和遠程處理,通過在網(wǎng)絡(luò)上轉(zhuǎn)發(fā)請求和響應(yīng)消息窄刘。
進行內(nèi)容后處理窥妇,例如應(yīng)用XSLT樣式表。
以前娩践,如何選擇合適的Web應(yīng)用程序框架成為困擾Python初學者的一個問題活翩,這是因為,一般而言翻伺,Web應(yīng)用框架的選擇將限制可用的Web服務(wù)器的選擇材泄,反之亦然。那時的Python應(yīng)用程序通常是為CGI吨岭,F(xiàn)astCGI脸爱,mod_python中的一個而設(shè)計,甚至是為特定Web服務(wù)器的自定義的API接口而設(shè)計的未妹。WSGI沒有官方的實現(xiàn), 因為WSGI更像一個協(xié)議簿废。只要遵照這些協(xié)議,WSGI應(yīng)用(Application)都可以在任何服務(wù)器(Server)上運行, 反之亦然。WSGI就是Python的CGI包裝络它,相對于Fastcgi是PHP的CGI包裝族檬。
WSGI將 web 組件分為三類: web服務(wù)器,web中間件,web應(yīng)用程序化戳, wsgi基本處理模式為 : WSGI Server -> (WSGI Middleware)* -> WSGI Application 单料。
uwsgi:
uwsgi協(xié)議是一個uWSGI服務(wù)器自有的協(xié)議,它用于定義傳輸信息的類型(type of information)点楼,每一個uwsgi packet前4byte為傳輸信息類型描述扫尖,它與WSGI相比是兩樣東西。據(jù)稱其效率是fcgi的10倍掠廓。具體的協(xié)議內(nèi)容請參考:the uwsgi protocol
以上四者都可以理解為協(xié)議换怖!協(xié)議!協(xié)議蟀瞧!實現(xiàn)了這樣的協(xié)議沉颂,就可以實現(xiàn)Web服務(wù)器與Web應(yīng)用程序相關(guān)聯(lián)的web服務(wù)!
uWSGI:
uWSGI項目旨在為部署分布式集群的網(wǎng)絡(luò)應(yīng)用開發(fā)一套完整的解決方案悦污。uWSGI主要面向web及其標準服務(wù)铸屉,已經(jīng)成功的應(yīng)用于多種不同的語言。由于uWSGI的可擴展架構(gòu)切端,它能夠被無限制的擴展用來支持更多的平臺和語言彻坛。目前,你可以使用C,C++和Objective-C來編寫插件昌屉。項目名稱中的“WSGI”是為了向同名的Python Web標準表示感謝钙蒙,因為WSGI為該項目開發(fā)了第一個插件。uWSGI是一個Web服務(wù)器怠益,它實現(xiàn)了WSGI協(xié)議、uwsgi瘾婿、http等協(xié)議蜻牢。uWSGI,既不用wsgi協(xié)議也不用FastCGI協(xié)議偏陪,而是自創(chuàng)了上文說將的uwsgi協(xié)議抢呆。
uWSGI的主要特點如下:
超快的性能。
低內(nèi)存占用(實測為apache2的mod_wsgi的一半左右)笛谦。
多app管理抱虐。
詳盡的日志功能(可以用來分析app性能和瓶頸)。
高度可定制(內(nèi)存大小限制饥脑,服務(wù)一定次數(shù)后重啟等)恳邀。
Gunicorn:
和uWSGi類似的工具,從rails的部署工具(Unicorn)移植過來的灶轰。但是它使用的協(xié)議是前文所講的WSGI谣沸,這是python2.5時定義的官方標準(PEP 333?),根紅苗正笋颤,而且部署比較簡單乳附,詳細的使用教程請點擊這里。Gunicorn采用prefork模式伴澄,Gunicorn 服務(wù)器與各種 Web 框架兼容赋除,只需非常簡單的執(zhí)行,輕量級的資源消耗非凌,以及相當迅速举农。它的特點是與?Django?結(jié)合緊密,部署特別方便敞嗡。 缺點也很多并蝗,不支持 HTTP 1.1,并發(fā)訪問性能不高秸妥,與 uWSGI滚停,Gevent 等有一定的性能差距。
1. Gunicorn設(shè)計
Gunicorn 是一個 master 進程粥惧,spawn 出數(shù)個工作進程的?web?服務(wù)器键畴。master 進程控制工作進程的產(chǎn)生與消亡,工作進程只需要接受請求并且處理。這樣分離的方式使得 reload 代碼非常方便起惕,也很容易增加或減少工作進程涡贱。 工作進程這塊作者給了很大的擴展余地,它可以支持不同的IO方式惹想,如 Gevent,Sync 同步進程问词,Asyc 異步進程,Eventlet 等等嘀粱。master 跟 worker 進程完全分離激挪,使得 Gunicorn 實質(zhì)上就是一個控制進程的服務(wù)。
2. Gunicorn源碼結(jié)構(gòu)
從?Application.run 開始锋叨,首先初始化配置垄分,從文件讀取,終端讀取等等方式完成 configurate娃磺。然后啟動 Arbiter薄湿,Arbiter 是實質(zhì)上的 master 進程的核心,它首先從配置類中讀取并設(shè)置偷卧,然后初始化信號處理函數(shù)豺瘤,建立 socket。然后就是開始 spawn 工作進程听诸,根據(jù)配置的工作進程數(shù)進行 spawn炉奴。然后就進入了輪詢狀態(tài),收到信號蛇更,處理信號然后繼續(xù)瞻赶。這里喚醒進程的方式是建立一個 PIPE,通過信號處理函數(shù)往 pipe 里 write派任,然后 master 從 select.select 中喚醒砸逊。
工作進程在?spawn?后,開始初始化掌逛,然后同樣對信號進行處理师逸,并且開始輪詢,處理 HTTP 請求豆混,調(diào)用 WSGI 的應(yīng)用端篓像,得到 resopnse 返回。然后繼續(xù)皿伺。
Sync 同步進程的好處在于每個?request?都是分離的员辩,每個 request 失敗都不會影響其他 request,但這樣導致了性能上的瓶頸鸵鸥。
Tornado:
Tornado即使一款python 的開發(fā)框架奠滑,也是一個異步非阻塞的http服務(wù)器丹皱,它本身的數(shù)據(jù)產(chǎn)出實現(xiàn)沒有遵從上文所說的一些通用協(xié)議,因為自身就是web服務(wù)器宋税,所以動態(tài)請求就直接通過內(nèi)部的機制摊崭,輸出成用戶所請求的動態(tài)內(nèi)容。如果把它作為一個單獨服務(wù)器杰赛,想用它來配合其他的框架如Flask來部署呢簸,則需要采用WSGI協(xié)議,Tornado內(nèi)置了該協(xié)議乏屯,tornado.wsgi.WSGIContainer根时。
wsgiref:
Python自帶的實現(xiàn)了WSGI協(xié)議的的wsgi server。wsgi?server可以理解為一個符合wsgi規(guī)范的web server瓶珊,接收request請求啸箫,封裝一系列環(huán)境變量耸彪,按照wsgi規(guī)范調(diào)用注冊的wsgi app伞芹,最后將response返回給客戶端。Django的自帶服務(wù)器就是它了蝉娜。
以上都可以理解為實現(xiàn)唱较!實現(xiàn)!實現(xiàn)召川!實現(xiàn)了協(xié)議的工具南缓!
注:mod_wsgi(apache的模塊)其實也是實現(xiàn)了wsgi協(xié)議的一個模塊,現(xiàn)在幾乎不廢棄了荧呐,所以也不多說了汉形,感興趣的自己查一下吧。
所以如果你采用Django框架開發(fā)了應(yīng)用之后倍阐,想部署到生產(chǎn)環(huán)境概疆,肯定不能用Django自帶的妆绞,可以用使用uwsgi協(xié)議的uWSGI服務(wù)器宿稀,也可以采用實現(xiàn)了WSGI協(xié)議的gunicorn或者Tornado,亦可以用FastCGI篡石、CGI模式的Nginx概耻、lighttpd使套、apache服務(wù)器。其他框架亦如此鞠柄!明白了這些概念在部署的時候就可以做到心中有數(shù)侦高,各種工具之間的搭配也就“知其然,并知其所以然”了厌杜。
在我們組的項目中有兩種框架Django和Tornado矫膨,生產(chǎn)環(huán)境也用到了兩種部署方式。uWSGI和Gunicorn:
Django項目用Nginx+uWSGI方式部署,Tornado項目用Nginx+Gunicorn方式部署:
Nginx都作為負載均衡以及靜態(tài)內(nèi)容轉(zhuǎn)發(fā)侧馅。Tornado項目用supervisord來管理Gunicorn危尿,用Gunicorn管理Tornado。眾所周知馁痴,由于Python的GIL存在谊娇,所以Python的并發(fā)都采用多進程模式,所以我們部署的方式是一個核心兩個進程罗晕。