區分wsgi、uWSGI、uwsgi、php-fpm、CGI、FastCGI

DevOps在路上發表於2021-12-02

在學習Python web開發時候,可能會遇到諸如uwsgi,wsgi等名詞,下面通過梳理總結探究它們之間的關係。

CGI

CGI,(Common Gateway Interface)通用閘道器介面,是一個協議,是外部應用程式(CGI程式)與WEB伺服器之間的介面標準,該協議定義了Web伺服器呼叫外部應用程式的時候需要輸入的引數和給Web伺服器的返回結果。通俗來說,規定一個程式該如何與web伺服器程式之間通訊,從而可以讓這個程式跑在web伺服器上

起源

最早的Web伺服器簡單地響應瀏覽器發來的HTTP請求,並將儲存在伺服器上的HTML檔案返回給瀏覽器,也就是靜態html。這個場景下的伺服器一般被稱為HTTP伺服器,常見的有Apache的httpd和Nginx

事物總是不 斷髮展,網站也越來越複雜,所以出現動態技術。但是伺服器並不能直接執行 php,asp這樣的檔案,自己不能做,外包給別人吧,但是要與第三做個約定,我給你什麼,然後你給我什麼,就是握把請求引數傳送給你,然後我接收你的處 理結果給客戶端。那這個約定就是 common gateway interface,簡稱cgi。這個協議可以用vb,c,php,python 來實現。cgi只是介面協議,根本不是什麼語言。

image.png

引入 CGI 以便客戶端請求能夠觸發 Web 伺服器執行另一個外部程式,客戶端所輸入的資料也會傳給這個外部程式,該程式執行結束後會將生成的 HTML 和其他資料通過 Web 伺服器再返回給客戶端(即動態請求,比如基於 PHP、Python、Java 實現的應用)。利用 CGI 可以針對使用者請求動態返回給客戶端各種各樣動態變化的資訊

工作原理

Web伺服器與CGI程式的互動
WEB伺服器將根據CGI程式的型別決定資料向CGI程式的傳送方式,一般是通過標準輸入/輸出流和環境變數來與CGI程式間傳遞資料。 如下圖所示:
image.png

CGI程式通過標準輸入(STDIN)和標準輸出(STDOUT)來進行輸入輸出。此外CGI程式還通過環境變數來得到輸入,作業系統提供了許多環境變數,它們定義了程式的執行環境,應用程式可以存取它們。Web伺服器和CGI介面又另外設定了一些環境變數,用來向CGI程式傳遞一些重要的引數。
**
常用CGI環境變數:

 變數名 描述
CONTENT_TYPE 這個環境變數的值指示所傳遞來的資訊的MIME型別。目前,環境變數CONTENT_TYPE一般都是:application/x-www-form-urlencoded,他表示資料來自於HTML表單。
CONTENT_LENGTH 如果伺服器與CGI程式資訊的傳遞方式是POST,這個環境變數即使從標準輸入STDIN中可以讀到的有效資料的位元組數。這個環境變數在讀取所輸入的資料時必須使用。
HTTP_COOKIE 客戶機內的 COOKIE 內容。
HTTP_USER_AGENT 提供包含了版本數或其他專有資料的客戶瀏覽器資訊。
PATH_INFO 這個環境變數的值表示緊接在CGI程式名之後的其他路徑資訊。它常常作為CGI程式的引數出現。
QUERY_STRING 如果伺服器與CGI程式資訊的傳遞方式是GET,這個環境變數的值即使所傳遞的資訊。這個資訊經跟在CGI程式名的後面,兩者中間用一個問號’?’分隔。
REMOTE_ADDR 這個環境變數的值是傳送請求的客戶機的IP地址,例如上面的192.168.1.67。這個值總是存在的。而且它是Web客戶機需要提供給Web伺服器的唯一標識,可以在CGI程式中用它來區分不同的Web客戶機。
REMOTE_HOST 這個環境變數的值包含傳送CGI請求的客戶機的主機名。如果不支援你想查詢,則無需定義此環境變數。
REQUEST_METHOD 提供指令碼被呼叫的方法。對於使用 HTTP/1.0 協議的指令碼,僅 GET 和 POST 有意義。
SCRIPT_FILENAME CGI指令碼的完整路徑
SCRIPT_NAME CGI指令碼的的名稱
SERVER_NAME 這是你的 WEB 伺服器的主機名、別名或IP地址。
SERVER_SOFTWARE 這個環境變數的值包含了呼叫CGI程式的HTTP伺服器的名稱和版本號。例如,上面的值為Apache/2.2.14(Unix)

