Python WebフレームTornado動作と展開


本論文の例では、Python WebフレームワークTornadoの運営と展開の詳細を共有しています。参考にしてください。具体的な内容は以下の通りです。
一、運行と配置
Tornadoは自分のHTTPServerを内蔵しているので、他のPythonのwebフレームとは違って運行と展開ができます。あなたはWSGI容器を配置してあなたのアプリケーションを実行する代わりに、メーン関数を書いてサービスを開始する必要があります。

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

if __name__ == '__main__':
 main()
あなたのオペレーティングシステムまたはプロセスマネージャを設定して、このプログラムを実行してサービスを開始します。各プロセスによって開くことができる最大のファイルのハンドル数を増やすことが必要です(「Too many open files」のエラーを避けるために)。この上限を増やすためには、例えば50000に設定してください。ulimitコマンドを使用して、修正/etc/security/limits.com fまたはminfdsをsupervisordの配置に設定してください。
二、プロセスとポート
PythonのGIL(大域分解器錠)は、マルチCPUのマシンをフルに利用するために、複数のPythonプロセスを実行する必要があります。通常は、各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のインスタンスに触れないことが重要です。第二に、このモデルでは、ゼロシャットダウンの更新は難しい。最後に、すべてのプロセスが同じポートを共有しているので、単独で監視するのはもっと難しいです。
より複雑な配置に対しては、独立したプロセスを起動し、それぞれ異なるポートを傍受することを提案します。supervisordの「プロセスグループ」機能は素晴らしい方法です。プロセスごとに異なるポートを使用する場合、外部負荷イコライザ、例えばHAProxyまたはnginxは通常、ゲストに単一のアドレスを提供する必要がある。
三、負荷イコライザの後ろで運転する
負荷イコライザなどで動作する場合は、HTTPServerの構築器にxheaders=Trueを送ることを推奨します。これは、すべての流量を負荷分散器からのIPアドレスではなく、ユーザのIPアドレスを取得するために、X−REAL−IPのようなHTTPヘッダを使用するというTornadoに通知するであろう。
これはオリジナルのnginxプロファイルで、構造的にはFriendFeedで使用されている構成に似ています。これは、nginxとTornado serverが同じマシンで動作し、4つのTornado serverが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;
  }
 }
}
四、静的ファイルとファイルキャッシュ
Tornadoでは、アプリケーションで特殊なstatic_を指定することができます。パスは、静的ファイルサービスを提供します。

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/先頭の要求をstaticディレクトリに渡します。例えば、http://localhost:8888/static/foo.png 指定されたstaticディレクトリを通じてfoo.pngファイルを提供します。私たちも自動的にstaticディレクトリから/robots.txtと/favicon.icoを提供します。
上記の設定では、Static FileHandlerのもとからapple-touch-incon.pngファイルを明確に構成しています。ファイルはstaticファイルディレクトリにありますが。正規表現キャプチャグループは、Static FileHandler要求のファイル名を通知し、Trapグループを呼び出してファイル名を方法としてパラメータを処理プログラムに渡すことができます。ウェブサイトのルートからsitemap.xmlファイルを提供するなど、同じことができます。もちろん、あなたはあなたのHTMLにタグを使うことによって、ルートディレクトリのapple-touch-con.pngを偽造することを避けることもできます。
性能を改善するためには、通常、ブラウザに静的リソースをアクティブにキャッシュさせるのがいい考えです。このようにブラウザは、不必要なページをレンダリングする際に詰まる可能性のあるIf-Maodifed-SinceまたはEd要求を送信しないようにします。Tornadoは静的なコンテンツバージョンを使用して、この機能をサポートします。
これらの機能を使うために、あなたのテンプレートにstatic_を使います。urlメソッドではなく、直接あなたのHTMLに静止ファイルのURLを入力します。

<html>
 <head>
  <title>FriendFeed - {{ _("Home") }}</title>
 </head>
 <body>
  <div><img src="{{ static_url("images/logo.png") }}"/></div>
 </body>
