问题描述
事情的起因是,服务器每运行一两天就会出现客户端连接不上的情况,登入服务器查看,发现服务器并没有挂掉,检查日志发现已经中断写日志一段时间了,怀疑是服务器死锁或者死循环了
排查思路
top发现CPU维持在150%多,而日志一直没有写入。但实际情况下,日志至少会定期写入一些统计信息,因此跟踪到写日志线程发现 fopen() 返回 NULL,检查errno为24:即 open files 太多。这时候通过lsof -p 进程号发现,上千个CLOSE_WAIT状态的连接。然后ulimit -n 发现单个进程可以打开的最大文件数为 1024,因此这个问题很明显了。这里要解决的第一个问题首先是打开文件数太少,需要适当改大点,毕竟当前的硬件配置这么少的打开数太浪费了。最核心的还是要解决为什么CLOSE_WAIT为什么这么多的问题。
因为之前服务器上线运行过,且从没有出现过这个问题,所以起初怀疑是配置问题。lsof 的结果如下:
TCP localhost:40824->localhost:http (CLOSE_WAIT)
因此是http连接的一个close_wait,程序中用到http的是一个推送通知服务,连接的nginx,nginx也是自己搭建的,用于处理php请求。因为close_wait是处于在游戏服进程,而且属于被动关闭的一方,因此判定是nginx一方关闭了连接,检查发现nginx配置中,设定的keepalive_timeout值为60s,而当用户数据量比较小的时候,很容易导致连接不够活跃,被nginx主动关闭了连接,也就出现了这个问题。之所以之前没出现这个问题,一是当初可打开文件数设置的比较大,二是活动用户比较多,一直激活着该连接。
但很明显,即使nginx超时时间很短,也不应该有大量的close_wait,因此游戏服本身没有主动close的问题是最根本的原因。