每當客戶請求CGI的時候,WEB伺服器就請求作業系統生成一個新的CGI直譯器程式(如php-cgi.exe),CGI 的一個程式則處理完一個請求後退出,下一個請求來時再建立新程式。當然,這樣在訪問量很少沒有併發的情況也行。但當訪問量增大,併發存在,這種方式就不適合了,於是就有了FastCGI

FastCGI

FASTCGI是Web伺服器(ex:nginx)和語言直譯器(ex:uWsgi)兩者底層的通訊協議的規範,是對CGI的開放的擴充套件。

CGI的一個擴充套件,像是一個常駐(long-live)型的CGI ,廢除了 CGI fork-and-execute (來一個請求 fork 一個新程式處理,處理完再把程式 kill 掉)的工作方式,轉而使用一種長生存期的方法,減少了程式消耗,提升了效能。

而FastCGI 則會先 fork 一個 master 程式,解析配置檔案,初始化執行環境,然後再 fork 多個 worker 程式(與 Nginx 有點像),當 HTTP 請求過來時,master 程式將其會傳遞給一個 worker 程式,然後立即可以接受下一個請求,這樣就避免了重複的初始化操作,效率自然也就提高了。而且當 worker 程式不夠用時,master 程式還可以根據配置預先啟動幾個 worker 程式等著;當空閒 worker 程式太多時,也會關掉一些,這樣不僅提高了效能,還節約了系統資源

php-fpm

FastCGI 只是一個協議規範,需要每個語言具體去實現,PHP-FPM 就是 PHP 版本的 FastCGI 協議實現,有了它,就是實現 PHP 指令碼與 Web 伺服器(通常是 Nginx)之間的通訊,同時它也是一個 PHP SAPI,從而構建起 PHP 直譯器與 Web 伺服器之間的橋樑

Php-fpm全稱是php fastcgi process manager即php fastcgi程式管理器,相比fastcgi靜態的喚起cgi,fpm能根據訪問的壓力動態的喚起cgi程式和銷燬以到達動態的調整cgi數量,這樣可以有效的使用記憶體。除此之外還有其它的一些優點,比如,fpm還可以平滑的過載php配置;由於fpm是使用Unix-Socket來和伺服器通訊,所以也不用再配置cgi埠;fpm有更好的狀態輸出和slowlog日誌,502的時候能給出更多的錯誤細節。

PHP-FPM 負責管理一個程式池來處理來自 Web 伺服器的 HTTP 動態請求,在 PHP-FPM 中,master 程式負責與 Web 伺服器進行通訊,接收 HTTP 請求,再將請求轉發給 worker 程式進行處理,worker 程式主要負責動態執行 PHP 程式碼,處理完成後,將處理結果返回給 Web 伺服器,再由 Web 伺服器將結果傳送給客戶端。這就是 PHP-FPM 的基本工作原理

WSGI / uwsgi / uWSGI

在python web開發中,我們經常使用uwsgi配合nginx部署一個web框架,如Django或flask。同時我們又會說,框架和web伺服器之間要符合WSGI協議

那就來釐清一下這幾個概念。
 