</html>
static.url()関数は相対パスを一つのURIに変換し、Tornadoサービスがユーザのブラウザにキャッシュヘッダを送信するようにしています。これはブラウザに無期限のキャッシュコンテンツを提供します。
パラメータvはファイルの内容に基づいていますので、ファイルを更新してサービスを再開すると、新しいv値を送信しますので、ユーザのブラウザは自動的に新しいファイルを引っ張ります。ファイルの内容が変更されていない場合、ブラウザは引き続きローカルキャッシュのコピーを使用し、サーバーから更新を確認することなく、レンダリング性能を著しく向上させます。
生産では、静的なファイルを提供したいかもしれません。例えば、nginxなどのより優れた静的なサーバを通じて、どのウェブサーバを構成しても、static_を介して識別できます。url()が提供するバージョンラベルに対応して、キャッシュヘッダを設定します。以下は私達がFriendFeedで使っているnginx関連の構成の一部です。

location /static/ {
 root /var/friendfeed/static;
 if ($query_string) {
  expires max;
 }
 }
五、Debugモードと自動リロード
debug=TrueをAplicationの構築関数に設定すると、アプリケーションはdebug/開発モードで実行されます。このモードでは、開発を容易にするためにいくつかの機能が有効になります。(それぞれは独立したラベルとしても使用できます。それらが特定されていれば、それぞれ独立した優先度が得られます。)
1、autreload=True:アプリケーションはそのソースファイルが変更されているかどうかを確認し、どのファイルが変更された時に、自分を積載します。これは、開発において、手動でサービスを再開する必要があるというニーズを低減しています。しかしながら、debugモードでは、いくつかのエラー(例えば、importの場合、シンタックスエラー)がサービスをクローズし、自動的に再開することができなくなります。
2、compled_template_cache=False:テンプレートはキャッシュされません。
3、static_hashcache=False:スタティック・ファイル・ハッシュurl関数を使用するとキャッシュされません。
4、serve_True:異常がRequest Handlerに捕捉されていない場合、スタック情報を呼び出すエラーページが生成されます。
自動リロードモードとHTTPServerのマルチプロセスモードは互換性がありません。HTTPServer.startに1以外のパラメータを渡すことはできません。processes)自動リロードモードを使うとき。
debugモードの自動リロード機能は、tonado.autreloadに独立したモジュールとして存在することができます。以下の2つの組み合わせは、構文エラー時に追加の壮健性を提供します。autreload=Trueを設定すると、app実行時にファイル修正を検出できます。また、python-m tonado.autreload myserver.pyを起動して、任意の構文エラーまたは他の起動時にエラーをキャプチャします。
再ロードは、任意のPython解釈器コマンドラインパラメータ(-u)を失います。sys.executableとsys.argvを使用してPythonを再実行します。また、これらの変数を変更すると、リロードエラーが発生します。
いくつかのプラットフォーム(WindowsとMac OSX 10.6を含む)では、プロセスは“元の場所”で更新されないので、コードの更新が検出されると、古いサービスは終了し、新しいサービスを開始します。これはいくつかのIDEを混同するために公知されている。
六、WSGIとGoogle App Engine
Tornadoは通常独立して運行しています。WSGI容器は必要ありません。しかし、いくつかの環境では、WSGIのみを実行しています。アプリケーションは独自のサービスを実行できません。この場合、Tornadoは、WSGI環境のみでTornado's機能のサブセットを許可する非同期動作モードをサポートしている。以下の機能はWSGIモードではサポートされていません。協程、@asynch ronous装飾器、Aync HTTPClient、authモジュールとWebSocketsを含みます。
tonado.wsgi.WSGIA dapterを使ってTornadoアプリをWSGIアプリケーションに変換できます。この例では、WSGI容器を配置してappicationオブジェクトを発見します。

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)
以上が本文の全部です。皆さんの勉強に役に立ちたいです。