最近有个项目,压测的时候发现,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
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

测试在并发连接数达到一定值后,能够有效的回收timewait的连接,从而使得服务器能够接受新的请求进来,有效解决了并发问题。

PS:这里说一下,由于这边是k8s容器部署,是共享宿主机的端口连接数,所以无法达到6w的连接属于正常情况。毕竟一台机器上跑了多个容器服务,都有业务在运行。同时tw回收的数量,根据业务场景自行尝试最优值。