web伺服器和web框架
在講uWSGI和WSGI之前,先要弄清楚web開發的兩大塊,web伺服器和web框架。
web伺服器即用來接受客戶端請求,建立連線,轉發響應的程式。至於轉發的內容是什麼,交由web框架來處理,即處理這些業務邏輯。如查詢資料庫、生成實時資訊等。Nginx就是一個web伺服器,Django或flask就是web框架。
 
那麼如何實現uWSGI和WSGI的配合呢?如何做到任意一個web伺服器,都能搭配任意一個框架呢?這就產生了WSGI協議。只要web伺服器和web框架滿足WSGI協議,它們就能相互搭配。所以WSGI只是一個協議,一個約定。而不是python的模組、框架等具體的功能。
 
而uWSGI,則是實現了WSGI協議的一個web伺服器。即用來接受客戶端請求,轉發響應的程式。實際上,一個uWSGI的web伺服器,再加上Django這樣的web框架,就已經可以實現網站的功能了。

WSGI

WSGI,(WEB SERVER GATEWAY INTERFACE),Web伺服器閘道器介面,是一種Web伺服器閘道器介面,它是一個Web伺服器(如Nginx,uWSGI等伺服器)與web應用(如Flask框架寫的程式)通訊的一種規範。當前執行在WSGI協議之上的Web框架有Bottle,Flask,Django

實現了python web程式與伺服器之間互動的通用性。有了這個東西,web.py或者bottle或者django等等的python web開發框架,就可以輕鬆地部署在不同的web server上了,不需要做任何特殊配置(也需要一些小小的配置調整)

image.png

WSGI協議其實是定義了一種server與application解耦的規範,即可以有多個實現WSGI server的伺服器,也可以有多個實現WSGI application的框架,那麼就可以選擇任意的server和application組合實現自己的web應用。例如 uWSGI和 Gunicorn都是實現了WSGI server協議的伺服器,Django,Flask是實現了WSGI application協議的web框架,可以根據專案實際情況搭配使用。
 
 像Django,Flask框架都有自己實現的簡單的WSGI server,一般用於伺服器除錯,生產環境下建議用其他WSGI server,WSGI伺服器的選擇很多,包括uWSGI和gunicorn

uwsgi

同WSGI一樣是一種通訊協議
uwsgi協議是一個uWSGI伺服器自有的協議,它用於定義傳輸資訊的型別(type of information),每一個uwsgi packet前4byte為傳輸資訊型別描述,它與WSGI相比是兩樣東西。

uWSGI (伺服器)

它是一個Web伺服器,它實現了WSGI協議、uwsgi、http等協議。用於接收前端伺服器轉發的動態請求並處理後發給 web 應用程式。
因為apache也好,nginx也罷,它們自己都沒有解析動態語言如php的功能,而是分派給其他模組來做,比如apache就可以說內建了php模組,支援的非常爽,讓人感覺好像apache就支援php一樣。uwsgi實現了WSGI協議、uwsgi、http等協議。 Nginx中HttpUwsgiModule的作用是與uWSGI伺服器進行交換。

uWSGI是使用C編寫的,顯示了自有的uwsgi協議的Web伺服器。它自帶豐富的元件,其中核心元件包含程式管理、監控、IPC等功能,實現應用伺服器介面的請求外掛支援多種語言和平臺,比如WSGI、Rack、Lua WSAPI,網管元件實現了負載均衡、代理和理由功能

uWSGI也可以當做中介軟體。

  • 如果是Nginx+uWSGI+App,那uWSGI就是一箇中介軟體
  • 如果是uWSGI+App,那它就是伺服器

Nginx+uWGSI

假設我們使用 python 的 Django 框架寫了一個網站,現在要將它掛在網上執行,我們一般需要:

  • Nginx 做為代理伺服器:負責靜態資源傳送(js、css、圖片等)、動態請求轉發以及結果的回覆。
  • uWSGI 做為後端伺服器:負責接收 Nginx 轉發的請求並處理後發給 Django 應用以及接收 Django 應用返回資訊轉發給 Nginx。
  • Django 應用收到請求後處理資料並渲染相應的返回頁面給 uWSGI 伺服器。

