Too many open files in system 问题排查记录

同事新上线了一个日志 sdk。运行一段时间后导致线上服务器打开太多文件而拒绝服务。

原因很简单每一个日志实例化,都持有了一个写文件的流,写完没有关闭。

随着业务运行导致服务器崩溃。

fd (file descriptor) 是什么?

我们先来介绍一下 fd,一个进程所有打开的文件可以通过 fd 查询。

举例来说,当一个程序(进程)要写文件时,会像操作系统申请权限。操作系统会授予一个标记(通常是数字)来指向所描述的文件。这个标记就是 fd。

在 centos 中,一个进程的所有打开的 fd 在 /proc/进程id/fd 下。

如何排查

比如一个 node 服务, 我们先找一下他的进程 id

1
ps aux | grep node

image

第二列就是进程 id。有了进程 id 就可以查一下具体的 fd

1
sudo ls -l /proc/29027/fd

image

当打开文件数量过多时,可以通过命令查看打开连接的总数:

1
sudo ls -l /proc/29027/fd | wc -l

结论

从现象定位问题是比较简单的。上面写了一些排查还有测试过程。这里在描述一下解决方案:

在 nodejs 中,流是一个非常重要的概念。在日志这个场景中。我们打开一个流,日志直接往内部写就可以了。在进程退出或者日志路径切换过程中销毁并新建即可。而不需要每次都新建一个流。

所以用全局的流来写日志是一个不错的方案。即便是多进程,以及按等级分不同的流,它的复杂度也是 O(n)。高效并且可控。

1
类似 appendFile 这种 buffer 形式写文件,每次写入都需要打开关闭,不适合来做日志。

参考

ISSUE

有问题?来 github 一起讨论。