前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Tornado入门(八)【运行和部署】

Tornado入门(八)【运行和部署】

作者头像
用户2936342
发布2018-08-27 14:04:54
7270
发布2018-08-27 14:04:54
举报
文章被收录于专栏:nummynummy

运行和部署

由于Tornado自身提供了HTTPServer, 所以它的运行和部署与其他Python Web 框架不一样。我们可以直接写一个main()方法来启动一个服务器,而不是配置WSGI容器。

代码语言:javascript
复制
def main():
    app = make_app()
    app.listen(8888)
    IOLoop.current().start()

if __name__ == '__main__':
    main()

配置操作系统以启动服务器,注意可能需要提高系统中单个进程可打开的文件数。

进程和端口

由于Python GIL锁的限制,需要通过多线程的方式来尽可能的利用好机器的多核CPU。最好是每个CPU运行一个进程。

Tornado内置了多进程模式,只需要在main方法中做一点点改动:

代码语言:javascript
复制
def main():
    app = make_app()
    server = tornado.httpserver.HTTPServer(app)
    server.bind(8888)
    server.start(0)  # forks one process per cpu
    IOLoop.current().start()

这是启用多进程最简单的方式,所有进程共享同一个端口。但还是存在如下限制:

  • 每个子进程都拥有独立的IOLoop,所以在fork之前不要操作全局的IOLoop实例。
  • 由于所有进程共享一个端口,所以管理起来更为麻烦

对于更为复杂的部署,推荐独立启动进程,然后每个进程监听不同的端口。supervisord提供了进程组可以组织这些进程。

当每个进程使用不同的端口时,可以使用负载均衡的服务器,比如nginx将不同端口转发至同一端口。

运行在负载均衡服务器后面

当使用类似nginx的负载均衡服务时,推荐传递参数xheaders=TrueHTTPServer构造器,这样Tornado才能通过X-Real-IP等头部字段获取真是的请求来源IP而不是转发服务器的IP。

下面是一个示例配置文件:

代码语言:javascript
复制
user nginx;
worker_processes 1;

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

events {
    worker_connections 1024;
    use epoll;
}

http {
    # Enumerate all the Tornado servers here
    upstream frontends {
        server 127.0.0.1:8000;
        server 127.0.0.1:8001;
        server 127.0.0.1:8002;
        server 127.0.0.1:8003;
    }

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    access_log /var/log/nginx/access.log;

    keepalive_timeout 65;
    proxy_read_timeout 200;
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    gzip on;
    gzip_min_length 1000;
    gzip_proxied any;
    gzip_types text/plain text/html text/css text/xml
               application/x-javascript application/xml
               application/atom+xml text/javascript;

    # Only retry if there was a communication error, not a timeout
    # on the Tornado server (to avoid propagating "queries of death"
    # to all frontends)
    proxy_next_upstream error;

    server {
        listen 80;

        # Allow file uploads
        client_max_body_size 50M;

        location ^~ /static/ {
            root /var/www;
            if ($query_string) {
                expires max;
            }
        }
        location = /favicon.ico {
            rewrite (.*) /static/favicon.ico;
        }
        location = /robots.txt {
            rewrite (.*) /static/robots.txt;
        }

        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://frontends;
        }
    }
}

静态文件和缓存

通过配置static_path来支持静态文件的分发。

代码语言:javascript
复制
settings = {
    "static_path": os.path.join(os.path.dirname(__file__), "static"),
    "cookie_secret": "__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__",
    "login_url": "/login",
    "xsrf_cookies": True,
}
application = tornado.web.Application([
    (r"/", MainHandler),
    (r"/login", LoginHandler),
    (r"/(apple-touch-icon\.png)", tornado.web.StaticFileHandler,
     dict(path=settings['static_path'])),
], **settings)

Tornado会自动分发以/static/开头的URL, 它会在static这个目录下查找这些文件。/robots.txt/favicon.ico也会自动分发。

在上面的配置中,我们明确指定使用StaticFileHandler来处理apple-touch-icon.png请求。而applie-touch-icon.png实际位于/static/目录下。

为了提高性能,可以告诉浏览器缓存这些静态页面。为了使用这个功能,在模板中应该使用static_url来代替正式的URL。

代码语言:javascript
复制
<html>
   <head>
      <title>FriendFeed - {{ _("Home") }}</title>
   </head>
   <body>
     <div>![]({{ static_url()</div>
   </body>
 </html>

static_url会将相对路径转换成类似/static/images/logo.png?v=aae54这样的URL,这里的v是logo.png的哈希值。Tornado通过识别它来发送缓存头给浏览器。

由于参数v的值是基于文件内容构建的,所以更新文件或者重启服务器都会改变它的值,然后浏览器就会自动获取最新的文件。如果文件内容没有改变,则继续使用缓存的文件。

在生产环境中,你可能想直接通过 nginx分发静态文件。

代码语言:javascript
复制
location /static/ {
    root /var/friendfeed/static;
    if ($query_string) {
        expires max;
    }
 }

调试模式和自动重启

如果设置debug=True,应用就会开启调试模式。在这种模式下,下面的特性会开启:

  • autoreload=True 当代码发生变化时,应用会自动重启,这样就省去了手动重启的麻烦,但是当出现语法错误的时候,重启会失败。
  • compile_template_cache=False 模板不会缓存
  • static_hash_cache=False 静态文件的哈希值不会缓存。
  • serve_traceback=TrueRequestHandler中发生异常而没有被捕获时,生成一个包含错误信息的页面。

自动重启模式与HTTPServer的多线程模式不兼容,所以当使用自动重启模式时,调用HTTPServer或者tornado.process.fork_processes时,只能指定一个进程。

自动重启模式也可以作为单独的模块使用,调用tornado.autoreload即可。通过组合调试模式和自动重启模式,可以实现更为稳健的应用。在应用中设置debug=True,当出现语法错误时,调用python -m tornado.autoreload myserver.py进行重启。

重启的时候,Python编译器的命令行参数就失效了,因为使用sys.executablesys.argv来执行Python。

WSGI

Tornado一般不需要类似WSGI的容器就可以运行,但是有些情况下,又只能使用WSGI,这时Tornado支持有限的非异步操作。不支持的操作包括协程,@asynchronous修饰器,AsyncHTTPClientauth模块和WebSocket

也可以调用tornado.wsgi.WSGIAdapter将Tornado应用转换为WSGI应用。

代码语言:javascript
复制
import tornado.web
import tornado.wsgi

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")

tornado_app = tornado.web.Application([
    (r"/", MainHandler),
])
application = tornado.wsgi.WSGIAdapter(tornado_app)
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.09.30 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 运行和部署
  • 进程和端口
  • 运行在负载均衡服务器后面
  • 静态文件和缓存
  • 调试模式和自动重启
  • WSGI
相关产品与服务
负载均衡
负载均衡(Cloud Load Balancer,CLB)提供安全快捷的流量分发服务,访问流量经由 CLB 可以自动分配到云中的多台后端服务器上,扩展系统的服务能力并消除单点故障。负载均衡支持亿级连接和千万级并发,可轻松应对大流量访问,满足业务需求。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档