首页 > 代码库 > TIME_WAIT状态的连接过多导致系统端口资源耗尽问题(2)

TIME_WAIT状态的连接过多导致系统端口资源耗尽问题(2)

      继上次解决完mysql连接过多,导致的TIME_WAIT进程过多问题之后,最近这个现象再一次出现,并且依然和之前一样严重。只不过这次出现问题的mysql 服务跟上次不一样,上一次主要是mysql master server,而这一次是mysql slave server。所以这意味着,我们上次解决了部分问题,但没有彻底解决,还存在一部分问题。所以这次彻底的把这个问题好好梳理一下。

      再次确认一下TIME_WAIT进程的所属服务:

sudo netstat -anp | grep TIME_WAIT | awk {print $5} | sort | uniq -c | sort -nr | less

     之前排名第一的是mysql master ,其次为mysql slave, 再次为redis的行情数据服务。上一次我们解决了mysql master的问题。所以目前TIME_WAIT进程最多的是mysql slave的连接进程,其次为redis的行情数据服务连接进程。优先查mysql slave,因为slave是只读库,后端这边用到的比较少,总共只有2个后端模块用到了,停掉这两个模块的进程,发现TIME_WAIT没有明显变化,所以集中查前端的php逻辑,因为前端php代码较多,所以简单一点,先统计apache log中各项接口的请求次数,如图:

      横轴是整点时间,纵轴是请求次数。很明显,我们有两个接口的请求次数异乎寻常的多,而且是在开盘时间迅猛上涨,收盘之后迅速回落,跟TIME_WAIT进程暴涨的时间完全吻合。至此,我们基本可以推断,就是这两个接口导致了大量的TIME_WAIT进程,从而导致端口资源被耗尽,新的连接请求失败。

      我们再来确认一下,为什么这两个接口会导致大量的TIME_WAIT进程。简单来说,每一个tcp连接关闭后,主动关闭方都会保留这个连接一段时间,这个时间内,这个连接的状态是TIME_WAIT,端口资源不会被释放。这个超时时间为2*MSL。RFC 793中规定MSL为2分钟,实际由系统决定,通常在30-120s。这个网上有很多详细解释,这里不过多阐述。因为连接的关闭释放有一定时间,并不是程序运行完就立刻释放端口资源,所以当申请的连接进程较多的时候,端口资源就不够用了。系统默认可用的端口资源:

 

$ cat /proc/sys/net/ipv4/ip_local_port_range
32768   61000

     总共才28232个可用端口,我们从日志中统计到高峰期每秒300多个http请求,每个请求都至少有一次tcp连接(mysql/redis/memcache),那么一分钟差不多就是20000个连接。这种环境下,所以端口资源耗尽是很正常的事情。
     至于解决方案,网上有一些详细的参考文档: http://blog.csdn.net/yunhua_lee/article/details/8146830, http://rhomobi.com/topics/47

     基本上解决思路分为两个方向:

1.  建立socket连接时设置SO_LINGER。或者是调整系统参数, 修改/etc/sysctrl.conf中的这几项

# 扩大端口范围,增加端口资源net.ipv4.ip_local_port_range = 1024  6553#开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0net.ipv4.tcp_tw_reuse = 1#开启TCP连接中TIME-WAIT sockets的快速回收,默认为0net.ipv4.tcp_tw_recycle = 1 
#服务端主动发起关闭后等待的超时时间
net.ipv4.tcp_fin_timeout = 5
#开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击
net.ipv4.tcp_syncookies = 1 

  这些调整基本上是能起到一个提高系统性能的作用,使得系统能承受更多的短连接并发。但设置的时候需要谨慎,后续要注意观察,有些参数设置可能在极端情况下存在丢包、断连或者连接不上的隐患。

2.  优化自己的系统,减少短连接次数

   因为tcp连接关闭后是有必要保留一段时间TIME_WAIT状态的,我们的目标不应该是简单的缩短TIME_WAIT时间,而是应该从根本上去优化我们的系统架构设计,减少不必要的短连接请求。

   再回到那两个高频的接口请求,这两个接口实际上是两个股票行情数据接口,为了保证行情的及时更新,客户端会在开市期间每隔2s去刷新一次。所以从根本上讲,这两类请求是不应该走短连接的。但我们的网站又都是用php实现,所以没法用到连接池一类的东西(貌似也可以通过第三方软件做,但对服务性能可能有影响)。

 

TIME_WAIT状态的连接过多导致系统端口资源耗尽问题(2)