第八章:部署Tornado

到目前爲止,爲了簡單起見,在咱們的例子中都是使用單一的Tornado進程運行的。這使得測試應用和快速變動很是簡單,可是這不是一個合適的部署策略。部署一個應用到生產環境面臨着新的挑戰,既包括最優化性能,也包括管理獨立進程。本章將介紹強化你的Tornado應用、增長請求吞吐量的策略,以及使得部署Tornado服務器更容易的工具。html

8.1 運行多個Tornado實例的緣由

在大多數狀況下,組合一個網頁不是一個特別的計算密集型處理。服務器須要解析請求,取得適當的數據,以及將多個組件組裝起來進行響應。若是你的應用使用阻塞的調用查詢數據庫或訪問文件系統,那麼服務器將不會在等待調用完成時響應傳入的請求。在這些狀況下,服務器硬件有剩餘的CPU時間來等待I/O操做完成。python

鑑於響應一個HTTP請求的時間大部分都花費在CPU空閒狀態下,咱們但願利用這個停工時間,最大化給定時間內咱們能夠處理的請求數量。也就是說,咱們但願服務器可以在處理已打開的請求等待數據的過程當中接收儘量多的新請求。nginx

正如咱們在第五章討論的異步HTTP請求中所看到的,Tornado的非阻塞架構在解決這類問題上大有幫助。回想一下,異步請求容許Tornado進程在等待出站請求返回時執行傳入的請求。然而,咱們碰到的問題是當同步函數調用塊時。設想在一個Tornado執行的數據庫查詢或磁盤訪問塊中,進程不容許迴應新的請求。這個問題最簡單的解決方法是運行多個解釋器的實例。一般狀況下,你會使用一個反向代理,好比Nginx,來非配多個Tornado實例的加載。正則表達式

8.2 使用Nginx做爲反向代理

一個代理服務器是一臺中轉客戶端資源請求到適當的服務器的機器。一些網絡安裝使用代理服務器過濾或緩存本地網絡機器到Internet的HTTP請求。由於咱們將運行一些在不一樣TCP端口上的Tornado實例,所以咱們將使用反向代理服務器:客戶端經過Internet鏈接一個反向代理服務器,而後反向代理服務器發送請求到代理後端的Tornado服務器池中的任何一個主機。代理服務器被設置爲對客戶端透明的,但它會向上遊的Tornado節點傳遞一些有用信息,好比原始客戶端IP地址和TCP格式。shell

咱們的服務器配置如圖8-1所示。反向代理接收全部傳入的HTTP請求,而後把它們分配給獨立的Tornado實例。數據庫

圖8-1

圖8-1 反向代理服務器後端的Tornado實例後端

8.2.1 Nginx基本配置

代碼清單8-1中的列表是一個Nginx配置的示例。Nginx啓動後監聽來自80端口的鏈接,而後分配這些請求到配置文件中列出的上游主機。在這種狀況下,咱們假定上游主機監聽來自他們本身的環回接口上的端口的鏈接。瀏覽器

代碼清單8-1 一個簡單的Nginx代理配置
user nginx;
worker_processes 5;

error_log /var/log/nginx/error.log;

pid /var/run/nginx.pid;

events {
    worker_connections 1024;
    use epoll;
}

proxy_next_upstream error;

upstream tornadoes {
    server 127.0.0.1:8000;
    server 127.0.0.1:8001;
    server 127.0.0.1:8002;
    server 127.0.0.1:8003;
}

server {
    listen 80;
    server_name www.example.org *.example.org;

    location /static/ {
        root /var/www/static;
        if ($query_string) {
            expires max;
        }
    }

    location / {
        proxy_pass_header Server;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Scheme $scheme;
        proxy_pass http://tornadoes;
    }
}

這個配置示例假定你的系統使用了epoll。在不一樣的UNIX發行版本中常常會有輕微的不一樣。一些系統可能使用了poll、/dev/poll或kqueue代替。緩存

按順序來看匹配location /static/location /的請求可能會頗有幫助。Nginx把位於location指令中的字符串看做是一個以行起始錨點開始、任何字母重複結束的正則表達式。因此/被看做是表達式^/.*。當Nginx匹配這些字符串時,像/static這樣更加特殊的字符串在像/這樣的更加的通用的字符串以前被檢查。Nginx文檔中詳細解釋了匹配的順序。安全

除了一些標準樣板外,這個配置文件最重要的部分是upstream指令和服務器配置中的proxy指令。Nginx服務器在80端口監聽鏈接,而後分配這種請求給upstream服務器組中列出的Tornado實例。proxy_pass指令指定接收轉發請求的服務器URI。你能夠在proxy_pass URI中的主機部分引用upstream服務器組的名字。

Nginx默認以循環的方式分配請求。此外,你也能夠選擇基於客戶端的IP地址分配請求,這種狀況下(除非鏈接中斷)能夠確保來自同一IP地址的請求老是被分配到同一個上游節點。你能夠在HTTPUpstreamModule文檔中瞭解更多關於這個選項的知識。

還須要注意的是location /static/指令,它告訴Nginx直接提供靜態目錄的文件,而再也不代理請求到Tornado。Nginx能夠比Tornado更高效地提供靜態文件,因此減小Tornado進程中沒必要要的加載是很是有意義的。

8.2.2 Nginx的SSL解密

應用的開發者在瀏覽器和客戶端之間傳輸我的信息時須要特別注意保護信息不要落入壞人之手。在不安全的WiFi接入中,用戶很容易受到cookie劫持攻擊,從而威脅他們在流行的社交網站上的帳戶。對此,大部分主要的社交網絡應用都默認或做爲用戶可配置選項使用安全協議。同時,咱們使用Nginx解密傳入的SSL加密請求,而後把解碼後的HTTP請求分配給上游服務器。

