1.CGI
通用網關接口(Common Gateway Interface/CGI)描述了客戶端和服務器程序之間傳輸數據的一種標準,可讓一個客戶端,從網頁瀏覽器向執行在網絡服務器上的程序請求數據。CGI 獨立於任何語言的,CGI 程序能夠用任何腳本語言或者是徹底獨立編程語言實現,只要這個語言能夠在這個系統上運行。Unix shell script, Python, Ruby, PHP, perl, Tcl, C/C++, 和 Visual Basic 均可以用來編寫 CGI 程序。(http://www.dwz.cn/yFFgQ)php
最初,CGI 是在 1993 年由美國國家超級電腦應用中心(NCSA)爲 NCSA HTTPd Web 服務器開發的。這個 Web 服務器使用了 UNIX shell 環境變量 來保存從 Web 服務器傳遞出去的參數,而後生成一個運行 CGI 的獨立的進程。cgi的處理流程以下圖所示:python
![](http://static.javashuo.com/static/loading.gif)
l step1. web 服務器收到客戶端(瀏覽器)的請求Http Request,啓動CGI程序,並經過環境變量、標準輸入傳遞數據nginx
l step2. cgi進程啓動解析器、加載配置(如業務相關配置)、鏈接其它服務器(如數據庫服務器)、邏輯處理等git
l step3. cgi程將處理結果經過標準輸出、標準錯誤,傳遞給web 服務器github
l step4. web 服務器收到cgi返回的結果,構建Http Response返回給客戶端,並殺死cgi進程web
web服務器與cgi經過環境變量、標準輸入、標準輸出、標準錯誤互相傳遞數據。shell
總結:CGI使外部程序與Web服務器之間交互成爲可能。CGI程式運行在獨立的進程中,並對每一個Web請求創建一個進程,這種方法很是容易實現,但效率不好,難以擴展。面對大量請求,進程的大量創建和消亡使操做系統性能大大降低。此外,因爲地址空間沒法共享,也限制了資源重用。數據庫
2.FastCGI
快速通用網關接口(Fast Common Gateway Interface/FastCGI)是通用網關接口(CGI)的改進,描述了客戶端和服務器程序之間傳輸數據的一種標準。FastCGI致力於減小Web服務器與CGI程式之間互動的開銷,從而使服務器能夠同時處理更多的Web請求。與爲每一個請求建立一個新的進程不一樣,FastCGI使用持續的進程來處理一連串的請求。這些進程由FastCGI進程管理器管理,而不是web服務器。(http://www.dwz.cn/yFMap)apache
當進來一個請求時,Web 服務器把環境變量和這個頁面請求經過一個unix domain socket(都位於同一物理服務器)或者一個IP Socket(FastCGI部署在其它物理服務器)傳遞給FastCGI進程。django
l step1. Web 服務器啓動時載入初始化FastCGI執行環境 。 例如IIS ISAPI、apache mod_fastcgi、nginx ngx_http_fastcgi_module、lighttpd mod_fastcgi
l step2. FastCGI進程管理器自身初始化,啓動多個CGI解釋器進程並等待來自Web 服務器的鏈接。啓動FastCGI進程時,能夠配置以ip和UNIX 域socket兩種方式啓動。
l step3. 當客戶端請求到達Web 服務器時, Web 服務器將請求採用socket方式轉發到 FastCGI主進程,FastCGI主進程選擇並鏈接到一個CGI解釋器。Web 服務器將CGI環境變量和標準輸入發送到FastCGI子進程。
l step4. FastCGI子進程完成處理後將標準輸出和錯誤信息從同一socket鏈接返回Web 服務器。當FastCGI子進程關閉鏈接時,請求便處理完成。
l step5. FastCGI子進程接着等待並處理來自Web 服務器的下一個鏈接。
因爲 FastCGI 程序並不須要不斷的產生新進程,能夠大大下降服務器的壓力而且產生較高的應用效率。它的速度效率最少要比CGI 技術提升 5 倍以上。它還支持分佈式的部署, 即 FastCGI 程序能夠在web 服務器之外的主機上執行。
總結:CGI 就是所謂的短生存期應用程序,FastCGI 就是所謂的長生存期應用程序。FastCGI像是一個常駐(long-live)型的CGI,它能夠一直執行着,不會每次都要花費時間去fork一次(這是CGI最爲人詬病的fork-and-execute 模式)。
3.WSGI
Web服務器網關接口(Python Web Server Gateway Interface,縮寫爲WSGI)是爲Python語言定義的Web服務器和Web應用程序或框架之間的一種簡單而通用的接口。自從WSGI被開發出來之後,許多其它語言中也出現了相似接口。WSGI是做爲Web服務器與Web應用程序或應用框架之間的一種低級別的接口,以提高可移植Web應用開發的共同點。WSGI是基於現存的CGI標準而設計的。
WSGI區分爲兩個部份:一爲「服務器」或「網關」,另外一爲「應用程序」或「應用框架」。在處理一個WSGI請求時,服務器會爲應用程序提供環境資訊及一個回呼函數(Callback Function)。當應用程序完成處理請求後,透過前述的回呼函數,將結果回傳給服務器。所謂的 WSGI 中間件同時實現了API的兩方,所以能夠在WSGI服務和WSGI應用之間起調解做用:從WSGI服務器的角度來講,中間件扮演應用程序,而從應用程序的角度來講,中間件扮演服務器。「中間件」組件能夠執行如下功能:
- 重寫環境變量後,根據目標URL,將請求消息路由到不一樣的應用對象。
- 容許在一個進程中同時運行多個應用程序或應用框架。
- 負載均衡和遠程處理,經過在網絡上轉發請求和響應消息。
- 進行內容後處理,例如應用XSLT樣式表。
之前,如何選擇合適的Web應用程序框架成爲困擾Python初學者的一個問題,這是由於,通常而言,Web應用框架的選擇將限制可用的Web服務器的選擇,反之亦然。那時的Python應用程序一般是爲CGI,FastCGI,mod_python中的一個而設計,甚至是爲特定Web服務器的自定義的API接口而設計的。WSGI沒有官方的實現, 由於WSGI更像一個協議。只要遵守這些協議,WSGI應用(Application)均可以在任何服務器(Server)上運行, 反之亦然。WSGI就是Python的CGI包裝,相對於Fastcgi是PHP的CGI包裝。
WSGI將 web 組件分爲三類: web服務器,web中間件,web應用程序, wsgi基本處理模式爲 : WSGI Server -> (WSGI Middleware)* -> WSGI Application 。
一、WSGI Server/gateway
wsgi server能夠理解爲一個符合wsgi規範的web server,接收request請求,封裝一系列環境變量,按照wsgi規範調用註冊的wsgi app,最後將response返回給客戶端。文字很難解釋清楚wsgi server究竟是什麼東西,以及作些什麼事情,最直觀的方式仍是看wsgi server的實現代碼。以python自帶的wsgiref爲例,wsgiref是按照wsgi規範實現的一個簡單wsgi server。它的代碼也不復雜。
- 服務器建立socket,監聽端口,等待客戶端鏈接。
- 當有請求來時,服務器解析客戶端信息放到環境變量environ中,並調用綁定的handler來處理請求。
- handler解析這個http請求,將請求信息例如method,path等放到environ中。
- wsgi handler再將一些服務器端信息也放到environ中,最後服務器信息,客戶端信息,本次請求信息所有都保存到了環境變量environ中。
- wsgi handler 調用註冊的wsgi app,並將environ和回調函數傳給wsgi app
- wsgi app 將reponse header/status/body 回傳給wsgi handler
- 最終handler仍是經過socket將response信息塞回給客戶端。
二、WSGI Application
wsgi application就是一個普通的callable對象,當有請求到來時,wsgi server會調用這個wsgi app。這個對象接收兩個參數,一般爲environ,start_response。environ就像前面介紹的,能夠理解爲環境變量,跟一次請求相關的全部信息都保存在了這個環境變量中,包括服務器信息,客戶端信息,請求信息。start_response是一個callback函數,wsgi application經過調用start_response,將response headers/status 返回給wsgi server。此外這個wsgi app會return 一個iterator對象 ,這個iterator就是response body。這麼空講感受很虛,對着下面這個簡單的例子看就明白不少了。
三、WSGI MiddleWare
有些功能可能介於服務器程序和應用程序之間,例如,服務器拿到了客戶端請求的URL, 不一樣的URL須要交由不一樣的函數處理,這個功能叫作 URL Routing,這個功能就能夠放在兩者中間實現,這個中間層就是 middleware。middleware對服務器程序和應用是透明的,也就是說,服務器程序覺得它就是應用程序,而應用程序覺得它就是服務器。這就告訴咱們,middleware須要把本身假裝成一個服務器,接受應用程序,調用它,同時middleware還須要把本身假裝成一個應用程序,傳給服務器程序。
其實不管是服務器程序,middleware 仍是應用程序,都在服務端,爲客戶端提供服務,之因此把他們抽象成不一樣層,就是爲了控制複雜度,使得每一次都不太複雜,各司其職。
有了以上三種接口以後,用戶能夠依據不一樣的接口來完成本身的應用程序的編寫,寫完後的程序如何與web服務器進行對接,針對不一樣的語言,不一樣的接口,有着不同的工具。固然使用這些工具也能夠直接啓動服務,暴露給外部。
PHP-CGI
PHP-CGI是PHP自帶的FastCGI管理器。PHP-CGI的不足:
- php-cgi變動php.ini配置後需重啓php-cgi才能讓新的php-ini生效,不能夠平滑重啓
- 直接殺死php-cgi進程php就不能運行了。(PHP-FPM和Spawn-FCGI就沒有這個問題,守護進程會平滑重新生成新的子進程。)
Spawn-FCGI
Spawn-FCGI是一個通用的FastCGI管理服務器,它是lighttpd中的一部份,不少人都用Lighttpd的Spawn-FCGI進行FastCGI模式下的管理工做,不過有很多缺點。而PHP-FPM的出現多少緩解了一些問題,但PHP-FPM有個缺點就是要從新編譯,這對於一些已經運行的環境可能有不小的風險),在php 5.3.3中能夠直接使用PHP-FPM了。Spawn-FCGI的代碼不多,所有才630行,用c語言編寫,最近一次提交是5年前。代碼主頁:https://github.com/lighttpd/spawn-fcgi
Spawn-FCGI代碼分析以下:
- spawn-fcgi 首先create socket,bind,listen 3步建立服務器socket,(把這個socket叫作 fcgi_fd)
- 用dup2,把fcgi_fd 交換給 FCGI_LISTENSOCK_FILENO (FCGI_LISTENSOCK_FILENO數值上等於0,這是fastcgi協議當中指定用來listen的socket id)
- 執行execl ,replaces the current process image with a new process image. process image 進程在運行空間的代碼段
很顯然,Spawn-FCGI也是 pre-fork 模型,只是用了上古C語言編寫,充滿了N多 unix下暗黑編程技巧。
Spawn-FCGI功能很單一:
- 只管fork進程,子進程掛了,主進程僅僅log記錄一次,根本不會從新fork。在2009年一段時間內,我曾經用spawn-fcgi部署php-cgi,當跑一段時間就會全掛掉,只能用crontab定時重啓spawn-fcgi
- 不負責子進程中的網絡IO,把socket放到指定位置就完了,接下來的事情由被spawn的程序處理
Spawn-FCGI是一個很早期的程序,瞻仰一下便可。另外有:1996年的一段代碼:http://www.fastcgi.com/om_archive/kit/cgi-fcgi/cgi-fcgi.c,和spawn-fcgi一個風格
PHP-FPM
PHP-FPM是一個PHP FastCGI管理器,是隻用於PHP的,能夠在 http://php-fpm.org/download下載獲得。PHP-FPM實際上是PHP源代碼的一個補丁,旨在將FastCGI進程管理整合進PHP包中。必須將它patch到你的PHP源代碼中,在編譯安裝PHP後纔可使用。FPM(FastCGI 進程管理器)用於替換 PHP-CGI 的大部分附加功能,對於高負載網站是很是有用的。它的功能包括:
- 支持平滑中止/啓動的高級進程管理功能;
- 能夠工做於不一樣的 uid/gid/chroot 環境下,並監聽不一樣的端口和使用不一樣的 php.ini 配置文件(可取代 safe_mode 的設置);
- stdout 和 stderr 日誌記錄;
- 在發生意外狀況的時候可以從新啓動並緩存被破壞的 opcode;
- 文件上傳優化支持;
- 「慢日誌」 – 記錄腳本(不只記錄文件名,還記錄 PHP backtrace 信息,可使用 ptrace或者相似工具讀取和分析遠程進程的運行數據)運行所致使的異常緩慢;
- fastcgi_finish_request() – 特殊功能:用於在請求完成和刷新數據後,繼續在後臺執行耗時的工做(錄入視頻轉換、統計處理等);
- 動態/靜態子進程產生;
- 基本 SAPI 運行狀態信息(相似Apache的 mod_status);
- 基於 php.ini 的配置文件。
uWSGI
uWSGI 項目旨在爲部署分佈式集羣的網絡應用開發一套完整的解決方案。uWSGI主要面向web及其標準服務,已經成功的應用於多種不一樣的語言。因爲uWSGI的可擴展架構,它可以被無限制的擴展用來支持更多的平臺和語言。目前,你可使用C,C++和Objective-C來編寫插件。項目名稱中的「WSGI」是爲了向同名的Python Web標準表示感謝,由於WSGI爲該項目開發了第一個插件。uWSGI是一個Web服務器,它實現了WSGI協議、uwsgi、http等協議。uWSGI,既不用wsgi協議也不用FastCGI協議,而是自創了一個uwsgi的協議,uwsgi協議是一個uWSGI服務器自有的協議,它用於定義傳輸信息的類型(type of information),每個uwsgi packet前4byte爲傳輸信息類型描述,它與WSGI相比是兩樣東西。聽說該協議大約是fcgi協議的10倍那麼快。
- uWSGI的主要特色以下:
- 超快的性能。
- 低內存佔用(實測爲apache2的mod_wsgi的一半左右)。
- 多app管理。
- 詳盡的日誌功能(能夠用來分析app性能和瓶頸)。
- 高度可定製(內存大小限制,服務必定次數後重啓等)。
其餘拓展知識:Java Servlet、Sinatra、Rack
What is WSGI ?
WSGI is the Web Server Gateway Interface. It is a specification for web servers and application servers to communicate with web applications (though it can also be used for more than that)
WSGI是一種Web服務器網關接口。它是一個Web服務器(如nginx)與應用服務器(如uWSGI服務器)通訊的一種規範。
關於WSGI協議看這裏:WSGI
what is uWSGI ?
uWSGI是一個Web服務器,它實現了WSGI協議、uwsgi、http等協議。
Nginx中HttpUwsgiModule的做用是與uWSGI服務器進行交換。
WSGI vs uwsgi(小寫) vs uWSGI ?
uwsgi同WSGI同樣是一種通訊協議,而uWSGI是實現了uwsgi和WSGI兩種協議的Web服務器。
uwsgi協議是一個uWSGI服務器自有的協議,它用於定義傳輸信息的類型(type of information),每個uwsgi packet前4byte爲傳輸信息類型描述,它與WSGI相比是兩樣東西。
關於uwsgi協議看這裏:The uwsgi protocol
有了uWSGI爲何還須要nginx?
nginx具有優秀的靜態內容處理能力,而後將動態內容轉發給uWSGI服務器,這樣能夠達到很好的客戶端響應。
注:一般python的web部署有兩種
如今項目中用的部署是 nginx + uwsgi + django,說白了就是 是用uWSGI(前面的應該是大寫) 利用wsgi來啓動django。