標籤:
CGI
CGI即通用閘道介面(Common Gateway Interface),是外部應用程式(CGI程式)與Web伺服器之間的介面標準,是在CGI程式和Web伺服器之間傳遞資訊的規程。CGI規範允許Web伺服器執行外部程式,並將它們的輸出發送給Web瀏覽器,CGI將Web的一組簡單的靜態超媒體文檔變成一個完整的新的互動式媒體。通俗的講CGI就像是一座橋,把網頁和WEB伺服器中的執行程式串連起來,它把HTML接收的指令傳遞給伺服器的執行程式,再把伺服器執行程式的結果返還給HTML頁。CGI 的跨平台效能極佳,幾乎可以在任何作業系統上實現。
CGI方式在遇到串連請求(使用者請求)先要建立cgi的子進程,啟用一個CGI進程,然後處理請求,處理完後結束這個子進程。這就是fork-and-execute模式。所以用cgi方式的伺服器有多少串連請求就會有多少cgi子進程,子進程反覆載入是cgi效能低下的主要原因。當使用者請求數量非常多時,會大量擠占系統的資源如記憶體,CPU時間等,造成效能低下。
CGI指令碼工作流程:
- 瀏覽器通過HTML表單或超連結請求指向一個CGI應用程式的URL。
- 伺服器收發到請求。
- 伺服器執行所指定的CGI應用程式。
- CGI應用程式執行所需要的操作,通常是基於瀏覽者輸入的內容。
- CGI應用程式把結果格式化為網路伺服器和瀏覽器能夠理解的文檔(通常是HTML網頁)。
- 網路伺服器把結果返回到瀏覽器中。
FastCGI
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 程式可以在網站伺服器以外的主機上執行並且接受來自其它網站伺服器來的請求。
FastCGI是語言無關的、可伸縮架構的CGI開放擴充,其主要行為是將CGI解譯器進程保持在記憶體中並因此獲得較高的效能。眾所周知,CGI解譯器的反覆載入是CGI效能低下的主要原因,如果CGI解譯器保持在記憶體中並接受FastCGI進程管理器調度,則可以提供良好的效能、伸縮性、Fail-Over特性等等。FastCGI介面方式採用C/S結構,可以將HTTP伺服器和指令碼解析伺服器分開,同時在指令碼解析伺服器上啟動一個或者多個指令碼解析守護進程。當HTTP伺服器每次遇到動態程式時,可以將其直接交付給FastCGI進程來執行,然後將得到的結果返回給瀏覽器。這種方式可以讓HTTP伺服器專一地處理靜態請求或者將動態指令碼伺服器的結果返回給用戶端,這在很大程度上提高了整個應用系統的效能。
FastCGI的工作流程:
- Web Server啟動時載入FastCGI進程管理器(PHP-CGI或者PHP-FPM或者spawn-cgi)
- FastCGI進程管理器自身初始化,啟動多個CGI解譯器進程(可見多個php-cgi)並等待來自Web Server的串連。
- 當用戶端請求到達Web Server時,FastCGI進程管理器選擇並串連到一個CGI解譯器。Web server將CGI環境變數和標準輸入發送到FastCGI子進程php-cgi。
- FastCGI子進程完成處理後將標準輸出和錯誤資訊從同一串連返回Web Server。當FastCGI子進程關閉串連時,請求便告處理完成。FastCGI子進程接著等待並處理來自FastCGI進程管理器(運行在Web Server中)的下一個串連。 在CGI模式中,php-cgi在此便退出。
FastCGI 的特點
- 打破傳統頁面處理技術。傳統的頁面處理技術,程式必須與 Web 服務器或 Application 伺服器處於同一台伺服器中。這種曆史已經早N年被FastCGI技術所打破,FastCGI技術的應用程式可以被安裝在伺服器群中的任何一台伺服器,而通過 TCP/IP 協議與 Web 服務器通訊,這樣做既適合開發大型分布式 Web 群,也適合高效資料庫控制。
- 明確的請求模式。CGI 技術沒有一個明確的角色,在 FastCGI 程式中,程式被賦予明確的角色(響應器角色、認證器角色、過濾器角色)。
ISAPI
ISAPI(Internet Server Application Program Interface)是微軟提供的一套面向WEB服務的API介面,它能實現CGI提供的全部功能,並在此基礎上進行了擴充,如提供了過濾器應用程式介面。ISAPI應用大多數以DLL動態庫的形式使用,可以在被使用者請求後執行,在處理完一個使用者請求後不會馬上消失,而是繼續駐留在記憶體中等待處理別的使用者輸入。此外,ISAPI的DLL應用程式和WEB伺服器處於同一個進程中,效率要顯著高於CGI。(由於微軟的排他性,只能運行於windows環境)
ISAPI伺服器擴充為使用 網際網路服務器的通用閘道介面(CGI) 應用程式提供了另一種選擇。與 CGI 應用程式不同,ISA 在 HTTP伺服器所在的同一地址空間運行,並且可以訪問可由 HTTP 伺服器使用的所有資源。ISA 的系統開銷比 CGI 應用程式低,因為它們不要求建立其他進程,也不執行需要越過進程邊界的通訊,而這種通訊非常耗時。如果記憶體被其他進程所需要,擴充和篩選器DLL 都可能被卸載。ISAPI 允許在一個 DLL 中有多個命令,這些命令作為 DLL 中CHttpServer對象的成員函數來實現。CGI 要求每個任務有一個單獨的名稱和一個到單獨的可執行檔的 URL 對應。每個新的 CGI 請求啟動一個新進程,而每個不同的請求包含在各自的可執行檔中,這些檔案根據每個請求載入和卸載,因此系統開銷高於 ISA。
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 進程在Runspace的程式碼片段
很顯然,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 的設定檔。
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 。
1、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資訊塞回給用戶端。
2、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。這麼空講感覺很虛,對著下面這個簡單的例子看就明白很多了。
3、WSGI MiddleWare
有些功能可能介於伺服器程式和應用程式之間,例如,伺服器拿到了用戶端請求的URL, 不同的URL需要交由不同的函數處理,這個功能叫做 URL Routing,這個功能就可以放在二者中間實現,這個中介層就是 middleware。middleware對伺服器程式和應用是透明的,也就是說,伺服器程式以為它就是應用程式,而應用程式以為它就是伺服器。這就告訴我們,middleware需要把自己偽裝成一個伺服器,接受應用程式,調用它,同時middleware還需要把自己偽裝成一個應用程式,傳給伺服器程式。
其實無論是伺服器程式,middleware 還是應用程式,都在服務端,為用戶端提供服務,之所以把他們抽象成不同層,就是為了控制複雜度,使得每一次都不太複雜,各司其職。
參考資料:
- http://blog.csdn.net/on_1y/article/details/18803563
- http://blog.kenshinx.me/blog/wsgi-research/
- http://blog.ez2learn.com/2010/01/27/introduction-to-wsgi/
uWCGI
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
轉載請註明:標點符 » 網關協議學習:CGI、FastCGI、WSGI
【技術分享】網關協議學習:CGI、FastCGI、WSGI