首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

从一次 TIME_WAIT 调优说起

keep-alive 连接

在 http 1.0 中,如果客户端在发起请求时加入 首部,服务端在响应的时候也加入 首部,则此次 http 请求将使用持久连接,即请求结束之后 TCP 连接不会关闭以供后续请求继续使用。不难看出,持久连接必须是客户端和服务器都同时支持才可能会发生,因为 TCP 协议是双向通信。

实现持久连接的 http 请求必须要保证报文可以正确判断起始和结束,这在 http 中是通过 content-length 首部以及 chunk 传输来保证的,具体可以参见《http 权威指南》“连接管理”章节,文章 > 也对 keep-alive 作用和意义有详细介绍。

总的来说利用 keep-alive 可有效利用 TCP 连接来提高 web 请求的性能。

一般 web 服务的架构

以简单的 Python web 服务为例,其架构组织如下:

其中 Python app 大多数是 web framework + gunicorn 的组合,gunicorn 是一个 web server。

一个来自 user 的请求会经过如下处理用户最终才能获得响应:

其中 user 连接 nginx 的 TCP 和 nginx 连接 app 的 TCP 是不同的连接,也就是说要完成一个完整的请求 nginx 必须维系着自身与 user 和 app 两端的连接,nginx 作为代理会负责对 user 的请求进行中转处理然后发起与 app 的新的 TCP 连接,这就是 nginx 的角色。

从线上后端 app 服务大量的 TIME_WAIT 说起

默认情况下的,大多数现代浏览器以及其他 web 终端与 nginx 的连接默认都会开启 keep-alive,但是 nginx 与后端 app 则不一定。

以我遇到的场景为例,在后端 app 服务所在的服务器,通过查看其和 nginx 端的连接通过 netstat 查看能够看到

处于 TIME_WAIT 的 TCP 是 1000 多个,但处于 ESTABLISHED 是 20 多个,按照 TCP 协议的描述,具体见 >,处于 TIME_WAIT 的 TCP 连接在等待 2MSL 时间之后才会真正关闭,但是关闭之前其所占用端口和内存资源都不会释放,也就是说 TIME_WAIT 的变多说明服务器的处理能力会受到影响,甚至在极端情况下不响应。

linux 内核 MSL 是 60s,2MSL 就是 120s,每秒有 20 TCP 连接,假设响应时间很短,断开之后等待 2MSL,则 120s 之后差不多会有 1000 多个 TIME_WAIT,基本符合 TCP 的状态变迁。

为什么后端 app 和 nginx 的连接会有如此多的 TIME_WAIT?

nginx 和 gunicorn 的默认配置

默认 nginx 和后端 APP 的连接是短连接,即请求结束之后就会关闭,无论是 nginx 主动关闭还是后端 APP 主动关闭都会产生大量的 TIME_WAIT。

Gunicorn 作为一个 web server 已经很早就开始支持 keep-alive 了,在本文开始说过要保持持久连接,连接的两端都必须支持 keep-alive,所以这里我们主要修改 nginx 和上游 upstream 的连接来支持 keep-alive。

修改 nginx 让 upstream keep-alive

在未修改 nginx 之前可以很明显看到

后端 app 和 nginx 的连接中端口 nginx server 的端口一直在改变,修改 nginx 支持 upstream 的 keep-alive 之后,端口改变的频率降低,甚至一段时间内都不在变化,说明请求复用了连接。

nginx 的 keep-alive 的支持需要在 upstream 配置 指令,并且在 location 中配置

告诉后端 app 请求支持 keep-alive。

具体 keepalive 指令的理解详见> ,尤其是需要注意对 keepalive 指令数量的控制,需要对 keepalive 有非常详细的了解。

内核参数对 TIME_WAIT 的影响

有很多内核参数决定了服务器 TIME_WAIT 在单位时间内产生的数量,比如

在配置服务器需要对不同内核参数进行特定场景的优化,为此就需要理解当前服务器的服务在整个 TCP 链接的角色和位置,比如是作为 client 还是 server。举例来说 nginx 对于下游用户来说是个 server,但是对于后端 app 来说是一个 client,nginx 扮演的角色的不同对其配置差异也很大。

优化内核参数需要认真研读理论部分,仔细就行测验,在结合他人的实践经验针对自己的业务调整。详见(具体链接见文末)

服务器TIME_WAIT和CLOSE_WAIT详解和解决办法

再叙TIME_WAIT

tcp_tw_recycle和tcp_timestamps导致connect失败问题

Android之网络丢包事件

理解 Linux backlog/somaxconn 内核参数

TCP timestamp

参考资料(包括文中文章链接)

https://www.byvoid.com/zhs/blog/http-keep-alive-header

https://skyao.gitbooks.io/learning-nginx/content/documentation/keep_alive.html

https://en.wikipedia.org/wiki/Transmission_Control_Protocol

http://perthcharles.github.io/2015/08/27/timestamp-intro/

http://jaminzhang.github.io/linux/understand-Linux-backlog-and-somaxconn-kernel-arguments/

http://blog.sina.com.cn/s/blog_781b0c850100znjd.html

https://huoding.com/2013/12/31/316

https://www.cnblogs.com/sunxucool/p/3449068.html

https://en.wikipedia.org/wiki/Transmission_Control_Protocol

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180303G0HQFG00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券