【nginx】nginx与http网络特性

nginx与http网络特性(持续更新)

本文包括以下内容:
1、http保持长连接的keepalive做法,以及nginx的实现。
2、http长连接的另一种方式——pipeline以及实现。
3、lingering_close问题以及nginx的处理方案。

1、keepalive

1.1、http的长连接协议

(1)http1.0——不带content-length头域,直到服务端发送完响应数据且服务端主动断开连接,才表示body接收完了。
(2)http1.1——Transfer-encode头域为chunked
body会被分成多个块,每块的开始会标识出当前块的长度。
(3)connection头域:如果客户端的请求头中的connection为close,则表示客户端需要关掉长连接,如果为 keep-alive,则客户端需要打开长连接,如果客户端的请求中没有 connection 这个头,那么根据协议,如果是 http1.0,则默认为 close,如果是 http1.1,则默认为keep-alive。

1.2、nginx的做法

(1)nginx的长连接等待超时:
nginx根据客户端的connection头域来设置当前连接的keepalive属性,同时会设置一个等待长连接的超时时间keepalive_timeout(如果配置为0,则表示都强制close,不作任何等待)。
(2)keepalive属性的优点:
对于请求量比较大的nginx来说,关掉keepalive最后会产生比较多的time-wait状态的socket。一般来说,当客户端的一次访问,需要多次访问同一个server时,打开keepalive的优势非常大,比如图片服务器,通常一个网页会包含很多个图片。打开keepalive也会大量减少time-wait的数量。

2、pipeline

pipeline是一种基于长连接的特性,在http1.1中引入,可以看作是keepalive属性的升华。

2.1、和keepalive的区别

pipeline可以利用一个连接做多次请求,客户端不必等到第一个请求的响应就可以发起第二个请求。如果客户端要提交多个请求,对于keepalive来说,那么第二个请求,必须要等到第一个请求的响应接收完全后,才能发起,这和TCP的停止等待协议是一样的,得到两个响应的时间至少2*RTT。

2.2、nginx支持pipeline特性

nginx利用pipeline特性,减少了处理完一个请求后,等待第二个请求的请求到来的时间。其实nginx的做法很简单,nginx在读取数据时,会将读取的数据放到一个buffer里面,所以,如果nginx在处理完前一个请求后,如果发现buffer里面还有数据,就认为剩下的数据是下一个请求的开始,然后就接下来处理下一个请求,否则就设置keepalive。

3、lingering_close

类似于tcp套接字的SO_LINGER选项。避免连接关闭前,最后的数据的读写没有完成。

3.1、问题场景

(1)前置条件:服务端在处理客户端请求的时候,由于一些错误情况,需要响应错误信息给对端并关闭连接。但是write()系统调用返回成功并不表示数据已经发送到客户端,有可能还在内核写缓冲区里。
(2)我们先看没有设置lingering_close的行为:如果直接close()的话,内核会首先检查内核读缓存区里有没有客户端发送过来的数据留在内核态没有被用户态进程读取,如果有则发送给客户端RST报文来关闭tcp连接丢弃内核写缓冲区里的数据,如果没有则等待内核写缓冲区里的数据发送完毕,然后再经过正常的4次挥手报文断开连接。
(3)问题来了:当在某些场景下出现内核写缓冲区里的数据在write()系统调用之后到close()系统调用执行之前没有发送完毕,且内核读缓存区里面还有数据没有读,服务端的close()调用会导致客户端收到RST报文,从而客户端就不会拿到服务端发送过来的完整的响应数据,客户端也就无法知道服务端要发给客户端的错误信息。

3.2、nginx的实现

nginx是自己实现的lingering_close特性。通过两个定时器来完成lingering的工作。
(1)lingering_timeout
在关闭连接前,会检测是否有用户发送的数据到达服务器,如果超过lingering_timeout时间后还没有数据可读,就直接关闭连接;否则,必须在读取完连接缓冲区上的数据并丢弃掉后才会关闭连接。
(2)lingering_time
这个时间也就是nginx在关闭写之后,保留socket的时间。客户端需要在这个时间内发送完所有的数据,否则nginx在这个时间过后,会直接close()关掉连接和释放套接字资源,就不再管客户端还有没有数据再发送过来了。
(3)nginx是支持配置是否打开lingering_close选项的,通过lingering_close选项来配置。在实际应用中,是否应该打开lingering_close呢?
这个就没有固定的推荐值了,如 Maxim Dounin所说,lingering_close的主要作用是保持更好的客户端兼容性,但是却需要消耗更多的额外资源(比如连接会一直占着)。

其实优雅关闭连接的代码实现主要还有两种方式:
方法一:给套接字设置SO_LINGER选项,然后关闭连接的时候直接close()就行。这样就由内核去帮上层去做延时释放套接字资源。
方法二:上层要关闭连接的时候先调用shutdown,然后上层自己去做延时,然后再调用close()。比如上述的nginx就是这种做法。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值