I
Member
服务器跑着跑着突然报 too many open files,新连接进不来,日志也写不进去,第一反应往往是调大 ulimit。但只调上限不找泄漏,等于把水桶换大却不补洞,过几天还会再满。
第一,先确认是谁占了句柄。用 lsof 或 /proc/<pid>/fd 数一下各进程的 fd 数量,排在前面的往往就是嫌疑对象。注意区分 socket、普通文件和 pipe:socket 涨得快多半是连接没关闭,文件句柄涨多半是代码里 open 了没 close。
第二,看系统级和用户级两层限制。ulimit -n 是单个进程的限制,fs.file-nr 和 fs.nr_open 是系统级上限,两层都要看。只调进程上限、系统上限没跟上,照样会报满。
第三,查泄漏的模式。fd 数量是缓慢匀速涨,还是突发式涨?匀速涨多半是每次请求漏关一个;突发涨多半是某个异常分支没走关闭逻辑,或者连接池配置不合理。对着代码里 open、socket、accept 的位置逐一核对关闭路径。
第四,看 TIME_WAIT 和 CLOSE_WAIT 的分布。CLOSE_WAIT 堆积说明应用没及时 close 对端已关闭的连接,这是典型的应用层泄漏;TIME_WAIT 多则是正常的连接关闭残留,调内核参数可以缓解,但不能当成泄漏来治。
第五,调上限要有依据。先按正常业务峰值加 2 到 3 倍余量设,再配合监控告警:fd 使用率到 70% 就告警,不要等到 100% 才发现。
大家排查过 fd 泄漏吗?最后定位到的泄漏点,是在连接处理、日志轮转,还是第三方库里?
第一,先确认是谁占了句柄。用 lsof 或 /proc/<pid>/fd 数一下各进程的 fd 数量,排在前面的往往就是嫌疑对象。注意区分 socket、普通文件和 pipe:socket 涨得快多半是连接没关闭,文件句柄涨多半是代码里 open 了没 close。
第二,看系统级和用户级两层限制。ulimit -n 是单个进程的限制,fs.file-nr 和 fs.nr_open 是系统级上限,两层都要看。只调进程上限、系统上限没跟上,照样会报满。
第三,查泄漏的模式。fd 数量是缓慢匀速涨,还是突发式涨?匀速涨多半是每次请求漏关一个;突发涨多半是某个异常分支没走关闭逻辑,或者连接池配置不合理。对着代码里 open、socket、accept 的位置逐一核对关闭路径。
第四,看 TIME_WAIT 和 CLOSE_WAIT 的分布。CLOSE_WAIT 堆积说明应用没及时 close 对端已关闭的连接,这是典型的应用层泄漏;TIME_WAIT 多则是正常的连接关闭残留,调内核参数可以缓解,但不能当成泄漏来治。
第五,调上限要有依据。先按正常业务峰值加 2 到 3 倍余量设,再配合监控告警:fd 使用率到 70% 就告警,不要等到 100% 才发现。
大家排查过 fd 泄漏吗?最后定位到的泄漏点,是在连接处理、日志轮转,还是第三方库里?