利用 NGINX 最大化 Python 效能,第一部分:Web 服務和快取

OneAPM官方技術部落格發表於2016-05-04

【編者按】本文主要介紹 nginx 的主要功能以及如何通過 NGINX 優化 Python 應用效能。本文系國內 ITOM 管理平臺 OneAPM 編譯呈現。

Python 的著名之處在於使用簡單方便,軟體開發簡單,而且據說執行效能優於其它指令碼語言。(雖然最新版本的 PHP、PHP 7 可能會與它展開激烈競爭。)

所有人都希望自己的網站和應用程式執行得更快一些。但是,每個網站在流量增長或驟然出現流量峰值時都很容易發生效能問題、甚至當機(這一般會在伺服器最繁忙的時候發生)。此外在執行期間,無論是流量穩步增長還是使用量急速飛漲,幾乎所有的網站都會經歷效能問題。

而關於網站效能問題,那就到了 NGINX 和 NGINX Plus 發揮作用的時候。一般可以通過以下三種方式改善網站效能:

作 web 伺服器,NGINX 最開始的設計初衷就是解決 C10K 問題,也就是能夠輕鬆支援1萬以上的同時訪問。NGINX 作為 Python web 伺服器,可以保證網站在流量較低時依然能夠快速執行。當擁有上千名使用者同時訪問時,你就必須提供更高效能、更少崩潰和更短停機時間的 web 伺服器。你也可以在 NGINX 伺服器上進行靜態檔案快取或微程式快取,不過這兩者在單獨的 NGINX 反向代理伺服器(見下段)上執行表現更佳。

做反向代理伺服器---你可以在當前應用程式伺服器上把 NGINX 設定為反向代理伺服器。NGINX 會將網路請求傳送到應用程式伺服器。這種古怪招數可以提高網站執行速度,減少停機時間,減少伺服器資源佔用,並且提高網站安全。你還可以在反向代理伺服器上快取靜態資料(非常高效),增加動態資料的微程式快取,從而減少應用程式本身的負擔。

做多個應用程式伺服器的負載均衡器---首先要部署反向代理伺服器,然後同時執行多個應用程式伺服器,並使用 NGINX 或 NGINX Plus 來均衡經過它們傳送的流量,進行擴充套件。通過這種部署,你可以輕鬆的根據流量需求來衡量網站效能,增加可靠度和正常執行時間。如果你需要既定的使用者會話儲存在同一個伺服器上,配置負載均衡器還可以支援會話永續性。

無論是將其用作 Python 的 web 伺服器、反向代理伺服器、負載均衡器,還是同時使用以上三種功能,NGINX 和 NGINX Plus 都能帶來很大好處。

下面介紹改善 Python 應用程式效能的5個技巧,本文會分多個章節進行介紹,包括把 NGINX 和 NGINX Plus 作為 web 伺服器,如何實施靜態檔案快取,以及微程式快取應用程式生成檔案。

再就是下篇文章會介紹如何把 NGINX 和 NGINX Plus 當作反向代理伺服器和多個應用程式伺服器的負載均衡器。

技巧1---找出 Python 效能瓶頸

檢驗 Python 應用程式的效能分有兩種不同情況。

第一種是在日常合理使用者數量的情況下;第二種則是負載很大的情況下。

很多站長毫不關心輕負載時網站效能,然而殘酷的現實經驗告訴我們,響應時間的每一秒鐘都應該為之捏一把汗。雖然將響應時間縮短几毫秒是個苦差事,但卻會帶來更好的使用者體驗和更好的運營成果。

另一個就是所有人都擔心的情境:網站繁忙時出現的效能問題,例如執行嚴重減緩和崩潰。此外,很多黑客攻擊也會表現為使用者數量急劇增長,所以改善網站效能也是解決攻擊問題的重要一步。

伺服器會為每位使用者分配一定數量的記憶體,例如 Apache HTTP 伺服器,隨著使用者數量的增長,實體記憶體就會出現超負載,伺服器開始將資料交換到磁碟上,效能驟降,隨之產生效能不良和崩潰。而使用 NGINX 將會有助於解決這一問題。

Python 尤其容易發生記憶體相關的效能問題,因為它在執行任務時一般比其它指令碼語言佔用更多的記憶體(因此它的執行速度更高)。因此,在同等條件下,基於 Python 的應用程式可能比其他語言的應用程式能承受的使用者負載量更小。

優化應用程式或多或少會有幫助,但是這通常不是流量相關網站效能問題的最佳或最快解決方案。本文後續會列出解決流量相關問題的最佳/最快解決方案。當你看完本文後,無論如何都要回去優化你的應用程式,或者使用微服務架構重寫。

技巧2---選擇單一伺服器或多個伺服器配置

小網站只要配置單一伺服器就可以執行良好,大網站則需要有多個伺服器。而如果你處於中間地帶,或者你的網站正在由小網站發展壯大起來,那你就要做些有意思的選擇了。

