Maison > développement back-end > Tutoriel Python > Introduction détaillée au fonctionnement et au déploiement du framework Web Python Tornado

Introduction détaillée au fonctionnement et au déploiement du framework Web Python Tornado

高洛峰
Libérer: 2017-03-06 13:54:35
original
1711 Les gens l'ont consulté

L'exemple dans cet article partage les détails du fonctionnement et du déploiement du framework Web Python Tornado pour votre référence. Le contenu spécifique est le suivant

Opération et déploiement<.>
Parce que Tornado a son propre serveur HTTP intégré, son exécution et son déploiement ne sont pas les mêmes que les autres frameworks Web Python. Au lieu de configurer un conteneur WSGI pour exécuter votre application, vous devez écrire une fonction main() pour démarrer le service :

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

if __name__ == &#39;__main__&#39;:
  main()
Copier après la connexion

Configurez votre système d'exploitation Ou un gestionnaire de processus pour exécuter ce programme pour démarrer le service. Notez qu'il peut être nécessaire d'augmenter le nombre maximum de descripteurs de fichiers autorisés à être ouverts par processus (pour éviter les erreurs « Trop de fichiers ouverts »). Pour augmenter cette limite (par exemple à 50 000), vous pouvez utiliser la commande ulimit, modifier /etc/security/limits.conf ou définir minfds dans votre configuration superviseur.

2. Processus et ports En raison du GIL (Global Interpreter Lock) de Python, afin d'utiliser pleinement les machines multi-CPU, il est nécessaire d'exécuter plusieurs processus Python. . En général, il est préférable d'exécuter un processus par processeur.

Tornado inclut un mode multi-processus intégré pour démarrer plusieurs processus à la fois, ce qui nécessite une légère modification de la fonction principale :

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

C'est le moyen le plus simple de démarrer plusieurs processus et de les faire partager le même port, même s'il présente certaines limites. Premièrement, chaque processus enfant aura son propre IOLoop, il est donc important de ne pas toucher à l'instance globale d'IOLoop avant de bifurquer (même indirectement). Deuxièmement, dans ce modèle, il est difficile d’obtenir des mises à jour sans temps d’arrêt. Enfin, comme tous les processus partagent le même port, il est plus difficile de les surveiller individuellement.

Pour les déploiements plus complexes, il est recommandé de démarrer des processus indépendants et de les laisser écouter différents ports. La fonction "groupes de processus" de superviseur est un bon moyen. Lorsque chaque processus utilise un port différent, un équilibreur de charge externe tel que HAProxy ou nginx doit généralement fournir une adresse unique aux visiteurs sortants.

3. Exécuter derrière un équilibreur de charge Lors de l'exécution derrière un équilibreur de charge tel que nginx, il est recommandé de transmettre xheaders=True au constructeur de HTTPServer. Cela indiquera à Tornado d'utiliser des en-têtes HTTP tels que X-Real-IP pour obtenir l'adresse IP de l'utilisateur au lieu de supposer que tout le trafic provient de l'adresse IP de l'équilibreur de charge.

Il s'agit d'un fichier de configuration nginx original, de structure similaire à la configuration que nous utilisons chez FriendFeed. Cela suppose que nginx et le serveur Tornado s'exécutent sur la même machine et que quatre serveurs Tornado s'exécutent sur les ports 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;
    }
  }
}
Copier après la connexion

4. Fichiers statiques et mise en cache de fichiers Dans Tornado, vous pouvez fournir des services de fichiers statiques en spécifiant un chemin statique spécial dans l'application :

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[&#39;static_path&#39;])),
], **settings)
Copier après la connexion

Ces paramètres transféreront automatiquement toutes les requêtes commençant par /static/ vers le répertoire statique. Par exemple, http://www.php.cn/:8888/static/foo.png transmettra le répertoire statique spécifié fourni par foo. fichier png. Nous servons également automatiquement /robots.txt et /favicon.ico à partir du répertoire statique (bien qu'ils ne commencent pas par le préfixe /static/).

Dans les paramètres ci-dessus, nous configurons explicitement Tornado pour obtenir le fichier apple-touch-icon.png à partir de la racine StaticFileHandler, bien que le fichier se trouve dans le répertoire de fichiers statiques. (Le groupe de capture regex doit indiquer au StaticFileHandler le nom de fichier demandé, et l'appel du groupe de capture transmet le nom de fichier comme argument de méthode au gestionnaire.) Vous pouvez faire la même chose, par exemple servir un fichier sitemap.xml à partir de la racine du site web. Bien sûr, vous pouvez également éviter de falsifier le fichier apple-touch-icon.png de la racine en utilisant la balise

Pour améliorer les performances, il est souvent judicieux de laisser le navigateur mettre en cache activement les ressources statiques afin que le navigateur n'envoie pas de requêtes If-Modified-Since ou Etag inutiles qui pourraient bloquer lors du rendu de la page. Oui, Tornado utilise la gestion des versions de contenu statique pour prendre en charge cette fonctionnalité.

Pour utiliser ces fonctionnalités, utilisez la méthode static_url dans votre modèle au lieu de saisir l'URL du fichier statique directement dans votre HTML :

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

La fonction static_url() traduira le chemin relatif en un URI similaire à /static/images/logo.png?v=aae54. Le paramètre v est le hachage du contenu logo.png, et l'existence de provoque le problème. Service Tornado pour envoyer les en-têtes de cache au navigateur de l'utilisateur, ce qui amènera le navigateur à mettre le contenu en cache indéfiniment.

Étant donné que le paramètre v est basé sur le contenu du fichier, si vous mettez à jour un fichier et redémarrez le service, il enverra une nouvelle valeur v, de sorte que le navigateur de l'utilisateur extraira automatiquement le nouveau fichier. Si le contenu du fichier n'a pas changé, le navigateur continuera à utiliser la copie mise en cache localement sans vérifier les mises à jour du serveur, améliorant ainsi considérablement les performances de rendu.

En production, vous souhaiterez peut-être servir des fichiers statiques via un meilleur serveur statique, tel que nginx. Vous pouvez configurer n'importe quel serveur Web pour reconnaître la balise de version fournie via static_url() et définir l'en-tête du cache en conséquence. Ce qui suit fait partie de la configuration liée à Nginx que nous utilisons dans FriendFeed :

location /static/ {
  root /var/friendfeed/static;
  if ($query_string) {
    expires max;
  }
 }
Copier après la connexion

五、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)
Copier après la connexion

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

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

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal