使用 isomorphic-unzip 发现的 Bug

前言

之前查看 NodeJS 项目的磁盘占用空间一直在增长,而且每次重启之后磁盘占用空间又急剧下降,然后又开始随时间增长。这个现象非常不符合预期。

排查

du 大法

首先是使用了 du 命令,查看了这个项目容器中,到底是哪些文件占用了磁盘空间。然而一无所获,根本没有找到大量占空间的文件/目录。

lsof 大法

既然 du 查不到,那试着查下当前打开的文件列表。不查不知道,一查吓一跳,发现了一堆已经删除但未正确释放的文件,大概像下面这样(从网上找的示例)。

1
mysqld	2660	mysql	4u	REG	8,2	0	524290	/tmp/xxxx (deleted)

关键逻辑梳理

到这里,问题就已经很明确了:项目中某些地方打开了这些文件,在没有正常关闭的情况下,被其它逻辑给删除了。

首先找到了几处删除的逻辑,定位到被操作的文件,然后再顺着往上找,找出所有可能操作这个文件的地方,然后就找到了 isomorphic-pkg-reader 这个库。这个库的源代码挂在了 TencentWSRD 这个 OWNER 下,但已经 8 年没有更新过了,估计也没有什么人用了。

这个库使用了 yauzl 来懒解压 zip 文件,从中读取需要的内容。但是并没有按照 yauzl 的官方文档正确关闭文件,也没有暴露接口给用户手动关闭(真的是造孽啊)。

If close() is never called, then the zipfile is “kept open”. For zipfiles created with fromFd(), this will leave the fd open, which may be desirable. For zipfiles created with open(), this will leave the underlying fd open, thereby “leaking” it, which is probably undesirable. For zipfiles created with fromRandomAccessReader(), the reader’s close() method will never be called. For zipfiles created with fromBuffer(), the close() function has no effect whether called or not.

处理

在定位到关键问题之后,我尝试着给这个库提了 PR,但已经快一个季度了,都没有任何回应。也许连之前的维护者也已经放弃这个库了?

无奈之下,我只好把库的源代码拷贝到自己的项目中,然后进行一点点「魔改」,解决这次的「磁盘泄露」问题。

如果你也恰好用了这个库,也可以参考我的 PR 内容处理一下。

一些想法

  • 尊重开源
  • 拥抱开源
  • 敬畏开源