如果你只具配置有單一伺服器的能力,那麼在流量峰值或整體流量迅速增長時,你會面臨極大風險。因為此時你的擴充套件性會受限,此時解決問題的方法可以包括優化應用程式、把網路伺服器改成 NGINX、換一個更大更快的伺服器,或者把儲存任務轉移到內容分發網路(CDN)等。這其中每一個選項都需要耗費時間、成本,並且在實施過程中都可能會引入錯誤和問題。

此外,配置單一伺服器的情況下,你的網站就有一個單一的失敗節點,會有很多問題造成你的網站下線而且沒有很快很簡捷的解決方法。

利用 NGINX 最大化 Python 效能,第一部分:Web 服務和快取

如果把配置單一伺服器改成使用 NGINX,可以自由選擇開源 NGINX 軟體或 NGINX Plus。NGINX Plus 包含企業級支援及額外功能。有些額外功能可以在單一伺服器配置狀況下實現,例如實時活動監控,而有些功能只有在把 NGINX Plus 作為多個伺服器配置下的反向代理伺服器時才會出現,例如負載均衡和會話永續性。

綜合以上所有考慮,除非你確信你的網站在接下來很長時間都不會擴大規模,停止執行也不會有大麻煩,可以抵抗一些其他的風險,那可以配置單一伺服器。但別忘了配置多個伺服器幾乎可以隨意擴充套件---單次失敗完全可以處理,能迅速擴充容量,總之你應用的效能由你來定。 Tip 3 – Change Your Web Server to NGINX

技巧3---把你的 web 伺服器改成 NGINX

在網路發展早期,Apache等同於web 伺服器。但是21世紀初 NGINX 誕生之後使用越來越廣泛,它已經成為世界上流量前1000、10000和100000的公司的 web 伺服器首選。

NGINX 的設計初衷是解決 C10K 問題,也就是在給定記憶體預算的範圍內能支援10000以上的同時訪問。其它 web 伺服器需要給每個訪問分配一部分記憶體,但當幾千名使用者同時訪問網站時,它們會面臨實體記憶體不足、執行緩慢或崩潰的問題。NGINX 分別處理每個請求,並且能優雅地應對更多使用者。(如上文所述,它在其它功能方面也有優異表現。)

以下為 NGINX 架構的概述。

利用 NGINX 最大化 Python 效能,第一部分:Web 服務和快取

在本圖中,是一個 Python 應用程式伺服器的後臺應用程式塊,需要通過 FastCGI 來訪問。NGINX 並不知道如何執行 Python,因此它需要關口來進入一個能夠執行 Python 的環境。FastCGI 是 PHP、Python 等語言廣泛使用的使用者介面。

不過,Python 和 NGINX 之間的溝通更常用的備選是服務閘道器介面(WSGI)。WSGI 可以在多執行緒、多程式環境下執行,因此它可以在本文提到的所有配置選擇下執行。

如果你要把 NGINX 作成你的 web 伺服器,網上有很多操作幫助資訊:

  • 配置 gunicorn---綠色獨角獸,一個很有名的 WSGI 伺服器,以便使用 NGINX。
  • 配置 uWSGI---另外一個有名的 WSGI 伺服器,以便使用 NGINX。uWSGI 能夠直接支援 NGINX。
  • 使用 uWSGI、NGINX 和 Django---一個很常用的 Python 網站框架。

以下片段展示瞭如何配置 NGINX 來與 uWSGI 一起執行(給出的例項是使用 Python 框架 Django 的一個專案):

http {
    ...
    upstream django {
       server 127.0.0.1:29000;
    }

    server {
        listen 80;
        server_name myapp.example.com;

        root /var/www/myapp/html;

        location / {
            index index.html;
        }

        location /static/  {
            alias /var/django/projects/myapp/static/;
        }

        location /main {
            include /etc/nginx/uwsgi_params;
            uwsgi_pass django;

            uwsgi_param Host $host;
            uwsgi_param X-Real-IP $remote_addr;
            uwsgi_param X-Forwarded-For $proxy_add_x_forwarded_for;
            uwsgi_param X-Forwarded-Proto $http_x_forwarded_proto;
        }
    }
}

技巧4——實施靜態資料快取

靜態資料快取包括把那些不經常變更的檔案(也許是幾個小時,也許是永遠不變)存在一個應用程式伺服器之外的地方。靜態檔案的典型例子就是作為網頁內容一部分展示的 JPEG 影像。

靜態檔案快取是增強應用程式效能的常見方法,而且實際上會在下面幾個層面發生:

  • 在使用者的瀏覽器
  • 多個層級的網路提供者---從一家公司的內網,到網際網路服務供應商(ISP)
  • web 伺服器上,正如本文所述

