在使用Linux系统中,有时候发现明明已经删除了大量的文件(特别是日志文件),但用du
查看磁盘,空间依然没有减少,这种非常奇怪的问题,最近遇到了。本文描述一下前因后果,并给出一些个人看法。
起因
最近项目准备上线,同事查了服务器磁盘使用情况,发现隔了几天磁盘空间就减少几百兆,叫我查一下。
环境描述如下:
1、nodejs应用服务,使用pm2管理,每天会产生大量日志,并且要保留。(这是必要的,为了与厂家扯皮保留证据)
2、每天半夜,自动压缩日志。(必须的,否则日志太多了)
3、服务器上还有一期遗留的产品,包括源码,日志。已不使用。
经过
首先使用du -h --max-depth=1
查看空间。如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 0 ./dev 0 ./proc 16K ./lost+found 961M ./root 337M ./var 2.5G ./usr 33M ./etc 8.0K ./opt 147G ./home 9.4M ./tmp 4.0K ./media 226M ./run 103M ./boot 4.0K ./srv 298G
|
注:有心的朋友如果计算各个目录的空间总和,则会发现其远远小于最后一行显示的空间大小。笔者在最后时刻才意识到。
/home目录是外挂的硬盘,此处暂不提。从上面信息看到,有几个目录可疑:
1 2 3 4
| 961M ./root 337M ./var 2.5G ./usr 226M ./run
|
发现/usr/local/share/.cache/yarn/v2
、/var/cache/yum
有缓存数据,可以删除。另外发现/root
、/root/path
存在一些旧代码以及不再使用的日志文件、sql文件,/root/.pm2/
有pm2产生的日志。
接着,查找最近1天修改过的文件,命令如下:
得到的文件体积均不大,可能不是此方面原因。
到网上搜索,发现有文章介绍相关的内容,使用lsof |grep delete
来查询已经删除的文件。结果出现大量文件列表,数量很多:
1 2
| lsof |grep delete | wc -l 7344
|
示例如下:
1 2 3 4 5
| node 786 root 15w REG 202,64 1941641 5354776 /root/logs/log39.2019-07-26.txt (deleted) node 786 root 16w REG 202,64 437345392 5354830 /root/logs/logtf.2019-07-26.txt (deleted) node 786 root 17w REG 202,64 471811 5354836 /root/logs/logtt.2019-07-26.txt (deleted) node 786 root 18w REG 202,64 1189231954 5354838 /root/logs/logt3.2019-07-26.txt (deleted) node 786 root 19w REG 202,64 2003838 5354840 /root/logs/logit.2019-07-26.txt (deleted)
|
分别为命令、PID、拥有者、FD、类型、设备、大小、节点、文件名称。只关注命令、PID、大小和文件名即可。
随便找一个进程,查看一下占用的文件句柄fd
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| ls -al /proc/74408/fd total 0 dr-x------ 2 root root 0 Jul 31 12:19 . dr-xr-xr-x 9 root root 0 Jun 27 12:27 .. lrwx------ 1 root root 64 Jul 31 12:19 0 -> socket:[1673886202] l-wx------ 1 root root 64 Jul 31 12:19 1 -> /root/.pm2/pm2.log lr-x------ 1 root root 64 Jul 31 12:19 10 -> /dev/null lrwx------ 1 root root 64 Jul 31 12:19 100 -> socket:[3240337185] l-wx------ 1 root root 64 Jul 31 12:19 13 -> /root/.pm2/logs/1024-error-28.log (deleted) lrwx------ 1 root root 64 Jul 31 12:19 130 -> socket:[3207913087] l-wx------ 1 root root 64 Jul 31 12:19 29 -> /root/logs/log34.2019-06-27.txt (deleted) lrwx------ 1 root root 64 Jul 31 12:19 3 -> socket:[2024014357] l-wx------ 1 root root 64 Jul 31 12:19 30 -> /root/logs/log51.2019-06-27.txt (deleted) l-wx------ 1 root root 64 Jul 31 12:19 31 -> /root/logs/logfa.2019-06-27.txt l-wx------ 1 root root 64 Jul 31 12:19 32 -> /root/logs/log3f.2019-06-27.txt l-wx------ 1 root root 64 Jul 31 12:19 33 -> /root/logs/log35.2019-06-27.txt (deleted) lrwx------ 1 root root 64 Jul 31 12:19 41 -> socket:[2024031696] lrwx------ 1 root root 64 Jul 31 12:19 42 -> socket:[2024031697]
|
至此,能定位到原因了:nodejs服务使用log4js
作为日志管理模块,每天定时备份,将旧日志文件压缩为新文件,再删除旧日志文件,但程序一直在运行,并未退出,即占用的文件句柄并未释放,所以要积累大量的已删除文件,占用磁盘空间。
解决
将nodejs服务手动重启一次,释放了很多空间,下面是重启前的磁盘空间:
1 2 3 4 5 6 7 8
| Filesystem 1K-blocks Used Available Use% Mounted on /dev/xvda2 37024320 27152180 7984756 78% / devtmpfs 3983648 0 3983648 0% /dev tmpfs 3981888 0 3981888 0% /dev/shm tmpfs 3981888 25672 3956216 1% /run tmpfs 3981888 0 3981888 0% /sys/fs/cgroup tmpfs 747024 0 747024 0% /run/user/0 /dev/xvde 515930552 189452476 300263676 39% /home
|
重启后,空间列表如下:
1 2 3 4 5 6 7 8
| Filesystem 1K-blocks Used Available Use% Mounted on /dev/xvda2 37024320 9699008 25437928 28% / devtmpfs 3983648 0 3983648 0% /dev tmpfs 3981888 0 3981888 0% /dev/shm tmpfs 3981888 25616 3956272 1% /run tmpfs 3981888 0 3981888 0% /sys/fs/cgroup tmpfs 747024 0 747024 0% /run/user/0 /dev/xvde 515930552 181515448 308200704 38% /home
|
其实笔者也有疑惑,按理说,log4js
应该在备份日志后,会自动释放句柄,搜索资料未果。按观察之结果,重启一次nodejs即可解决问题。看来,后面要在一定时间间隔内,重启所有的nodejs进程才行。
指导
1、对于旧资料,该删除的要删除,不应保留,除了占用空间,没有其它用。本次排查,统计了旧资料,至少有1GB以上。囿于权限,本次不敢清理。
2、系统缓存(不管是npm、yarn还是apt、yum),建议隔一段时间删除。
3、对使用的程序模块要深入研究,不放过细节。(在追求速度时代,笔者还无法做到)
4、日志规范化,该写的信息要写,不该写的,不写。
5、程序安装目录,尽量不要选择系统目录,如/bin
、/sbin
、/usr/bin
、/usr/sbin
,如果一定要安装,仅将必须的二进制安装在系统目录,配置文件、日志文件、数据文件,放到其它分区。本次发现,mysql和redis的数据目录与安装目录是在一起的,这样做不太合理。
拓展
yarn相关命令:
列出cache目录:yarn cache dir
。
列出详细文件:yarn cache list
。
清除cache:yarn cache clean
。
设置cache目录:yarn config set cache-folder <目录>
。
查找指定时间修改过的文件命令:
查找N天之内:find ./* -mtime -<N天>
查找N天之前:find ./* -mtime +<N天>
恰好N天:find ./* -mtime <N天>
-mtime
以天为单位,类似的,-mmin
以分钟为单位。
资料
磁盘空间被未知资源占尽分析
一次诡异的磁盘空间占用问题排查
诡异的Linux磁盘空间被莫名其妙占用问题
PS:本文为笔者参考网络资料,结合实验经历得到的一些记录,并不权威,仅为个人观点而已。