代碼清單8-2展現了一個用於解密傳入的HTTPS請求的server塊,並使用代碼清單8-1中咱們使用過的代理指令轉發解密後的通訊。

代碼清單8-2 使用SSL的server塊
server {
    listen 443;
    ssl on;
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/cert.key;

    default_type application/octet-stream;

    location /static/ {
        root /var/www/static;
        if ($query_string) {
            expires max;
        }
    }

    location = /favicon.ico {
        rewrite (.*) /static/favicon.ico;
    }

    location / {
        proxy_pass_header Server;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Scheme $scheme;
        proxy_pass http://tornadoes;
    }
}

這段代碼和上面的配置很是類似,除了Nginx將在標準HTTPS的443端口監聽安全Web請求外。若是你想強制使用SSL鏈接,你能夠在server塊中包含一個rewrite指令來監聽80端口的HTTP鏈接。代碼清單8-3是這種重定向的一個例子。

代碼清單8-3 用於重定向HTTP請求到安全渠道的server塊
server {
    listen 80;
    server_name example.com;

    rewrite /(.*) https://$http_host/$1 redirect;
}

Nginx是一個很是魯棒的工具,咱們在這裏僅僅接觸到幫助Tornado部署的一些簡單的配置選項。Nginx的wiki文檔是得到安裝和配置這個強有力的工具額外信息的一個很是好的資源。

8.3 使用Supervisor監控Tornado進程

正如8.2節中埋下的伏筆,咱們將在咱們的Tornado應用中運行多個實例以充分利用現代的多處理器和多核服務器架構。開發團隊大多傳聞每一個核運行一個Tornado進程。可是,正如咱們所知道的,大量的傳聞並不表明事實,因此你的結果可能不一樣。在本節中,咱們將討論在UNIX系統中管理多個Tornado實例的策略。

到目前爲止,咱們都是在命令行中運行Tornado服務器的,就像python main.py --port=8000。可是,在長期的生產部署中,這是不可管理的。由於咱們爲每一個CPU核心運行一個獨立的Tornado進程,所以有不少進程須要監控和控制。supervisor守護進程能夠幫助咱們完成這個任務。

Supervisor的設計是每次開機時啓動其配置文件中列出的進程。這裏,咱們將看到管理咱們在Nginx配置文件中做爲上游主機提到的四個Tornado實例的Supervisor配置。典型的supervisord.conf文件中包含了全局的配置指令,並加載conf.d目錄下的其餘配置文件。代碼清單8-4展現了咱們想啓動的Tornado進程的配置文件。

代碼清單8-4 tornado.conf
[group:tornadoes]
programs=tornado-8000,tornado-8001,tornado-8002,tornado-8003

[program:tornado-8000]
command=python /var/www/main.py --port=8000
directory=/var/www
user=www-data
autorestart=true
redirect_stderr=true
stdout_logfile=/var/log/tornado.log
loglevel=info

[program:tornado-8001]
command=python /var/www/main.py --port=8001
directory=/var/www
user=www-data
autorestart=true
redirect_stderr=true
stdout_logfile=/var/log/tornado.log
loglevel=info

[program:tornado-8002]
command=python /var/www/main.py --port=8002
directory=/var/www
user=www-data
autorestart=true
redirect_stderr=true
stdout_logfile=/var/log/tornado.log
loglevel=info

[program:tornado-8003]
command=python /var/www/main.py --port=8003
directory=/var/www
user=www-data
autorestart=true
redirect_stderr=true
stdout_logfile=/var/log/tornado.log
loglevel=info

爲了Supervisor有意義,你須要至少包含一個program部分。在代碼清單8-4中,咱們定義了四個程序,分別命名爲tornado-8000tornado-8003。program部分定義了Supervisor將要運行的每一個命令的參數。command的值是必須的,一般是帶有咱們但願監聽的port參數的Tornado應用。咱們還爲每一個程序的工做目錄、有效用戶和日誌文件定義了額外的設置;而把autorestartredirect_stderr設置爲true是很是有用的。

爲了一塊兒管理全部的Tornado進程,建立一個組是頗有必要的。在這個例子的頂部,咱們聲明瞭一個叫做tornadoes的組,並在其中列出了每一個程序。如今,當咱們想要管理咱們的Tornado應用時,咱們能夠經過帶有通配符的組名引用全部的組成程序。好比,要重啓應用時,咱們只須要在supervisorctl工具中使用命令restart tornadoes:*

一旦你安裝和配置好Supervisor,你就可使用supervisorctl來管理supervisord進程。爲了啓動你的Web應用,你可讓Supervisor從新讀取配置,而後任何配置改變的程序或程序組將被重啓。你一樣能夠手動啓動、中止和重啓被管理的程序或檢查整個系統的狀態。

supervisor> update
tornadoes: stopped
tornadoes: updated process group
supervisor> status
tornadoes:tornado-8000 RUNNING pid 32091, uptime 00:00:02
tornadoes:tornado-8001 RUNNING pid 32092, uptime 00:00:02
tornadoes:tornado-8002 RUNNING pid 32093, uptime 00:00:02
tornadoes:tornado-8003 RUNNING pid 32094, uptime 00:00:02

Supervisor和你係統的初始化進程一塊兒工做,而且它應該在系統啓動時自動註冊守護進程。當supervisor啓動後,程序組會自動在線。默認狀況下,Supervisor會監控子進程,並在任何程序意外終止時重生。若是你想無論錯誤碼,重啓被管理的進程,你能夠設置autorestarttrue

Supervisor不僅可使管理多個Tornado實例更容易,還能讓你在Tornado服務器遇到意外的服務中斷後從新上線時泰然處之。

相關文章
相關標籤/搜索