美文网首页
2.7、User’s guide (Running and de

2.7、User’s guide (Running and de

作者: 宝宝家的隔壁老王 | 来源:发表于2018-03-29 21:57 被阅读13次

    Running and deploying

    tornado 有自己的 HTTPServer,他的运行和部署和其他的 python web 框架略有不同。
    
    你只需要写一个 main() 函数启动服务,不需要配置 WSGI 容器来找到你的应用。
    
    def main():
        app = make_app()
        app.listen(8888)
        IOLoop.current().start()
    
    if __name__ == '__main__':
        main()
    
    配置你的操作系统或者进程管理器来运行程序启动服务。增加每个进程打开文件数量是很有必要的 (避免 Too many open files 错误)。
    
    通过 ulimit 命令行设置 (一般为 50000)。修改 /etc/security/limits.conf 或者设置管理的 minfds 配置。
    

    Processes and ports

    由于 python 的 GIL(Global Interpreter Lock),需要运行多个 python 进程才能充分利用机器的 cpu。
    
    通常是每个 CPU 运行一个进程。
    
    tornado 包括一个内置的多进程模块可以同时启动多个进程。
    
    需要在标准 main 函数中做轻微改动。
    
    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 实例。
    
    第二:很难做到零宕机下更新模块
    
    第三:因为所有进程共享相同的端口,所以跟男去分别监控他们。
    
    对于复杂的部署,建议使用独立的进程,每一个监听不同的端口。进程组管理特征是有一个很好的方式去实现。
    
    当每一个进程使用不同的端口时,一个外部负载均衡器如 HAProxy 或者 nginx 通常需要呈现一个唯一地址给外部访问。
    

    Running behind a load balancer

    当运行在负载均衡器如 nginx 时,建议在 HTTPServer 构造器中传递 xheaders=True。他将会告诉 tornado 使用 X-Real-IP 获取用户的 IP 地址,而不是将所有流量传给平衡器的 IP 地址。
    
    这是一个简单的 nginx 配置,在结构上类似于我们使用的 FriendFeed。他假定 nginx 和 tornado 服务运行在同一台机器,四个 tornado 服务运行在 8000-8003 4个端口。
    
    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 files and aggressive file caching

    在 tornado 中,可以通过 static_path 在应用中设置静态文件的路径。
    
    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)
    
    这个设置会自动将所有以 /static/ 开头的请求到指定的静态文件目录。我们也会自动的将 /robots.txt 和 /favicon.ico 服务到指定的静态文件。(即使他们不是以 /static/ 开头)
    
    上文中,尽管在静态文件夹中,我们还是明确的使用 StaticFileHandler 配置 tornado 服务的 apple-touch-icon.png 文件。
    
    为了提高性能,浏览器通常会积极缓存静态资源,这样浏览器可以避免发送不必要可能阻塞页面呈现的 If-Modified-Since 或者 Etag 请求。
    
    tornado 支持开箱即用的静态资源版本管理。
    
    为了使用这个特性,在模板中使用 static_url 方法而不是直接将静态文件的 URL 输入在 HTML 中。 
    
    <html>
       <head>
          <title>FriendFeed - {{ _("Home") }}</title>
       </head>
       <body>
         <div><img src="{{ static_url("images/logo.png") }}"/></div>
       </body>
     </html>
    
    static_url() 函数将相对路径转化为 URI 地址,如:/static/images/logo.png?v=aae54 。参数 v 是 logo.png 值的散列值,他是 tornado 服务通过发送缓存头告知用户浏览器去做无限期的缓存。
    
    因为 v 参数是基于文件内容的,如果你更新了文件并且重启了服务,他将会发送一个新的 v 值,这样用户的浏览器就可以自动获取新文件。如果文件的内容没有发生改变,浏览器会继续使用本地的缓存,不再更新服务上的文件。显著提高渲染性能。
    
    在生产中你可能希望为静态文件提供一个更优的静态文件服务器,如 nginx。
    
    你可以配置任何服务器去识别 static_url() 所使用的版本号,并且设置相应的缓存头。如下是我们在 FriendFeed 中使用的 nginx 配置。
    
    location /static/ {
        root /var/friendfeed/static;
        if ($query_string) {
            expires max;
        }
     }
    

    Debug mode and automatic reloading

    如果将 debug=True 传递给 Application 构造函数,应用将会运行在调试/开发模式。
    
    这种模式下。一些方便用于开发的功能将开启。
    
    • autoreload=True
    应用将会监视他的源文件,一旦文件发生改变,将重新加载。这减少了在开发过程中手动重启的服务的次数。
    
    然而,一些错误(如语法错误)也可以使服务器挂掉导致无法恢复。
    
    • compiled_template_cache=False
    Templates 不缓存
    
    • static_hash_cache=False
    静态文件序列化不再缓存
    
    • serve_traceback=True
    当 RequestHandler 没有捕捉到异常时,将生成一个包含堆栈跟踪的错误页面。
    
    Autoreload 模式不兼容多进程模式的 HTTPServer。
    
    调试模式下的自动重载特性在 tornado.autoreload 模块中独立实现。
    
    这两个结合使用可以提供额外的健壮性对抗语法错误:
    
    1、设置 sutoreload=True 在运行时检测变化
    
    2、使用 python -m tornado.autoreload myser.py 在启动时捕捉语法或其他错误。
    
    重载会丢失 python 解释器的命令行参数,因为他使用 sys.executable 和 sys.argv 重新执行 python。除此之外,修改这些变量将导致重载行为错误。
    
    在一些平台上(Windows 和 Mac 10.6之前),进程不能直接更新,所以当检测到代码更新的时候,旧的服务退出,然后重启一个新的。
    

    WSGI and Google App Engine

    tornado 通常自己就运行而不需要一个 WSGI 容器。然而,在某些环境中(如Google App Enging),只有 WSGI 被允许,应用不能运行在自己的服务上。在这种情况下,tornado 允许一个受限制的操作模式,不支持异步操作,但是允许一系列 tornado 功能在 WSGI-only 环境。
    
    在 WSGI 模式下,协程, @asynchronous 装饰器, AsyncHTTPClient, auth, WebSockets 特征不被允许,
    
    你可以使用 tornado.wsgi.WSGIAdapter 将 tornado 应用转换成 WSGI 应用。这种情况下,配置好 WSGI 容器去找到应用对象。
    
    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)
    

    上一篇: 2.6、User’s guide (Authentication and security)

    相关文章

      网友评论

          本文标题:2.7、User’s guide (Running and de

          本文链接:https://www.haomeiwen.com/subject/xwivcftx.html