$request_time是 nginx收到第一个字节 到 nginx把全部响应内容放到tcp 发送缓冲区的时间。nginx
很长一段时间,我都以为上面的说法是正确的。git
直到前两天跟同事探讨$request_time,才发现并不彻底正确,才把之前的一些疑问解释了,以为挺有意义,这里记录一下。github
Nginx文档对于$request_time的定义以下:socket
request processing time in seconds with a milliseconds resolution; time elapsed since the first bytes were read from the clienttcp
文档只介绍了什么时候开始计算request_time,没有说什么时候结束。svg
对于开启长链接的请求处理,上面的说法是彻底正确的。优化
可是对于短链接的呢?ui
大概是16年初,曾经某水果台曾使用咱们公司CDN。客户使用几家CDN,对比发现咱们的CDN慢速请求(byte_sent/request_time)数较多。atom
讲道理的话,这时候应该优化了。固然首先想到的确定是sndbuf,恩,其实不少公司也确实是这么作的。
把sndbuf调整到2M, 果真排名靠前了很多。
这时候售前同窗就统计了,说Http 1.0的慢速请求数仍是不少。
sndbuf还区分协议的?
显然,http1.0和http1.1的一个主要区别就是http1.0默认是关闭长链接的。
查了下代码,发现 ngx_http_finalize_connection
中对因而否开启长链接,走了两种不一样的路径。
显然,开启了keep_alive,会走ngx_http_set_keepalive分支;可是,如若不开启,keepalive则有两种可能:
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的处理后有所改变,代码以下:
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
。
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错误.