>  기사  >  백엔드 개발  >  Python 웹 프레임워크 Tornado 운영 및 배포에 대한 자세한 소개

Python 웹 프레임워크 Tornado 운영 및 배포에 대한 자세한 소개

高洛峰
高洛峰원래의
2017-03-06 13:54:351652검색

본 글의 예시는 참고용으로 Python 웹 프레임워크 Tornado의 운영 및 배포에 대한 세부 내용을 공유하고 있습니다.

1. 🎜>
Tornado에는 자체 HTTPServer가 내장되어 있으므로 이를 실행하고 배포하는 것은 다른 Python 웹 프레임워크와 동일하지 않습니다. 애플리케이션을 실행하기 위해 WSGI 컨테이너를 구성하는 대신 서비스를 시작하기 위한 main() 함수를 작성해야 합니다.

def main():
  app = make_app()
  app.listen(8888)
  IOLoop.current().start()

if __name__ == '__main__':
  main()

운영 체제 또는 프로세스 구성 관리자는 이 프로그램을 실행하여 서비스를 시작합니다. "열린 파일이 너무 많습니다" 오류를 방지하기 위해 프로세스당 열 수 있는 최대 파일 핸들 수를 늘려야 할 수도 있습니다. 이 제한을 늘리려면(예: 50000) ulimit 명령을 사용하거나 /etc/security/limits.conf를 수정하거나 Supervisord 구성에서 minfds를 설정할 수 있습니다.

2. 프로세스 및 포트 Python의 GIL(Global Interpreter Lock)로 인해 다중 CPU 시스템을 최대한 활용하려면 여러 Python 프로세스를 실행해야 합니다. . 일반적으로 CPU당 하나의 프로세스를 실행하는 것이 가장 좋습니다.

Tornado에는 한 번에 여러 프로세스를 시작할 수 있는 다중 프로세스 모드가 내장되어 있으며, 이를 위해서는 기본 기능에 약간의 변경이 필요합니다.

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이 있으므로 분기하기 전에 전역 IOLoop 인스턴스를 건드리지 않는 것이 중요합니다(간접적으로라도). 둘째, 이 모델에서는 가동 중지 시간 없는 업데이트를 달성하기가 어렵습니다. 마지막으로 모든 프로세스가 동일한 포트를 공유하기 때문에 개별적으로 모니터링하기가 더 어렵습니다.

더 복잡한 배포의 경우 독립적인 프로세스를 시작하고 서로 다른 포트를 수신하도록 하는 것이 좋습니다. 각 프로세스가 다른 포트를 사용하는 경우 HAProxy 또는 nginx와 같은 외부 로드 밸런서는 일반적으로 아웃바운드 방문자에게 단일 주소를 제공해야 합니다.

3. 로드 밸런서 뒤에서 실행 nginx와 같은 로드 밸런서 뒤에서 실행하는 경우 xheaders=True를 HTTPServer 생성자에 전달하는 것이 좋습니다. 이는 모든 트래픽이 로드 밸런서의 IP 주소에서 온다고 가정하는 대신 X-Real-IP와 같은 HTTP 헤더를 사용하여 사용자의 IP 주소를 가져오도록 Tornado에 지시합니다.

이 파일은 FriendFeed에서 사용하는 구성과 구조가 유사한 원본 nginx 구성 파일입니다. 이는 nginx와 Tornado 서버가 동일한 시스템에서 실행되고 있고 4개의 Tornado 서버가 포트 8000 - 8003에서 실행되고 있다고 가정합니다.

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;
    }
  }
}

4. 정적 파일 및 파일 캐싱 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/으로 시작하는 모든 요청을 자동으로 정적 디렉터리로 라우팅합니다. 예를 들어 http://www.php.cn/:8888/static/foo.png는 지정된 정적 디렉터리 png 파일을 통해 foo를 제공합니다. 또한 정적 디렉터리에서 /robots.txt 및 /favicon.ico를 자동으로 제공합니다(단, /static/ 접두사로 시작하지 않음).

위 설정에서는 파일이 정적 파일 디렉터리에 있더라도 StaticFileHandler 루트에서 apple-touch-icon.png 파일을 가져오도록 Tornado를 명시적으로 구성했습니다. (정규식 캡처 그룹은 요청된 파일 이름을 StaticFileHandler에 알려야 하며 캡처 그룹을 호출하면 파일 이름이 메서드에 대한 인수로 처리기에 전달됩니다.) 다음에서 sitemap.xml 파일을 제공하는 것과 같은 동일한 작업을 수행할 수 있습니다. 웹사이트의 루트. 물론 HTML에서 439940bdb518e9fd892bed955b59e35a 태그를 사용하여 루트의 apple-touch-icon.png를 위조하는 것을 방지할 수도 있습니다.

