第八章:部署Tornado
到目前为止,为了简单起见,在我们的例子中都是使用单一的Tornado进程运行的。这使得测试应用和快速变更非常简单,但是这不是一个合适的部署策略。部署一个应用到生产环境面临着新的挑战,既包括最优化性能,也包括管理独立进程。本章将介绍强化你的Tornado应用、增加请求吞吐量的策略,以及使得部署Tornado服务器更容易的工具。
8.1 运行多个Tornado实例的原因
在大多数情况下,组合一个网页不是一个特别的计算密集型处理。服务器需要解析请求,取得适当的数据,以及将多个组件组装起来进行响应。如果你的应用使用阻塞的调用查询数据库或访问文件系统,那么服务器将不会在等待调用完成时响应传入的请求。在这些情况下,服务器硬件有剩余的CPU时间来等待I/O操作完成。
鉴于响应一个HTTP请求的时间大部分都花费在CPU空闲状态下,我们希望利用这个停工时间,最大化给定时间内我们可以处理的请求数量。也就是说,我们希望服务器能够在处理已打开的请求等待数据的过程中接收尽可能多的新请求。
正如我们在第五章讨论的异步HTTP请求中所看到的,Tornado的非阻塞架构在解决这类问题上大有帮助。回想一下,异步请求允许Tornado进程在等待出站请求返回时执行传入的请求。然而,我们碰到的问题是当同步函数调用块时。设想在一个Tornado执行的数据库查询或磁盘访问块中,进程不允许回应新的请求。这个问题最简单的解决方法是运行多个解释器的实例。通常情况下,你会使用一个反向代理,比如Nginx,来非配多个Tornado实例的加载。
8.2 使用Nginx作为反向代理
一个代理服务器是一台中转客户端资源请求到适当的服务器的机器。一些网络安装使用代理服务器过滤或缓存本地网络机器到Internet的HTTP请求。因为我们将运行一些在不同TCP端口上的Tornado实例,因此我们将使用反向代理服务器:客户端通过Internet连接一个反向代理服务器,然后反向代理服务器发送请求到代理后端的Tornado服务器池中的任何一个主机。代理服务器被设置为对客户端透明的,但它会向上游的Tornado节点传递一些有用信息,比如原始客户端IP地址和TCP格式。
我们的服务器配置如图8-1所示。反向代理接收所有传入的HTTP请求,然后把它们分配给独立的Tornado实例。
图8-1 反向代理服务器后端的Tornado实例
8.2.1 Nginx基本配置
代码清单8-1中的列表是一个Nginx配置的示例。Nginx启动后监听来自80端口的连接,然后分配这些请求到配置文件中列出的上游主机。在这种情况下,我们假定上游主机监听来自他们自己的环回接口上的端口的连接。
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中我们使用过的代理指令转发解密后的通信。
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是这种重定向的一个例子。
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进程的配置文件。
[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-8000到tornado-8003。program部分定义了Supervisor将要运行的每个命令的参数。command的值是必须的,通常是带有我们希望监听的port参数的Tornado应用。我们还为每个程序的工作目录、有效用户和日志文件定义了额外的设置;而把autorestart和redirect_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会监控子进程,并在任何程序意外终止时重生。如果你想不管错误码,重启被管理的进程,你可以设置autorestart为true。
Supervisor不只可以使管理多个Tornado实例更容易,还能让你在Tornado服务器遇到意外的服务中断后重新上线时泰然处之。
第八章:部署Tornado的更多相关文章
- Centos7部署tornado项目
今天帮一个学生解决tornado的部署问题,在此记录了这其中的过程,其中的tornado项目更换为demo示例. 开发环境: 本地开发环境:Win10 + Python3.5.4 + PyCharm ...
- 阿里云服务器部署Tornado应用指南
本篇详细介绍tornado应用部署到阿里云服务器上的全过程. Tornado程序地址:github https://github.com/ddong8/ihasy.git 准备工作:阿里云服务器Cen ...
- 阿里云服务器部署Tornado应用
本篇详细介绍tornado应用部署到阿里云服务器上的全过程. Tornado程序地址:github https://github.com/ddong8/ihasy.git 准备工作:阿里云服务器Cen ...
- Linux高级运维 第八章 部署docker容器虚拟化平台
8.1 Docker概述 实验环境: CENTOS7.4-63 64位 Dcoker概述 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到 ...
- supervisor部署tornado
supervisord常见命令 supervisorctl shutdown 关闭命令 supervisord -c /etc/supervisord.conf 启动supervisord super ...
- centos上发布部署python的tornado网站项目完整流程
先说下大体上的做法,开发环境上要新弄一个 virtualenv的环境,在这个里面放你的开发调试,当然这个其实也不是必须的,但是这样会方便管理一些. 再在centos上也弄一个 virtualenv虚拟 ...
- 《Introduction to Tornado》中文翻译计划——第五章:异步Web服务
http://www.pythoner.com/294.html 本文为<Introduction to Tornado>中文翻译,将在https://github.com/alioth3 ...
- Tornado教程目录
第一章:引言 第二章:表单和模板 第三章:模板扩展 第四章:数据库 第五章:异步Web服务 第六章:编写安全应用 第七章:外部服务认证 第八章:部署Tornado
- Tornado 目录
第一章:引言 1.1 Tornado是什么? 1.1.1 Tornado入门 1.1.2 社区和支持 1.2 简单的Web服务 1.2.1 Hello Tornado 1.2.1.1 参数handle ...
随机推荐
- Python用MySQLdb, pymssql 模块通过sshtunnel连接远程数据库
转载自 https://www.cnblogs.com/luyingfeng/p/6386093.html 安全起见,数据库的访问多半是要做限制的,所以就有一个直接的问题是,往往多数时候,在别的机器上 ...
- Python脚本连接数据库读取特定字段保存在文件中
从Script表中取出Description字段作为文件名,并按协议将脚本归位相同的文件夹,取TestScript字段的内容写入文件 import MySQLdb import sys import ...
- PAT 1051 Pop Sequence[栈][难]
1051 Pop Sequence (25 分) Given a stack which can keep M numbers at most. Push N numbers in the order ...
- Mac Angular打包报错xcode-select: error: tool 'xcodebuild' requires Xcode
Mac Angular打包报错: Error: xcode-select: error: tool 'xcodebuild' requires Xcode, but active developer ...
- Java并发编程实战4章
第4章主要介绍如何构造线程安全类. 在设计线程安全类的过程中,需要包含以下三个基本要素: 找出构成对象状态的所有变量. 找出约束状态变量的不变性条件. 建立对象状态的并发访问管理策略. 构造线程安全类 ...
- Linux系统——NFS网络文件系统
在企业集群架构的工作场景中,NFS网络文件系统一般被用来存储共享视频,图片,附件等静态资源文件,通常网站用户上传的文件都会放到NFS共享里,然后前端所有的节点访问这些静态资源时都会读取NFS存储上的资 ...
- Java基础知识陷阱(六)
本文发表于本人博客. 上次说了下equals跟==的问题,今天再来认识一下这个equals()跟hasCode().上次的代码如下: class Person{ public String name; ...
- RabbitMQ 如何实现对同一个应用的多个节点进行广播
1.背景 了解过RabbitMQ的Fanout模式,应该知道它原本的Fanout模式就是用来做广播的.但是它的广播有一点区别,来回顾下它的含义:Fanout类型没有路由键的概念,只要队列绑定到了改ex ...
- 什么是Java中的原子操作( atomic operations)
1.啥是java的原子性 原子性:即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行. 一个很经典的例子就是银行账户转账问题: 比如从账户A向账户B转1000元,那么 ...
- webmagic的设计机制及原理-如何开发一个Java爬虫 转
此文章是webmagic 0.1.0版的设计手册,后续版本的入门及用户手册请看这里:https://github.com/code4craft/webmagic/blob/master/user-ma ...