網關協議學習:CGI、FastCGI、WSGI、uWSGI

一直對這四者的概念和區別很模糊,如今就特地梳理一下它們的關係與區別。php

CGIpython

CGI即通用網關接口(Common Gateway Interface),是外部應用程序(CGI程序)與Web服務器之間的接口標準,是在CGI程序和Web服務器之間傳遞信息的規程。CGI規範容許 Web服務器執行外部程序,並將它們的輸出發送給Web瀏覽器,CGI將Web的一組簡單的靜態超媒體文檔變成一個完整的新的交互式媒體。通俗的講CGI 就像是一座橋,把網頁和WEB服務器中的執行程序鏈接起來,它把HTML接收的指令傳遞給服務器的執行程序,再把服務器執行程序的結果返還給HTML頁。 CGI 的跨平臺性能極佳,幾乎能夠在任何操做系統上實現。nginx

CGI方式在遇到鏈接請求(用戶請求)先要建立cgi的子進程,激活一個CGI進程,而後處理請求,處理完後結束這個子進程。這就是fork- and-execute模式。因此用cgi方式的服務器有多少鏈接請求就會有多少cgi子進程,子進程反覆加載是cgi性能低下的主要緣由。當用戶請求數 量很是多時,會大量擠佔系統的資源如內存,CPU時間等,形成效能低下。git

CGI腳本工做流程:github

  1. 瀏覽器經過HTML表單或超連接請求指向一個CGI應用程序的URL。
  2. 服務器收發到請求。
  3. 服務器執行所指定的CGI應用程序。
  4. CGI應用程序執行所須要的操做,一般是基於瀏覽者輸入的內容。
  5. CGI應用程序把結果格式化爲網絡服務器和瀏覽器可以理解的文檔(一般是HTML網頁)。
  6. 網絡服務器把結果返回到瀏覽器中。

FastCGIweb

FastCGI是一個可伸縮地、高速地在HTTP server和動態腳本語言間通訊的接口。多數流行的HTTP server都支持FastCGI,包括Apache、Nginx和lighttpd等,同時,FastCGI也被許多腳本語言所支持,其中就有PHP。數據庫

FastCGI是從CGI發展改進而來的。傳統CGI接口方式的主要缺點是性能不好,由於每次HTTP服務器遇到動態程序時都須要從新啓動腳本解析 器來執行解析,而後結果被返回給HTTP服務器。這在處理高併發訪問時,幾乎是不可用的。FastCGI像是一個常駐(long-live)型的CGI, 它能夠一直執行着,只要激活後,不會每次都要花費時間去fork一次(這是CGI最爲人詬病的fork-and-execute 模式)。CGI 就是所謂的短生存期應用程序,FastCGI 就是所謂的長生存期應用程序。因爲 FastCGI 程序並不須要不斷的產生新進程,能夠大大下降服務器的壓力而且產生較高的應用效率。它的速度效率最少要比CGI 技術提升 5 倍以上。它還支持分佈式的運算, 即 FastCGI 程序能夠在網站服務器之外的主機上執行而且接受來自其它網站服務器來的請求。apache

FastCGI是語言無關的、可伸縮架構的CGI開放擴展,其主要行爲是將CGI解釋器進程保持在內存中並所以得到較高的性能。衆所周知,CGI解 釋器的反覆加載是CGI性能低下的主要緣由,若是CGI解釋器保持在內存中並接受FastCGI進程管理器調度,則能夠提供良好的性能、伸縮性、 Fail-Over特性等等。FastCGI接口方式採用C/S結構,能夠將HTTP服務器和腳本解析服務器分開,同時在腳本解析服務器上啓動一個或者多 個腳本解析守護進程。當HTTP服務器每次遇到動態程序時,能夠將其直接交付給FastCGI進程來執行,而後將獲得的結果返回給瀏覽器。這種方式可讓 HTTP服務器專注地處理靜態請求或者將動態腳本服務器的結果返回給客戶端,這在很大程度上提升了整個應用系統的性能。編程

