找到归档 2013-03 的文章 4 篇.


tornado长连接断开的处理机制

Posted on 2013-03-08 20:18:01 tornado

摘要:

使用tornado的异步http调用时候,在继续RequestHandler的子类中,可以重载on_connection_close方法。 此方法在对端连接关闭,或者在socket上读写错误的时候被调用,可以让服务器做一些清理。

阅读全文

关于HTTP长连接的保持和断开

Posted on 2013-03-07 19:03:17 network

最近在折腾一个长连接HTTP服务器的时候,积累了一些经验,下面总结出来:

  1. 最好使用支持HTTP/1.1的服务器,HTTP/1.1默认支持keep-alive,不需要像HTTP/1.0那样检测Connection: keep-alive.

  2. 浏览器的刷新也会断开长连接,如果在服务端有一些判断,要注意发生重复的可能。

  3. 在用户关闭浏览器的标签的时候,如果有多个页面和服务器保持长连接,服务器应检测对应的页面,并做清理。

  4. 将长连接服务器位于反向代理之后,应在反向代理服务器上设置保持keep-alive,如nginx。 这样可显著减少后端upstream服务器的压力。

  5. 检测用户刷新页面,如果刷新应询问用户是否真的刷新。这样可以减少一些误判断。 如WEBQQ在检测到用户刷新时,对应的动作是重新登录。 这样做是很好,可以预防用户在当前页面重复触发一些业务逻辑。

  6. 如因为业务需要将长连接和会话绑定(很多WEB IM都这样做),应注意清理服务端保持的长连接。 发送完消息,就应该删除这个长连接。因为浏览器ajax请求还会立即请求的。


Nginx对后端upstream server启用keepalive

Posted on 2013-03-06 19:49:00 os

Nginx upstream目前只有短连接,通过HTTP/1.0向后端发起连接,并把请求的”Connection” header设为”close”。Nginx与前端的连接默认为长连接,一个用户跟Nginx建立连接之后,通过这个长连接发送多个请求。如果Nginx只是作为reverse proxy的话,可能一个用户连接就需要多个向后端的短连接。如果后端的服务器(源站或是缓存服务器)处理并发连接能力不强的话(比如单进程的squid),就可能导致瓶颈的出现。

从nginx 1.1.4 开始有了原生的ngx_http_upstream_keepalive 模块 和”proxy_http_version” fastcgi_keep_conn” 等指令 ,所以后端的keepalive也在nginx 1.2.0成为现实。

HTTP 1.0实现长连接需要设置请求头部Connection: keep-alive。 但是在HTTP 1.1 中已经不需要了。 所以在nginx中这样配置:

upstream http_backend {
    server 127.0.0.1:8080;
 
    keepalive 16;
}
 
server {
    ...
 
    location /http/ {
        proxy_pass http://http_backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        ...
    }
}

tornado中计算etag的一个BUG

Posted on 2013-03-06 15:16:21 tornado

在tornado中是根据send buffer中的内容计算etag的,而这样对于一些只判断逻辑的页面会有问题。

计算etag的代码如下:

def compute_etag(self):
    """Computes the etag header to be used for this request.

    May be overridden to provide custom etag implementations,
    or may return None to disable tornado's default etag support.
    """
    hasher = hashlib.sha1()
    for part in self._write_buffer:
        hasher.update(part)
    return '"%s"' % hasher.hexdigest()

可以很清楚的看到,是根据self._writer_buffer中的内容计算etag,然后返回。

但是如果遇到下面的代码会出现问题:

def post(self):
    username = self.get_argument("username")
    if not redis.UserManager.is_user_exists(username):
        self.set_secure_cookie("user", username)
        self.redirect("/room", status=301)
        return
    else:
        self.render("login.html", user_exists=True)

这段代码中,返回的内容永远不会有变化。 所以客户端判断返回为304,导致出现问题。 解决方法是禁用etag。解决方法很简单,只要重载compute_etag方法,并返回None即可。 并且建议,对于所有动态页面,不用计算etag的方法,这样可以让客户端永远获取最新的内容。 如果真的要客户端缓存页面,可以用Cache-Control,设置有效期,这样比较合理。