最近有个项目,压测的时候发现,cpu和数据库连接,包括redis负载都并不高,但是会在连接数到达2000左右时出现瓶颈,导致大量拒绝连接。
后来分析了下netstat,发现大量的close_wait的连接。考虑系统连接数被吃满,没有及时释放,导致web服务器无法获得有效连接,所以请求进不来。
这里排查了几个方面,首先肯定是是否有主动关闭连接。
发现底层httpclient都有正常处理close,feign也有处理,同时也有配置超时时间。nginx也没有配置keepalive的长连接。
后来查询资料,发现close_wait系统回收也需要时间。
所以需要缩短close_wait的回收时间。查了一下系统配置。
net.ipv4.tcp_max_tw_buckets 默认是180000。这个参数是配置timewait的连接数量。我们把它改小到3000。然后配置timewait的快速回收。net.ipv4.tcp_tw_recycle=1。
完整配置如下:
#timewait 的数量,默认是 180000。
net.ipv4.tcp_max_tw_buckets = 3000
#本地可用端口范围
net.ipv4.ip_local_port_range = 1024 65000
#启用 timewait 快速回收。
net.ipv4.tcp_tw_recycle = 1
#开启重用。允许将 TIME-WAIT sockets 重新用于新的 TCP 连接。
net.ipv4.tcp_tw_reuse = 1
测试在并发连接数达到一定值后,能够有效的回收timewait的连接,从而使得服务器能够接受新的请求进来,有效解决了并发问题。
PS:这里说一下,由于这边是k8s容器部署,是共享宿主机的端口连接数,所以无法达到6w的连接属于正常情况。毕竟一台机器上跑了多个容器服务,都有业务在运行。同时tw回收的数量,根据业务场景自行尝试最优值。