1. 程式人生 > >你可能不知道的 Python Web 部署方式總結

你可能不知道的 Python Web 部署方式總結

分享一篇文章,總結了很多Python Web 部署的內容,原文位於:Python Web部署方式總結

不要讓伺服器裸奔

學過PHP的都瞭解,php的正式環境部署非常簡單,改幾個檔案就OK,用FastCgi方式也是分分鐘的事情。相比起來,Python在web應用上的部署就繁雜的多,主要是工具繁多,主流伺服器支援不足,在瞭解Python的生產環境部署方式之前,先明確一些概念!很重要!python學習交流群:516107834

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指令碼工作流程:

  1. 瀏覽器通過HTML表單或超連結請求指向一個CGI應用程式的URL。
  2. 伺服器執行務器收發到請求。所指定的CGI應用程式。
  3. CGI應用程式執行所需要的操作,通常是基於瀏覽者輸入的內容。
  4. CGI應用程式把結果格式化為網路伺服器和瀏覽器能夠理解的文件(通常是HTML網頁)。
  5. 網路伺服器把結果返回到瀏覽器中。

python有cgi模組可支援原生cgi程式。

FastCGI:

FastCGI是一個可伸縮地、高速地在HTTP server和動態指令碼語言間通訊的介面。多數流行的HTTP server都支援FastCGI,包括Apache、Nginx和lighttpd等,同時,FastCGI也被許多指令碼語言所支援,其中就有Python。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的工作流程:

  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 程式中,程式被賦予明確的角色(響應器角色、認證器角色、過濾器角色)。

WSGI:

Python 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 。

uwsgi:

uwsgi協議是一個uWSGI伺服器自有的協議,它用於定義傳輸資訊的型別(type of information),每一個uwsgi packet前4byte為傳輸資訊型別描述,它與WSGI相比是兩樣東西。據稱其效率是fcgi的10倍。具體的協議內容請參考:the uwsgi protocol(http://uwsgi-docs.readthedocs.org/en/latest/Protocol.html

以上四者都可以理解為協議!協議!協議!實現了這樣的協議,就可以實現Web伺服器與Web應用程式相關聯的web服務!

uWSGI:

uWSGI專案旨在為部署分散式叢集的網路應用開發一套完整的解決方案。uWSGI主要面向web及其標準服務,已經成功的應用於多種不同的語言。由於uWSGI的可擴充套件架構,它能夠被無限制的擴充套件用來支援更多的平臺和語言。目前,你可以使用C,C++和Objective-C來編寫外掛。專案名稱中的“WSGI”是為了向同名的Python Web標準表示感謝,因為WSGI為該專案開發了第一個外掛。uWSGI是一個Web伺服器,它實現了WSGI協議、uwsgi、http等協議。uWSGI,既不用wsgi協議也不用FastCGI協議,而是自創了上文說將的uwsgi協議。

uWSGI的主要特點如下:

  1. 超快的效能。
  2. 低記憶體佔用(實測為apache2的mod_wsgi的一半左右)。
  3. 多app管理。
  4. 詳盡的日誌功能(可以用來分析app效能和瓶頸)。
  5. 高度可定製(記憶體大小限制,服務一定次數後重啟等)。

Gunicorn:

和uWSGi類似的工具,從rails的部署工具(Unicorn)移植過來的。但是它使用的協議是前文所講的WSGI,這是python2.5時定義的官方標準(PEP 333 ),根紅苗正,而且部署比較簡單,詳細的使用教程請點選這裡(http://gunicorn.org/)。Gunicorn採用prefork模式,Gunicorn 伺服器與各種 Web 框架相容,只需非常簡單的執行,輕量級的資源消耗,以及相當迅速。它的特點是與 Django 結合緊密,部署特別方便。 缺點也很多,不支援 HTTP 1.1,併發訪問效能不高,與 uWSGI,Gevent 等有一定的效能差距。

1. Gunicorn設計

Gunicorn 是一個 master 程序,spawn 出數個工作程序的 web 伺服器。master 程序控制工作程序的產生與消亡,工作程序只需要接受請求並且處理。這樣分離的方式使得 reload 程式碼非常方便,也很容易增加或減少工作程序。 工作程序這塊作者給了很大的擴充套件餘地,它可以支援不同的IO方式,如 Gevent,Sync 同步程序,Asyc 非同步程序,Eventlet 等等。master 跟 worker 程序完全分離,使得 Gunicorn 實質上就是一個控制程序的服務。

2. Gunicorn原始碼結構

從 Application.run() 開始,首先初始化配置,從檔案讀取,終端讀取等等方式完成 configurate。然後啟動 Arbiter,Arbiter 是實質上的 master 程序的核心,它首先從配置類中讀取並設定,然後初始化訊號處理函式,建立 socket。然後就是開始 spawn 工作程序,根據配置的工作程序數進行 spawn。然後就進入了輪詢狀態,收到訊號,處理訊號然後繼續。這裡喚醒程序的方式是建立一個 PIPE,通過訊號處理函式往 pipe 裡 write,然後 master 從 select.select() 中喚醒。

工作程序在 spawn 後,開始初始化,然後同樣對訊號進行處理,並且開始輪詢,處理 HTTP 請求,呼叫 WSGI 的應用端,得到 resopnse 返回。然後繼續。

Sync 同步程序的好處在於每個 request 都是分離的,每個 request 失敗都不會影響其他 request,但這樣導致了效能上的瓶頸。

Tornado:

Tornado即使一款python 的開發框架,也是一個非同步非阻塞的http伺服器,它本身的資料產出實現沒有遵從上文所說的一些通用協議,因為自身就是web伺服器,所以動態請求就直接通過內部的機制,輸出成使用者所請求的動態內容。如果把它作為一個單獨伺服器,想用它來配合其他的框架如Flask來部署,則需要採用WSGI協議,Tornado內建了該協議,tornado.wsgi.WSGIContainer。

wsgiref:

Python自帶的實現了WSGI協議的的wsgi server。wsgi server可以理解為一個符合wsgi規範的web server,接收request請求,封裝一系列環境變數,按照wsgi規範呼叫註冊的wsgi app,最後將response返回給客戶端。Django的自帶伺服器就是它了。

以上都可以理解為實現!實現!實現!實現了協議的工具!

注:mod_wsgi(apache的模組)其實也是實現了wsgi協議的一個模組,現在幾乎被廢棄了,所以也不多說了,感興趣的自己查一下吧。

所以如果你採用Django框架開發了應用之後,想部署到生產環境,肯定不能用Django自帶的,可以用使用uwsgi協議的uWSGI伺服器,也可以採用實現了WSGI協議的gunicorn或者Tornado,亦可以用FastCGI、CGI模式的Nginx、lighttpd、apache伺服器。其他框架亦如此!明白了這些概念在部署的時候就可以做到心中有數,各種工具之間的搭配也就“知其然,並知其所以然”了。

在我們組的專案中有兩種框架Django和Tornado,生產環境也用到了兩種部署方式。uWSGI和Gunicorn:

Django專案用Nginx+uWSGI方式部署,Tornado專案用Nginx+Gunicorn方式部署:

Nginx都作為負載均衡以及靜態內容轉發。Tornado專案用supervisord來管理Gunicorn,用Gunicorn管理Tornado。眾所周知,由於Python的GIL存在,所以Python的併發都採用多程序模式,所以我們部署的方式是一個核心兩個程序。