前几天碰到碰到一个线上redis CPU跑满的情况,基本无法处理正常请求了,刚开始以为是其他地方的问题,后来grep "Max open files" /proc/`pidof redis-server`/ -r  排查原来是启动redis的时候。ulimit -n 只有1024,从而无法接受新连接。

晚高峰时间段突发的大量请求导致redis连接数超过1024,从而listen sock 持续可读并且accept失败,从而CPU跑满,导致严重的雪崩。比如简单复现的话,ulimit -n 20 修改当前会话的打开文件数,然后启动某个服务器程序,然后给其发送超过限制的TCP连接,这时候监听套接字一定会每次select / epoll的时候,都返回句柄可读。从而不断的accept调用,然后accept立即出现如下错误,也就是EMFILE:

accept failed. errno:24, errmsg:Too many open files.

但是,accept的实现里面遇到句柄数不够的处理方法为:留在下次处理,而不是断开TCP连接,也是有道理的,因为下回说不定就关闭了一些呢。

但这一就会导致监听套接字不断有可读消息,但却accept无法接受,从而listen的backlog被塞满;从而导致后面的连接被RST了。

这里多啰嗦一下,memcached对于这种情况的处理有点特殊,或者说周到,如果memcache accept 的时候返回EMFILE,那么它会立即调用listen(sfd, 0) , 也就是将监听套接字的等待accept队列的backlog设置为0,从而拒绝掉这部分请求,减轻系统负载,保全自我。还是挺不错的。