tornado是有它自己的HTTP服務(wù)器的
一般情況
def main():
app = make_app()
app.listen(8888)
IOLoop.current().start()
if __name__ == '__main__':
main()
需要 改變可以同時(shí)打開的文件數(shù)量,通過/etc/security/limits.conf或者supvisor的minfds設(shè)置榛丢。
啟動(dòng)多個(gè)進(jìn)程
def main():
app = make_app()
server = tornado.httpserver.HTTPServer(app)
server.bind(8888)
server.start(0) # 有幾個(gè)CPU啟動(dòng)幾個(gè) 共享一個(gè)端口
IOLoop.current().start()
限制問題是每個(gè)進(jìn)程是有自己的IOloop,不能動(dòng)全局的IOloop坑填;無法做不停機(jī)更新;因?yàn)槎急O(jiān)聽一個(gè)端口沒法有效控制。
最好是分開啟動(dòng)它們氧秘,每個(gè)監(jiān)聽不同的端口,可以使用supvisor的process groups概念趴久。當(dāng)每個(gè)進(jìn)程監(jiān)聽不同端口時(shí)丸相,可以使用負(fù)載均衡例如HAProxy或nginx來分發(fā)。
在負(fù)載均衡之后
可以在初始化HTTPServer時(shí)傳入xheaders=True來告訴tornado使用X-Real-IP來獲得用戶的IP地址而不是負(fù)載均衡的IP彼棍。
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;
}
}
}
靜態(tài)文件部署
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開頭的訪問都會(huì)到static dir中去灭忠。包括robots.txt和favicon.ico。
<html>
<head>
<title>FriendFeed - {{ _("Home") }}</title>
</head>
<body>
<div>![]({{ static_url()</div>
</body>
</html>
使用static_url的url是/static/images/logo.png?v=aae54會(huì)包含一個(gè)該文件的hash值座硕,這樣在圖片未改變之前都會(huì)cache弛作。
使用nginx來提供靜態(tài)文件:
location /static/ {
root /var/friendfeed/static;
if ($query_string) {
expires max;
}
}
debug和自動(dòng)重載
啟用了debug后
autoreload=True 監(jiān)聽文件變化并自動(dòng)reload 使用了該設(shè)置則不能用多進(jìn)程
compiled_template_cache=False: Templates will not be cached.
static_hash_cache=False: Static file hashes (used by the static_url function) will not be cached
serve_traceback=True: When an exception in a is not caught, an error page including a stack trace will be generated.
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)