성능을 향상하려면 브라우저가 페이지를 렌더링할 때 차단할 수 있는 불필요한 If-Modified-Since 또는 Etag 요청을 보내지 않도록 브라우저가 정적 리소스를 적극적으로 캐시하도록 하는 것이 좋습니다. Tornado는 이 기능을 지원하기 위해 정적 콘텐츠 버전 관리를 사용합니다.

이러한 기능을 사용하려면 HTML에 정적 파일의 URL을 직접 입력하는 대신 템플릿에서 static_url 메소드를 사용하세요.

<html>
  <head>
    <title>FriendFeed - {{ _("Home") }}</title>
  </head>
  <body>
    <p><img src="{{ static_url("images/logo.png") }}"/></p>
  </body>
</html>

static_url() 함수는 상대 경로를 /static/images/logo.png?v=aae54와 유사한 URI로 변환합니다. v 매개변수는 logo.png 콘텐츠의 해시이며 그 존재로 인해 Tornado 서비스가 사용자의 브라우저에 캐시 헤더를 보내면 브라우저가 콘텐츠를 무기한으로 캐시하게 됩니다.

v 매개변수는 파일 내용을 기반으로 하기 때문에 파일을 업데이트하고 서비스를 다시 시작하면 새로운 v 값이 전송되므로 사용자의 브라우저가 자동으로 새 파일을 가져옵니다. 파일 내용이 변경되지 않은 경우 브라우저는 서버의 업데이트를 확인하지 않고 로컬로 캐시된 복사본을 계속 사용하므로 렌더링 성능이 크게 향상됩니다.

프로덕션에서는 nginx와 같은 더 나은 정적 서버를 통해 정적 파일을 제공할 수 있습니다. static_url()을 통해 제공된 버전 태그를 인식하고 이에 따라 캐시 헤더를 설정하도록 웹 서버를 구성할 수 있습니다. 다음은 FriendFeed에서 사용하는 nginx 관련 구성의 일부입니다:

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

五、Debug模式和自动重载
如果传递 debug=True 配置给 Application 的构造函数,应用程序将会运行在debug/开发模式。 在这个模式下,为了方便于开发的一些功能将被启用( 每一个也可以作为独立的标签使用,如果它们都被专门指定,那它们都将获得独立的优先级):

1、autoreload=True: 应用程序将会观察它的源文件是否改变,并且当任何文件改变的时候便重载它自己。这减少了在开发中需要手动重启服务的需求。然而,在debug模式下,某些错误(例如import的时候有语法错误)会导致服务 关闭,并且无法自动恢复。
2、compiled_template_cache=False: 模板将不会被缓存。
3、static_hash_cache=False: 静态文件哈希 (被 static_url 函数使用) 将不会被缓存。
4、serve_traceback=True: 当一个异常在 RequestHandler 中没有捕获,将会生成一个包含调用栈信息的错误页。
自动重载(autoreload)模式和 HTTPServer 的多进程模式不兼容,你不能给 HTTPServer.start 传递 1 以外的参数(或者调用 tornado.process.fork_processes) 当你使用自动重载模式的时候。

debug模式的自动重载功能可作为一个独立的模块位于 tornado.autoreload。以下两者可以结合使用,在语法错误之时提供额外的健壮性: 设置 autoreload=True 可以在app运行时检测文件修改,还有启动 python -m tornado.autoreload myserver.py 来捕获任意语法错误或者其他的启动时错误。

重载会丢失任何Python解释器命令行参数(-u). 因为它使用 sys.executable 和 sys.argv 重新执行Python。此外,修改这些变量将造成重载错误。

在一些平台(包括Windows 和Mac OSX 10.6之前),进程不能被“原地”更新,所以当检测到代码更新,旧服务就会退出然后启动一个新服务。这已经被公知来混淆一些IDE。

六、WSGI和Google App Engine
Tornado通常是独立运行的,不需要一个WSGI容器。然而,在一些环境中 (例如Google App Engine),只运行WSGI,应用程序不能独立运行自己的服务。在这种情况下,Tornado支持一个有限制的操作模式,不支持异步操作但允许一个Tornado's功能的子集在仅WSGI环境中。以下功能在WSGI模式下是不支持的,包括协程,@asynchronous 装饰器,AsyncHTTPClient,auth 模块和WebSockets。

你可以使用 tornado.wsgi.WSGIAdapter 把一个Tornado Application 转换成WSGI应用。在这个例子中, 配置你的WSGI容器发 现 application 对象:

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)

以上就是本文的全部内容,希望对大家的学习有所帮助。

更多PythonWeb框架Tornado运行和部署详细介绍相关文章请关注PHP中文网!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.