FastCGI的工做流程:windows

  1. Web Server啓動時載入FastCGI進程管理器(PHP-CGI或者PHP-FPM或者spawn-cgi)
  2. FastCGI進程管理器自身初始化,啓動多個CGI解釋器進程(可見多個php-cgi)並等待來自Web Server的鏈接。
  3. 當客戶端請求到達Web Server時,FastCGI進程管理器選擇並鏈接到一個CGI解釋器。Web server將CGI環境變量和標準輸入發送到FastCGI子進程php-cgi。
  4. FastCGI子進程完成處理後將標準輸出和錯誤信息從同一鏈接返回Web Server。當FastCGI子進程關閉鏈接時,請求便告處理完成。FastCGI子進程接着等待並處理來自FastCGI進程管理器(運行在Web Server中)的下一個鏈接。 在CGI模式中,php-cgi在此便退出。

FastCGI 的特色

  1. 打破傳統頁面處理技術。傳統的頁面處理技術,程序必須與 Web 服務器或 Application 服務器處於同一臺服務器中。這種歷史已經早N年被FastCGI技術所打破,FastCGI技術的應用程序能夠被安裝在服務器羣中的任何一臺服務器,而通 過 TCP/IP 協議與 Web 服務器通信,這樣作既適合開發大型分佈式 Web 羣,也適合高效數據庫控制。
  2. 明確的請求模式。CGI 技術沒有一個明確的角色,在 FastCGI 程序中,程序被賦予明確的角色(響應器角色、認證器角色、過濾器角色)。

ISAPI

ISAPI(Internet Server Application Program Interface)是微軟提供的一套面向WEB服務的API接口,它能實現CGI提供的所有功能,並在此基礎上進行了擴展,如提供了過濾器應用程序接 口。ISAPI應用大多數以DLL動態庫的形式使用,能夠在被用戶請求後執行,在處理完一個用戶請求後不會立刻消失,而是繼續駐留在內存中等待處理別的用 戶輸入。此外,ISAPI的DLL應用程序和WEB服務器處於同一個進程中,效率要顯著高於CGI。(因爲微軟的排他性,只能運行於windows環境)

ISAPI服務器擴展爲使用 Internet 服務器的通用網關接口(CGI) 應用程序提供了另外一種選擇。與 CGI 應用程序不一樣,ISA 在 HTTP服務器所在的同一地址空間運行,而且能夠訪問可由 HTTP 服務器使用的全部資源。ISA 的系統開銷比 CGI 應用程序低,由於它們不要求建立其餘進程,也不執行須要越過進程邊界的通訊,而這種通訊很是耗時。若是內存被其餘進程所須要,擴展和篩選器DLL 均可能被卸載。ISAPI 容許在一個 DLL 中有多個命令,這些命令做爲 DLL 中CHttpServer對象的成員函數來實現。CGI 要求每一個任務有一個單獨的名稱和一個到單獨的可執行文件的 URL 映射。每一個新的 CGI 請求啓動一個新進程,而每一個不一樣的請求包含在各自的可執行文件中,這些文件根據每一個請求加載和卸載,所以系統開銷高於 ISA。

PHP-CGI

PHP-CGI是PHP自帶的FastCGI管理器。PHP-CGI的不足:

  1. php-cgi變動php.ini配置後需重啓php-cgi才能讓新的php-ini生效,不能夠平滑重啓
  2. 直接殺死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代碼分析以下:

  1. spawn-fcgi 首先create socket,bind,listen 3步建立服務器socket,(把這個socket叫作 fcgi_fd)
  2. 用dup2,把fcgi_fd 交換給 FCGI_LISTENSOCK_FILENO (FCGI_LISTENSOCK_FILENO數值上等於0,這是fastcgi協議當中指定用來listen的socket id)
  3. 執行execl ,replaces the current process image with a new process image. process image 進程在運行空間的代碼段

很顯然,Spawn-FCGI也是 pre-fork 模型,只是用了上古C語言編寫,充滿了N多 unix下暗黑編程技巧。

