Heim  >  Artikel  >  Backend-Entwicklung  >  Detaillierte Einführung in den Betrieb und die Bereitstellung des Python-Web-Frameworks Tornado

Detaillierte Einführung in den Betrieb und die Bereitstellung des Python-Web-Frameworks Tornado

高洛峰
高洛峰Original
2017-03-06 13:54:351705Durchsuche

Das Beispiel in diesem Artikel enthält die Details zum Betrieb und zur Bereitstellung des Python-Web-Frameworks Tornado. Der spezifische Inhalt lautet wie folgt:

1 🎜>
Da Tornado über einen eigenen HTTP-Server verfügt, ist die Ausführung und Bereitstellung nicht dasselbe wie bei anderen Python-Web-Frameworks. Anstatt einen WSGI-Container zum Ausführen Ihrer Anwendung zu konfigurieren, müssen Sie eine main()-Funktion schreiben, um den Dienst zu starten:

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

if __name__ == '__main__':
  main()

Konfigurieren Sie Ihr Betriebssystem Oder Prozessmanager, um dieses Programm auszuführen, um den Dienst zu starten. Beachten Sie, dass es möglicherweise erforderlich ist, die maximale Anzahl der pro Prozess geöffneten Dateihandles zu erhöhen (um „Zu viele geöffnete Dateien“-Fehler zu vermeiden). Um dieses Limit zu erhöhen (z. B. auf 50000), können Sie den Befehl ulimit verwenden, /etc/security/limits.conf ändern oder minfds in Ihrer Supervisord-Konfiguration festlegen.

2. Prozesse und Ports Aufgrund von Pythons GIL (Global Interpreter Lock) ist es zur vollständigen Nutzung von Multi-CPU-Maschinen notwendig, mehrere Python-Prozesse auszuführen . Im Allgemeinen ist es am besten, einen Prozess pro CPU auszuführen.

Tornado verfügt über einen integrierten Multiprozessmodus zum gleichzeitigen Starten mehrerer Prozesse, was eine geringfügige Änderung der Hauptfunktion erfordert:

def main():
  app = make_app()
  server = tornado.httpserver.HTTPServer(app)
  server.bind(8888)
  server.start(0) # forks one process per cpu
  IOLoop.current().start()

Dies ist der einfachste Weg, mehrere Prozesse zu starten und sie denselben Port gemeinsam nutzen zu lassen, obwohl es einige Einschränkungen gibt. Erstens verfügt jeder untergeordnete Prozess über seinen eigenen IOLoop. Daher ist es wichtig, die globale IOLoop-Instanz vor dem Forken nicht zu berühren (auch nicht indirekt). Zweitens ist es bei diesem Modell schwierig, Updates ohne Ausfallzeiten zu erreichen. Da schließlich alle Prozesse denselben Port verwenden, ist es schwieriger, sie einzeln zu überwachen.

Für komplexere Bereitstellungen empfiehlt es sich, unabhängige Prozesse zu starten und diese auf verschiedene Ports hören zu lassen. Die Funktion „Prozessgruppen“ von supervisord ist eine gute Möglichkeit. Wenn jeder Prozess einen anderen Port verwendet, muss ein externer Load Balancer wie HAProxy oder Nginx ausgehenden Besuchern normalerweise eine einzige Adresse bereitstellen.

3. Ausführung hinter einem Load Balancer Bei Ausführung hinter einem Load Balancer wie Nginx wird empfohlen, xheaders=True an den Konstruktor von HTTPServer zu übergeben. Dadurch wird Tornado angewiesen, HTTP-Header wie X-Real-IP zu verwenden, um die IP-Adresse des Benutzers zu erhalten, anstatt davon auszugehen, dass der gesamte Datenverkehr von der IP-Adresse des Load Balancers kommt.

Dies ist eine Original-Nginx-Konfigurationsdatei, deren Struktur der Konfiguration ähnelt, die wir bei FriendFeed verwenden. Dies setzt voraus, dass Nginx und der Tornado-Server auf demselben Computer ausgeführt werden und dass vier Tornado-Server auf den Ports 8000 – 8003 ausgeführt werden:

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. Statische Dateien und Datei-Caching In Tornado können Sie statische Dateidienste bereitstellen, indem Sie einen speziellen static_path in der Anwendung angeben:

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)

Diese Einstellungen übertragen automatisch alle Anfragen, die mit /static/ beginnen, in das statische Verzeichnis. Beispielsweise wird http://www.php.cn/:8888/static/foo.png das angegebene statische Verzeichnis übergeben, das foo bereitstellt. PNG-Datei. Wir stellen auch /robots.txt und /favicon.ico automatisch aus dem statischen Verzeichnis bereit (obwohl sie nicht mit dem Präfix /static/ beginnen).

In den obigen Einstellungen konfigurieren wir Tornado explizit so, dass die Datei apple-touch-icon.png vom StaticFileHandler-Stammverzeichnis abgerufen wird, obwohl sich die Datei im statischen Dateiverzeichnis befindet. (Die Regex-Erfassungsgruppe muss dem StaticFileHandler den angeforderten Dateinamen mitteilen, und der Aufruf der Erfassungsgruppe übergibt den Dateinamen als Argument an die Methode an den Handler.) Sie können das Gleiche tun, z. B. die Bereitstellung einer sitemap.xml-Datei von das Stammverzeichnis der Website. Natürlich können Sie auch verhindern, dass die Datei „apple-touch-icon.png“ des Stammverzeichnisses gefälscht wird, indem Sie das 439940bdb518e9fd892bed955b59e35a-Tag in Ihrem HTML verwenden.

Um die Leistung zu verbessern, ist es oft eine gute Idee, den Browser aktiv statische Ressourcen zwischenspeichern zu lassen, damit der Browser keine unnötigen If-Modified-Since- oder Etag-Anfragen sendet, die beim Rendern der Seite blockieren könnten. Tornado verwendet statische Inhaltsversionierung, um diese Funktion zu unterstützen.

Um diese Funktionen zu nutzen, verwenden Sie die Methode static_url in Ihrer Vorlage, anstatt die URL der statischen Datei direkt in Ihren HTML-Code einzugeben:

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

Die Funktion

static_url() übersetzt den relativen Pfad in einen URI ähnlich wie /static/images/logo.png?v=aae54. Der v-Parameter ist der Hash des logo.png-Inhalts und verursacht den Der Tornado-Dienst sendet Cache-Header an den Browser des Benutzers, was dazu führt, dass der Browser den Inhalt auf unbestimmte Zeit zwischenspeichert.

Da der Parameter v auf dem Dateiinhalt basiert, sendet er beim Aktualisieren einer Datei und Neustarten des Dienstes einen neuen v-Wert, sodass der Browser des Benutzers automatisch die neue Datei abruft. Wenn sich der Inhalt der Datei nicht geändert hat, verwendet der Browser weiterhin die lokal zwischengespeicherte Kopie, ohne nach Updates vom Server zu suchen, wodurch die Rendering-Leistung erheblich verbessert wird.

In der Produktion möchten Sie möglicherweise statische Dateien über einen besseren statischen Server wie nginx bereitstellen. Sie können jeden Webserver so konfigurieren, dass er das über static_url() bereitgestellte Versions-Tag erkennt und den Cache-Header entsprechend festlegt. Das Folgende ist Teil der Nginx-bezogenen Konfiguration, die wir in FriendFeed verwenden:

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中文网!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn