nginx讲解之request_time 和upstream_response_time差别

来源:互联网 发布:div height javascript 编辑:程序博客网 时间:2024/06/04 20:01
1、request_time
官网描述:request processing time in seconds with a milliseconds resolution; time elapsed between the first bytes were read from the client and the log write after the last bytes were sent to the client 。
指的就是从接受用户请求的第一个字节到发送完响应数据的时间,即包括接收请求数据时间、程序响应时间、输出响应数据时间。

2、upstream_response_time
官网描述:keeps times of responses obtained from upstream servers; times are kept in seconds with a milliseconds resolution. Several response times are separated by commas and colons like addresses in the $upstream_addr variable
是指从Nginx向后端(php-cgi)建立连接开始到接受完数据然后关闭连接为止的时间。
从上面的描述可以看出,$request_time肯定比$upstream_response_time值大,特别是使用POST方式传递参数时,因为Nginx会把request body缓存住,接受完毕后才会把数据一起发给后端。所以如果用户网络较差,或者传递数据较大时,$request_time会比$upstream_response_time大很多。
所以如果使用nginx的accesslog查看php程序中哪些接口比较慢的话,记得在log_format中加入$upstream_response_time。

现对request_time进一步理解如下:
对于开启长连接的请求处理,上面的说法是完全正确的。
但是对于短连接的呢?
在使用http1.0和http1.1时主要如下区别就是http1.0默认是关闭长连接的,而http1.1是默认长连接的。
查了下代码,发现 ngx_http_finalize_connection中对于是否开启长连接,走了两种不同的路径。
显然,开启了keep_alive,会走ngx_http_set_keepalive分支;但是,如若不开启keepalive则有两种可能:
1、ngx_http_close_request;
2、ngx_http_set_lingering_close; 显然调用lingering_close的话,会导致打印日志的时间推迟;
    if (!ngx_terminate
         && !ngx_exiting
         && r->keepalive
         && clcf->keepalive_timeout > 0)
    {
        ngx_http_set_keepalive(r);
        return;
    }


    if (clcf->lingering_close == NGX_HTTP_LINGERING_ALWAYS
        || (clcf->lingering_close == NGX_HTTP_LINGERING_ON
            && (r->lingering_close
                || r->header_in->pos < r->header_in->last
                || r->connection->read->ready)))
    {
        ngx_http_set_lingering_close(r);
        return;
    }
    ngx_http_close_request(r, 0);


Nginx对于epoll采用的是NGX_USE_GREEDY_EVENT策略(The event filter requires to do i/o operation until EAGAIN: epoll.)。
这种策略导致,在调用ngx_http_finalize_connection时,read->ready一直为1,从而调用ngx_http_set_lingering_close关闭连接。
但是这个问题在1.11.13版本,nginx引入epoll对于EPOLL_RDHUP的处理后有所改变,代码如下:
nginx diff
        if (n == 0) { //读取到的字节数为0,表示对端关闭连接
            rev->ready = 0;
            rev->eof = 1;
            return 0;
        }
        if (n > 0) {
#if (NGX_HAVE_EPOLLRDHUP)
            if ((ngx_event_flags & NGX_USE_EPOLL_EVENT)
                && ngx_use_epoll_rdhup)
            {
                if ((size_t) n < size) {
                    if (!rev->pending_eof) {
                        rev->ready = 0;
                    }
                    rev->available = 0;
                }
                return n;
            }
#endif
            if ((size_t) n < size
                && !(ngx_event_flags & NGX_USE_GREEDY_EVENT)) 
            {
                rev->ready = 0;
            }
            return n;
        }
        err = ngx_socket_errno;
        if (err == NGX_EAGAIN || err == NGX_EINTR) {
            ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
                           "recv() not ready");
            n = NGX_AGAIN;
        } else {
            n = ngx_connection_error(c, err, "recv() failed");
            break;
        }

所以对于nginx 1.11.13之后的版本,无论是否开启keepalive上述的结论仍然是正确的。

对于之前版本,如果想避免lingering_close,可以在配置项中lingering_close off。

TCP Socket对于linger close的支持

close(l_onoff=0缺省状态):在套接口上不能在发出发送或接收请求;套接口发送缓冲区中的内容被发送到对端.如果描述字引用计数变为0;在发送完发送缓冲区中的数据后,跟以正常的TCP连接终止序列(发送FIN);套接口接受缓冲区中内容被丢弃
close(l_onoff = 1, l_linger =0):在套接口上不能再发出发送或接受请求,如果描述子引用计数变为0,RST被发送到对端;连接的状态被置为CLOSED(没有TIME_WAIT状态),套接口发送缓冲区和套接口接受缓冲区的数据被丢弃
close(l_onoff =1, l_linger != 0):在套接口上不能在发出发送或接收请求;套接口发送缓冲区中的内容被发送到对端.如果描述字引用计数变为0;在发送完发送缓冲区中的数据后,跟以正常的TCP连接终止序列(发送FIN);套接口接受缓冲区中内容被丢弃;如果在连接变成CLOSED状态前延滞时间到,那么close返回EWOULDBLOCK错误.


原创粉丝点击