Spawn-FCGI功能很單一:

  1. 只管fork進程,子進程掛了,主進程僅僅log記錄一次,根本不會從新fork。在2009年一段時間內,我曾經用spawn-fcgi部署php-cgi,當跑一段時間就會全掛掉,只能用crontab定時重啓spawn-fcgi
  2. 不負責子進程中的網絡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 的大部分附加功能,對於高負載網站是很是有用的。它的功能包括:

  1. 支持平滑中止/啓動的高級進程管理功能;
  2. 能夠工做於不一樣的 uid/gid/chroot 環境下,並監聽不一樣的端口和使用不一樣的 php.ini 配置文件(可取代 safe_mode 的設置);
  3. stdout 和 stderr 日誌記錄;
  4. 在發生意外狀況的時候可以從新啓動並緩存被破壞的 opcode;
  5. 文件上傳優化支持;
  6. 「慢日誌」 – 記錄腳本(不只記錄文件名,還記錄 PHP backtrace 信息,可使用 ptrace或者相似工具讀取和分析遠程進程的運行數據)運行所致使的異常緩慢;
  7. fastcgi_finish_request() – 特殊功能:用於在請求完成和刷新數據後,繼續在後臺執行耗時的工做(錄入視頻轉換、統計處理等);
  8. 動態/靜態子進程產生;
  9. 基本 SAPI 運行狀態信息(相似Apache的 mod_status);
  10. 基於 php.ini 的配置文件。

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服務器的角度來講,中間件扮演應用程序,而從應用程序的 角度來講,中間件扮演服務器。「中間件」組件能夠執行如下功能:

  1. 重寫環境變量後,根據目標URL,將請求消息路由到不一樣的應用對象。
  2. 容許在一個進程中同時運行多個應用程序或應用框架。
  3. 負載均衡和遠程處理,經過在網絡上轉發請求和響應消息。
  4. 進行內容後處理,例如應用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

一、WSGI Server/gateway

wsgi server能夠理解爲一個符合wsgi規範的web server,接收request請求,封裝一系列環境變量,按照wsgi規範調用註冊的wsgi app,最後將response返回給客戶端。文字很難解釋清楚wsgi server究竟是什麼東西,以及作些什麼事情,最直觀的方式仍是看wsgi server的實現代碼。以python自帶的wsgiref爲例,wsgiref是按照wsgi規範實現的一個簡單wsgi server。它的代碼也不復雜。

wsgi-gateway

  1. 服務器建立socket,監聽端口,等待客戶端鏈接。
  2. 當有請求來時,服務器解析客戶端信息放到環境變量environ中,並調用綁定的handler來處理請求。
  3. handler解析這個http請求,將請求信息例如method,path等放到environ中。
  4. wsgi handler再將一些服務器端信息也放到environ中,最後服務器信息,客戶端信息,本次請求信息所有都保存到了環境變量environ中。
  5. wsgi handler 調用註冊的wsgi app,並將environ和回調函數傳給wsgi app
  6. wsgi app 將reponse header/status/body 回傳給wsgi handler
  7. 最終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 仍是應用程序,都在服務端,爲客戶端提供服務,之因此把他們抽象成不一樣層,就是爲了控制複雜度,使得每一次都不太複雜,各司其職。

參考資料:

uWCGI

基於Python的Web項目部署起來真是頭痛,常見的部署方法有:
◆fcgi:用spawn-fcgi或者框架自帶的工具對各個project分別生成監聽進程,而後和http服務互動。
◆wsgi:利用http服務的mod_wsgi模塊來跑各個project。
不管哪一種都很麻煩,apache的mod_wsgi配置起來麻煩,內存佔用還大,若是要加上nginx做爲 靜態頁面的服務器那就更麻煩了;
若是Python中能有個什麼東西像php-cgi同樣監聽同一端口,進行統一管理和 負載平衡,那真是能省下大量的部署功夫。這就是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倍那麼快。

  1. uWSGI的主要特色以下:
  2. 超快的性能。
  3. 低內存佔用(實測爲apache2的mod_wsgi的一半左右)。
  4. 多app管理。
  5. 詳盡的日誌功能(能夠用來分析app性能和瓶頸)。
  6. 高度可定製(內存大小限制,服務必定次數後重啓等)。

另外一篇文章用類比的方法幫助理解:http://sunxiunan.com/?p=1778

總結

從CGI、FastCGI、WSGI、uWSGI,它們的主要功能就是CGI的做用—HTTP服務器與你的或其它機器上的程序進行「交談」的一種工具,其程序須運行在網絡服務器上,是從遠到近逐步完善的過程。CGI是基礎,fastCGI解決了其性能低下、佔用系統和內存高的缺點。WSGI相比較於fastCGI,解決了Web應用框架的選擇將限制可用的Web服務器的選擇這一問題,只要遵守WSGI協議,WSGI應用(Application)均可以在任何服務器(Server)上運行。基於Python的Web項目部署時用wsgi和fastcgi很麻煩,因此像php-cgi同樣監聽同一端口,進行統一管理和負載平衡的uWSG便應運而生,它相較於fastCGI和WSGI的性能要高,佔用的內存要少不少。

相關文章
相關標籤/搜索