當我們部署完一個應用程序,瀏覽網頁時具體的過程是怎樣的呢?首先我們得有一個 Web 服務器來處理 HTTP 協議的內容,Web 服務器獲得客戶端的請求,交給應用程序,應用程序處理完,返回給 Web 服務器,這時 Web 服務器再返回給客戶端。Web 服務器與應用程序之間顯然要進行交互,這時就出現了很多 Web 服務器與應用程序之間交互的規范,最早出現的是 CGI,后來又出現了改進 CGI 性能的FasgCGI,Java 專用的 Servlet 規范,Python 專用的 WSGI 規范等等。有了統一標准,程序的可移植性就大大提高了。這里我們只介紹 WSGI。
WSGI 全稱是 Web Server Gateway Interface,也就是 Web 服務器網關接口,它是 Python 語言定義出來的 Web 服務器和 Web 應用程序之間的簡單而通用的接口,基於現存的 CGI 標准設計,后來在很多其他語言中也出現了類似的接口。 總的來說,WSGI 可以分為服務器和應用程序兩個部分,實際上可以將 WSGI 理解為服務器與應用程序之間的一座橋,橋的一邊是服務器,另一邊是應用程序。
按照 web 組件分類,WSGI 內部可以分為三類,web 應用程序,web 服務器,web 中間件。應用程序端的部分通過Python 語言的各種 Web 框架實現,比如 Flask,Django這些,有了框架,開發者就不需要處理 WSGI,框架會幫忙解決這些,開發者只需處理 HTTP 請求和響應,web 服務器的部分就要復雜一點,可以通過 uWSGI 實現,也可以用最常見的 Web 服務器,比如 Apache、Nginx,但這些 Web 服務器沒有內置 WSGI 的實現,是通過擴展完成的。如 Apache,通過擴展模塊 mod_wsgi 來支持WSGI,Nginx可以通過代理的方式,將請求封裝好,交給應用服務器,比如 uWSGI。uWSGI 可以完成 WSGI 的服務端,進程管理以及對應用的調用。WSGI 中間件的部分可以這樣理解:我們把 WSGI 看做橋,這個橋有兩個橋墩,一個是應用程序端,另一個是服務器端,那么橋面就是 WSGI 中間件,中間件同時具備服務器、應用程序端兩個角色,當然也需要同時遵守 WSGI 服務器和 WSGI 應用程序兩邊的限制和需要。更詳細的內容可以看PEP-333 中間件的描述
Flask 依賴的 Werkzeug 就是一個 WSGI 工具包,官方文檔的定義是 Werkzeug 是為 Python 設計的 HTTP和 WSGI 實用程序庫。我們需要注意的是,Flask 自帶的 Werkzeug 是用來開發的,並不能用於生產環境,Flask 是 Web 框架,而 Werkzeug 不是 Web框架,不是 Web 服務器,它只是一個 WSGI 工具包,它在 Flask 的作用是作為 Web 框架的底層庫,它方便了我們的開發。
我們將 uwsgi 和 uWSGI 放在一起講解。uWSGI 是一個 Web 服務器程序,WSGI,上面已經談到,是一種協議,uwsgi 也是一種協議,uWSGI 實現了 uwsgi、WSGI、http 等協議。 uwsgi 的介紹可以看這里,uwsgi 是 uWSGI 使用的一個自有的協議,它用4個字節來定義傳輸數據類型描述。盡管都是協議,uwsgi 和 WSGI 並沒有聯系,我們需要區分這兩個詞。
Nginx
Nginx 是高效的 Web 服務器和反向代理服務器,可以用作負載均衡(當有 n 個用戶訪問服務器時,可以實現分流,分擔服務器的壓力),與 Apache 相比,Nginx 支持高並發,可以支持百萬級的 TCP 連接,十萬級別的並發連接,部署簡單,內存消耗少,成本低,但 Nginx 的模塊沒有 Apache 豐富。Nginx 支持 uWSGI 的 uwsgi 協議,因此我們可以將 Nginx 與 uWSGI 結合起來,Nginx 通過 uwsgi_pass
將動態內容交給 uWSGI 處理。
uWSGI 和 Nginx 的關系
從上面的講解中,我們知道,uWSGI 可以起到 Web 服務器的作用,那么為什么有了 uWSGI 還需要 Nginx 呢?
最普遍的說法是 Nginx 對於處理靜態文件更有優勢,性能更好。其實如果是小網站,沒有靜態文件需要處理,只用 uWSGI 也是可以的,但加上 Nginx 這一層,優勢可以很具體:
- 對於運維來說比較方便,如果服務器被某個 IP 攻擊,在 Nginx 配置文件黑名單中添加這個 IP 即可,如果只用 uWSGI,那么就需要在代碼中修改了。另一方面,Nginx 是身經百戰的 Web 服務器了,在表現上 uWSGI 顯得更專業,比如說 uWSGI 在早期版本里是不支持 https 的,可以說 Nginx 更安全。
- Nginx 的特點是能夠做負載均衡和 HTTP 緩存,如果不止一台服務器,Nginx 基本就是必選項了,通過 Nginx,將資源可以分配給不同的服務器節點,只有一台服務器,也能很好地提高性能,因為 Nginx 可以通過 headers 的Expires or E-Tag,gzip 壓縮等方式很好地處理靜態資源,畢竟是 C 語言寫的,調用的是 native 的函數,針對 I/O做了優化,對於動態資源來說,Nginx 還可以實現緩存的功能,配合 CDN 優化(這是 uWSGI 做不到的)。Nginx 支持epoll/kqueue 等高效網絡庫,能夠很好地處理高並發短連接請求,性能比 uWSGI 不知道高到哪里去了。
- 如果服務器主機上運行了PHP,Python 等語言寫的多個應用,都需要監聽80端口,這時候 Nginx 就是必選項了。因為我們需要一個轉發的服務。
WSGI:全稱是Web Server Gateway Interface,WSGI不是服務器,python模塊,框架,API或者任何軟件,只是一種規范,描述web server如何與web application通信的規范。要實現WSGI協議,必須同時實現web server和web application,當前運行在WSGI協議之上的web框架有Bottle, Flask, Django。
uwsgi:與WSGI一樣是一種通信協議,是uWSGI服務器的獨占協議,用於定義傳輸信息的類型(type of information)
uWSGI:是一個web服務器,實現了WSGI協議、uwsgi協議、http協議等。
WSGI協議主要包括server和application兩部分:
WSGI server負責從客戶端接收請求,將request轉發給application,將application返回的response返回給客戶端;
WSGI application接收由server轉發的request,處理請求,並將處理結果返回給server。application中可以包括多個棧式的中間件(middlewares),這些中間件需要同時實現server與application,因此可以在WSGI服務器與WSGI應用之間起調節作用:對服務器來說,中間件扮演應用程序,對應用程序來說,中間件扮演服務器。
WSGI協議其實是定義了一種server與application解耦的規范,即可以有多個實現WSGI server的服務器,也可以有多個實現WSGI application的框架,那么就可以選擇任意的server和application組合實現自己的web應用。例如uWSGI和Gunicorn都是實現了WSGI server協議的服務器,Django,Flask是實現了WSGI application協議的web框架,可以根據項目實際情況搭配使用。