目录
- 1. 前言
- 2. keepalive 介绍
- 3. Nginx 与 keepalive 的关系
- 3.1 Nginx - keepalive_timeout
- 3.2 Nginx - keepalive_requests
- 3.3 Nginx - upstream - keepalive
1. 前言
在 nginx中,有三处配置会涉及到 keepalive 的配置:
- http配置段的 keepalive_timeout 项
- http配置段的 keepalive_request 项
- upstream 代码段的 keepalive 项
2. keepalive 介绍
什么是 keepalive?作用是什么?
keepalive 是在 TCP 中一个可以检测死连接的机制,作用是保持 socket 长连接不被断开,属于 TCP 层的功能,并不属于应用层。
TCP 层怎么做到保持长连接的?
Linxu 中有三个参数,开发给应用层使用:
net.ipv4.tcp_keepalive_intvl = 75 探测间隔,未收到回复时,重试的时间间隔,单位:秒 net.ipv4.tcp_keepalive_probes = 9 探测次数,重试次数 net.ipv4.tcp_keepalive_time = 7200 探测的心跳间隔,TCP链接在多少秒之后没有数据报文传输启动探测报文,单位:秒
3. Nginx 与 keepalive 的关系
3.1 Nginx - keepalive_timeout
在 nginx http配置段有 keepalive_timeout 配置项,默认为 65 秒
keepalive_timeout 65; 服务器端主动发起keepalive连接,并保持 65 秒,如果超过65秒没有发送任何请求,则服务器主动断开连接,TCP从ESTABLISHED 转为 TIME_WAIT 状态。
为什么会用到 keepalive_timeout ?
通过配置 keepalive_timeout 可以实现服务器与客户端之间的长连接,用户连接访问服务器可能不止 1 次请求,使用keepalive可以减少系统对TCP连接的建立和销毁的开销。
接下来通过抓包来验证 开启 和 关闭 keepalive_timeout 的两种情况:
(1)测试1 - 配置 keepalive_timeout 为 0
192.168.118.15:nginx服务器 192.168.118.94:客户端
配置如下:
抓包分析:
当设置 keepalive_timeout 0 时,用户发起一个请求,创建一个TCP连接,完成请求后,nginx端主动发送 FIN 断开,从ESTABLISHED 转为 TIME_WAIT 当第二个请求再来时,重复以上步骤。
在创建和销毁TCP连接的同时,会消耗系统资源。在高并发的时候,会造成大量系统资源的浪费,产生很多 TIME_WAIT 连接占用端口,如果不能及时的断开,则会造成系统端口用尽的情况。
当设置 keepalive_timeout 0 时,通过浏览器快速刷新,查看nginx服务器连接数:
可以看到, 充斥着大量的 TIME_WAIT 状态的tcp连接,这只截了一部分。
(2)测试2 - 配置 keepalive_timeout 65
首先,从时间上分析下keepalive 保活,从上图看, TCP Keep-Alive 是 10 秒中,没有任何数据传输才会触发 keepalive保活机制。
在从这张图来看,在 nginx 中,keepalive_timeout 的解释应该是:如果 65 秒中之内,没有接收到任何数据,则主动断开,如果在65秒内有数据传输,则从最后一次数据传输完毕后,重置计时时间。
从 TCP 追踪流来看
在 keepalive_timeout 时间内的请求, 都由一个 TCP 连接进行处理了,TCP连接得到很好的复用,减少了系统的开销。
当设置 keepalive_timeout 65 时,通过浏览器快速刷新,查看nginx服务器连接数:
可以看到, 对于一个客户端,只需要开启一个tcp连接请求就能轻松实现请求处理,大大减低了资源的浪费。
总结:
对于nginx来说,开启 keepalive_timeout 还是很有必要的,通过测试也得知,keepalive_timeout 是从最后一个请求开始计时,对于高并发的主机来说,这个时间可以适当的进行调整。
3.2 Nginx - keepalive_requests
keepalive_requests指令用于设置一个keep-alive连接上可以服务的请求的最大数量,当最大请求数量达到时,连接被关闭,值为0会也禁用keep-alive客户端连接;。默认是100。
答案显而易见,通过 keepalive_timeout keepalive_requests 来管理长连接:
- 当一个tcp连接存活时间超过 keepalive_timeout 时则会被close掉,nginx的具体实现,是通过定时器来做的
- 当一个tcp连接最大数超过 keepalive_requests 时则也会被close掉
(1)测试1 - keepalive_requests 为 0
抓包分析如下:
当 keepalive_requests 为 0 的时候,keepalive 的关闭的状态,1个TCP连接处理1个请求。和keepalive_timeout 为 0 一样的效果。因此要开启keepalive时,这两个参数都不能为0
(2)测试-2 - keepalive_requests 为 3
抓包分析如下:
当设置 keepalive_requests 为 3 时,一个TCP 连接最多响应用户请求 3 次就强制断开连接,不会等到 keepalive_timeout 时间后断开。
总结:
keepalive_requests 就等于是设置 一个 TCP 连接的处理请求的数量,当请求等于设定的这个数值,就断开该连接,如果用户再次发起连接则新建一个TCP连接响应用户。
3.3 Nginx - upstream - keepalive
为了测试 upstream 中的 keepalive 的功能,后端服务器采用 tomcat
主机信息:
客户端 192.168.118.94 nginx 192.168.118.15 tomcat 192.168.118.16
在 http 1.1 中可以配置服务器端开启 keepalive 与客户端保持长连接。接下来看 nginx与后端服务器怎样交互的。
nginx 配置如下:
keepalive_timeout:65 设置nginx开启keepalive,超时时间为65秒,也就是说:如果客户端65秒内没有后续的请求过来,nginx就会断掉这个TCP连接,设置为0表示禁用keepalive。
keepalive_requests :100 设置长连接能够处理请求的次数,100表示:一个长连接nginx最多处理100次请求就会关闭。
这两个配置项,上面已经得到了证实。
keepalive : 10 这个值必须设置,默认为0. 设置每个worker可以保持长连接空闲时的最大连接数。
这里需要特别解释一下,假设nginx有100个请求需要访问Tomcat,那么会建立100个连接,如果双方都支持keepalive,那么这100个连接都是长连接(可以复用那种的),当请求结束后,nginx会立马销毁 90个(100-90),只剩下10个长连接,这10个长连接在Tomcat的keepAliveTimeout时间到期后由Tomcat方关闭。
Tomcat的 keepAliveTimeout这个值可以设置大一些,性能会很好,比如设置个10分钟,20分钟的。
测试
用户端用浏览器快速的刷新,首先查看 nginx 连接情况:
可以看到火狐浏览器启动了 5 个tcp连接来加载资源,无论怎么刷新,连接都不会变化,这就是因为使用了 keepalive,所有的连接可以进行复用,如果把 nginx 的keepalive_timeout 设置为 0 ,每次刷新都会使用新的 TCP 连接,这里会出现大量的 TIME_WAIT 的连接。
接下来,查看 tomcat 服务器连接情况:
只截图了一部分,出现了大量的 TIME_WAIT 的 tcp 连接,也就是说 客户端与 nginx 连接时确实是用了keepalive,但是nginx与tomcat的连接却没有启用keepalive,每一次请求都新建一个 tcp,用完一次就关闭没有复用,所以出现了大量的TIME_WAIT的TCP连接,如果流量稍微大一些tomcat服务器会因为tcp资源耗尽而宕机。
通过上面的配置,在 upstream 中,已经配置过 keepalive,为什么没有生效呢?
这里就需要抓包分析 nginx 与 tomcat 之间是不是依然采用的http1.0 短连接通信:
客户端连接nginx时,使用的 http1.1,并设置了 keepalive 头
而 nginx 请求tomcat时,采用的是 http1.0,并且 connection 设置了 close 告诉 tomcat 连接只用一次,用完关闭。
通过上面分析,很明确的知道了 nginx 到 tomcat 采用的是 http1.0 短连接模式。查看官方:
需要在 location 中配置:
proxy_http_version 1.1; proxy_set_header Connection "";
现在 nginx 到后端的连接也是 http1.1
接下来,还是通过浏览器刷新,查看服务器连接状态:
nginx 服务器查看如下:
一共 10 个连接, 其中 5 个是 客户端与 nginx 的连接,另外 5 个是nginx与tomcat的连接。
再次查看 tomcat 服务器连接状态:
tomcat 上一共是 5 个与 nginx 服务器的连接。这样 nginx 与 tomcat 也是 keepalive 长连接了。
这里在补充下,经过测试,nginx 与 后端 tomcat 断开是由 tomcat 中 connectionTimeout 决定的,而且是由后端tomcat 主动断开连接。