第八章:部署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服务器遇到意外的服务中断后从新上线时泰然处之。

相关文章
相关标签/搜索