image.png
一個Django應用,通過WSGI協議連線uWSGI伺服器,uWSGI伺服器實現WSGI、http等協議,通過uwsgi協議和Nginx伺服器實現http的動態請求和轉發以及結果

問題:有uWGSI了Django為什麼還需要Nginx?
一個普通的個人網站,訪問量不大的話,當然可以由uWSGI和Django構成。但是一旦訪問量過大,客戶端請求連線就要進行長時間的等待。這個時候就出來了分散式伺服器,我們可以多來幾臺web伺服器,都能處理請求。但是誰來分配客戶端的請求連線和web伺服器呢?Nginx就是這樣一個管家的存在,由它來分配。這也就是由Nginx實現反向代理,即代理伺服器。
image.png

Nginx是一個HTTP和反向代理伺服器

  • 正向代理
    正向的就是由瀏覽器主動的想代理伺服器發出請求,經代理伺服器做出處理後再轉給目標伺服器

  • 反向代理
    反向的就是不管瀏覽器同不同意,請求都會經過代理伺服器處理再發給目標伺服器

使用Nginx作為反向代理伺服器的好處:

  • 安全

不管什麼請求都要經過代理伺服器,可以避免外部程式直接攻擊Web伺服器

  • 負載均衡

根據請求情況和伺服器負載情況,將請求分配給不同的Web伺服器,保證伺服器效能

  • 提高Web伺服器的IO效能

請求從客戶端傳到Web伺服器是需要時間的,傳遞多長時間就會讓這個程式阻塞多長時間,而通過反向代理,就可以由反向代理完整接受該請求,然後再傳給Web伺服器,從而保證伺服器效能,而且有的一些簡單的事情(比如靜態檔案)可以直接由反向代理處理,不經過Web伺服器

總結

  • WSGI是一種通訊協議
  • uwsgi是一種通訊協議,常用於在uWSGI伺服器與其他網路伺服器的資料通訊
  • 而uWSGI是實現了uwsgi和WSGI兩種協議的Web伺服器

百度百科上說uwsgi是一種線路協議而不是通訊協議,個人更傾向於uwsgi是類似WSGI的通訊協議的說法,uwsgi和WSGI都是基於CGI擴充套件出來的。

ASGI

非同步閘道器協議介面,一個介於網路協議服務和Python應用之間的標準介面,能夠處理多種通用的協議型別,包括HTTP,HTTP2和WebSocket。
然而目前的常用的WSGI主要是針對HTTP風格的請求響應模型做的設計,並且越來越多的不遵循這種模式的協議逐漸成為Web變成的標準之一,例如WebSocket。

ASGI嘗試保持在一個簡單的應用介面的前提下,提供允許資料能夠在任意的時候、被任意應用程式傳送和接受的抽象。並且同樣描述了一個新的,相容HTTP請求響應以及WebSocket資料幀的序列格式。允許這些協議能通過網路或本地socket進行傳輸,以及讓不同的協議被分配到不同的程式中。
 

WSGI和ASGI的區別

WSGI是基於HTTP協議模式的,不支援WebSocket,而ASGI的誕生則是為了解決Python常用的WSGI不支援當前Web開發中的一些新的協議標準。同時,ASGI對於WSGI原有的模式的支援和WebSocket的擴充套件,即ASGI是WSGI的擴充套件。

參考

https://www.cnblogs.com/wanghetao/p/3934350.html
https://baike.baidu.com/item/fastcgi/10880685
https://www.jianshu.com/p/679dee0a4193
https://baijiahao.baidu.com/s?id=1590941335729952485&wfr=spider&for=pc
https://blog.csdn.net/qq_35318838/article/details/61198183

相關文章