Open jinhailang opened 6 years ago
keepalive_requests
Waf(基于 Nginx 实现的七层防护系统)上线上后,QA 同事对系统进行大流量压测(十万级 QPS),发现部署机器处于 TIME_WAIT 状态的 TCP 连接数异常,高峰期达到几千。按理 waf 这边使用的是长连接,连接数不应该这么多的。
Waf
TIME_WAIT
首先确认下 TCP 连接处于 TIME_WAIT 原因:
TCP 连接主动关闭方会处于较长的 TIME_WAIT 状态, 以确保数据传输完毕, 时间可长达 2 * MSL, 即就是一个数据包在网络中往返一次的最长时间。 其目的是避免连接串用导致无法区分新旧连接。
这就说明确实是服务端这边主动关闭了连接。我重新 review 了一下 Nginx 配置,确实使用了长连接,并且,我上线前在本地使用 ab 工具压测过, 没有观察到连接数量异常情况。
只能祭出 google 大法了,发现可能是 keepalive_requests 设置太小引起的。
keepalive_requests 参数限制了一个 HTTP 长连接最多可以处理完成的最大请求数, 默认是 100。当连接处理完成的请求数达到最大请求数后,将关闭连接。
而我并没有配置 keepalive_requests,所以,就是使用的默认数 100,即一个长连接只能处理一百个请求,然后 Nginx 就就会主动关闭连接,使大量连接处于 TIME_WAIT 状态。
我猜测很大可能就是这个原因了,为了在本地验证,我将 keepalive_requests 分别设为 10, 50, 100, 1000,分四组分别进行压测,对比结果。
10
50
100
1000
压测命令:
ab -n100000 -c10 -k http://127.0.0.1:8086/test
然后使用 netstat -nat |awk '{print $6}'|sort|uniq -c 查看连接数,结果出乎意料的清晰,TIME_WAIT 数量基本等于 总请求数/keepalive_requests,这就基本证实了猜测。
netstat -nat |awk '{print $6}'|sort|uniq -c
其实大部分情况下,使用默认值是没有问题的,但是对于 QPS 较大的情况,默认数值就不够了,综合考虑,在 Nginx conf 增加配置项:
keepalive_requests 1024;
可能很多人更习惯不做限制,可以设置一个最大的数来实现这个效果 -- 2^32 - 1 = 4294967295(这是在运行32位和64位系统的计算机中是无符号长整形数所能表示的最大值,亦是运行32位系统的计算机中所能表示的最大自然数),
2^32 - 1 = 4294967295
虽然问题解决了,但是,为什么 Nginx 要对单个长连接的处理请求数进行最大限制呢?一般我们理解的,长连接是在连接池里维护的,只要连接本身没有超时等异常问题,是可以一直复用的。
关于这个疑问,讨论的似乎不多,只在 Nginx 开发者论坛上看[nginx] Upstream keepalive: keepalive_requests directive.有所讨论,开发者有模糊的表述:
Much like keepalive_requests for client connections, this is mostly a safeguard to make sure connections are closed periodically and the memory allocated from the connection pool is freed.
但是,为什么需要定时关闭连接,释放内存?难道这只是一种保护策略,怕极端情况下,用户配置不当,导致连接一直不断开,引起内存问题?很奇怪,从 Nginx 开发日志也没有找到特别说明。
另外,上面的讨论贴其实是讨论 Upstream keepalive_requests 设置的,最新版 Nginx (version 1.15.3.) 在 Upstream 内增加了 keepalive_requests 配置项,与 keepalive_requests client connections 类似,默认值也是 100。也就是说,之前的版本,连接上游的连接是没有次数限制的,完全由上游的服务端的 keepalive_requests 设置,但是,如果上游服务端不使用 Nginx 的话,别的系统一般也是没有这个限制的。
keepalive_requests client connections
在大流量的场景下,Nginx 代理升级到这个版本,就可能会引起连接异常情况。关于默认值和兼容性,作者的回复也比较主观,可能这块确实很难面面俱到吧,只能满足大多数场景了。
综上,在 QPS 较高的场景下,服务端要注意将 keepalive_requests 设置的大一些,如果 Nginx 升级到最新版,还需要注意设置 upstream 的keepalive_requests,这两个数量可以不一致,一般服务端要设置的大些,因为一般来说,一个服务端可能对应多个代理。
Nginx
keepalive_requests
踩坑总结问题起因
Waf
(基于 Nginx 实现的七层防护系统)上线上后,QA 同事对系统进行大流量压测(十万级 QPS),发现部署机器处于TIME_WAIT
状态的 TCP 连接数异常,高峰期达到几千。按理 waf 这边使用的是长连接,连接数不应该这么多的。问题定位
首先确认下 TCP 连接处于 TIME_WAIT 原因:
这就说明确实是服务端这边主动关闭了连接。我重新 review 了一下 Nginx 配置,确实使用了长连接,并且,我上线前在本地使用 ab 工具压测过, 没有观察到连接数量异常情况。
只能祭出 google 大法了,发现可能是 keepalive_requests 设置太小引起的。
而我并没有配置
keepalive_requests
,所以,就是使用的默认数 100,即一个长连接只能处理一百个请求,然后 Nginx 就就会主动关闭连接,使大量连接处于TIME_WAIT
状态。我猜测很大可能就是这个原因了,为了在本地验证,我将
keepalive_requests
分别设为10
,50
,100
,1000
,分四组分别进行压测,对比结果。压测命令:
然后使用
netstat -nat |awk '{print $6}'|sort|uniq -c
查看连接数,结果出乎意料的清晰,TIME_WAIT
数量基本等于 总请求数/keepalive_requests,这就基本证实了猜测。问题解决
其实大部分情况下,使用默认值是没有问题的,但是对于 QPS 较大的情况,默认数值就不够了,综合考虑,在 Nginx conf 增加配置项:
可能很多人更习惯不做限制,可以设置一个最大的数来实现这个效果 --
2^32 - 1 = 4294967295
(这是在运行32位和64位系统的计算机中是无符号长整形数所能表示的最大值,亦是运行32位系统的计算机中所能表示的最大自然数),疑问
虽然问题解决了,但是,为什么 Nginx 要对单个长连接的处理请求数进行最大限制呢?一般我们理解的,长连接是在连接池里维护的,只要连接本身没有超时等异常问题,是可以一直复用的。
关于这个疑问,讨论的似乎不多,只在 Nginx 开发者论坛上看[nginx] Upstream keepalive: keepalive_requests directive.有所讨论,开发者有模糊的表述:
但是,为什么需要定时关闭连接,释放内存?难道这只是一种保护策略,怕极端情况下,用户配置不当,导致连接一直不断开,引起内存问题?很奇怪,从 Nginx 开发日志也没有找到特别说明。
另外,上面的讨论贴其实是讨论 Upstream keepalive_requests 设置的,最新版 Nginx (version 1.15.3.) 在 Upstream 内增加了
keepalive_requests
配置项,与keepalive_requests client connections
类似,默认值也是 100。也就是说,之前的版本,连接上游的连接是没有次数限制的,完全由上游的服务端的keepalive_requests
设置,但是,如果上游服务端不使用 Nginx 的话,别的系统一般也是没有这个限制的。在大流量的场景下,Nginx 代理升级到这个版本,就可能会引起连接异常情况。关于默认值和兼容性,作者的回复也比较主观,可能这块确实很难面面俱到吧,只能满足大多数场景了。
综上,在 QPS 较高的场景下,服务端要注意将 keepalive_requests 设置的大一些,如果 Nginx 升级到最新版,还需要注意设置 upstream 的keepalive_requests,这两个数量可以不一致,一般服务端要设置的大些,因为一般来说,一个服务端可能对应多个代理。