在 web 伺服器上實施靜態資料快取有兩個好處:

  • 更快傳送到使用者---NGINX 針對靜態資料快取做了優化,執行靜態內容的請求的速度比應用程式伺服器快得多。
  • 減輕應用伺服器的負擔---應用伺服器甚至不會收到快取靜態資料的請求,因為網路伺服器已經實現這些請求。

靜態檔案快取在單個伺服器執行時執行良好,但其實硬體方面依然由 web 伺服器和應用程式伺服器共享。如果 web 伺服器使用硬體找回快取的檔案(及時非常高效)應用程式將無法使用這些硬體,執行速度可能會受到影響。

要支援瀏覽器快取,就要為靜態檔案正確設定 HTTP 標頭。需要考慮 HTTP 快取控制標頭(尤其是它的 max‑age 設定)、Expires 標頭和實體標籤。如想了解更多這方面的介紹,可以參考 Using NGINX as an Application Gateway with uWSGI and Django

下面的程式碼配置 NGINX,用於快取包括 JPEG 檔案、GIF、PNG檔案、MP4 視訊檔案、ppt等多種型別的靜態檔案(用你的網址來替代 www.example.com ):

server {
    # substitute your web server's URL for "www.example.com"
    server_name www.example.com;
    root /var/www/example.com/htdocs;
    index index.php;
    access_log /var/log/nginx/example.com.access.log;
    error_log /var/log/nginx/example.com.error.log;

   location / {
        try_files $uri $uri/ /index.php?$args;
    }

   location ~ \.php$ {
        try_files $uri =404;
        include fastcgi_params;
        # substitute the socket, or address and port, of your Python server
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        #fastcgi_pass 127.0.0.1:9000;
    }  

   location ~* .(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|css|rss|atom|js|jpg
                  |jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid
                  |midi|wav|bmp|rtf)$ {
        expires max;
        log_not_found off;
        access_log off;
    }
}

技巧5---實施微程式快取

微程式快取給了那些執行 Python、PHP 和其它語言的應用程式伺服器提升效能的大好機會。可快取的網頁有以下3種型別:

  • 靜態檔案---可快取,見技巧4。
  • 應用程式生成的、非個人化頁面---一般來說,快取這些沒有意義,因為這些內容需要不斷更新。舉個例子,使用者登入電商網站時看到的頁面(見下段)---在售商品、同類商品推薦等等可能會不斷更新,因此提供最新的網頁非常重要。不過,如果另一個使用者在十分之一秒之後登入,向他們展示前一位使用者看到的同樣頁面也沒有什麼問題。
  • 應用程式生成的、個人化頁面---這些通常不會被快取,因為它們是單個使用者所屬,而且同一個使用者也不會再次看到相同的頁面。舉個例子,使用者登入電商網站後看到的頁面,同樣的頁面不能向其他使用者展示。

利用 NGINX 最大化 Python 效能,第一部分:Web 服務和快取

微程式快取對上述第二種網頁型別很有用---應用程式生成的、非個人化頁面。微是一個概括的時間範圍。如果你的網站一秒之內數次生成同樣的頁面,快取一秒鐘就不會影響網頁的新鮮度。不過這個概括的快取時間期限會極大地減輕應用程式伺服器的負擔,尤其是流程峰值期間。在快取逾時期限內,不用生成10次、20次、100次(相同的內容),而是生成既定的網頁一次,然後這個網頁就會被快取,並且通過快取向多個使用者展示。

而這產生的效果卻不可思議,伺服器一秒鐘處理大量請求執行緩慢,但在只處理一個請求時速度是極快的。(當然,還有任何個人化的頁面)。設定一秒超時的代理伺服器這樣的核心變化只需要幾行配置程式碼。

proxy_cache_path /tmp/cache keys_zon\=cache:10m levels=1:2 inactive=600s max_size=100m;
server {
    proxy_cache cache;
    proxy_cache_valid 200 1s;
    ...
}

更多配置範例,請參考 Tyler Hicks‑Wright 的部落格 Python and uWSGI with NGINX.

結論

在這部分,本文介紹了提升單一伺服器提升 Python 應用效能的解決方案,可以在單一伺服器上配置,也可在反向代理伺服器或單獨的快取伺服器上實現。(快取在單獨的伺服器上執行更好。)接下來的第二部分介紹需要兩個或更多伺服器才能實現的效能提升方案。

當然如果你想了解 NGINX Plus 適用於你的應用程式的高階功能,例如支援、實時活動監控、執行時同時配置,可以去 NGINX 官網檢視。

OneAPM 能夠幫你檢視 Python 應用程式的方方面面,不僅能夠監控終端的使用者體驗,還能監控伺服器效能,同時還支援追蹤資料庫、第三方 API 和 Web 伺服器的各種問題。想閱讀更多技術文章,請訪問 OneAPM 官方技術部落格

本文轉自 OneAPM 官方部落格

原文地址:Maximizing Python Performance with NGINX, Part I: Web Serving and Caching

相關文章