首页 【开发日志】df、du 和 lsof
文章
取消

【开发日志】df、du 和 lsof

最近在服务器上遇到一个诡异的事情,磁盘空间每天都达到上限,好不容易腾出一些空间,好几 G 的存储马上被占完;加上 df -ha 和其他一些工具统计的存储大小相差太大,本来我也懒得去找原因。

但我实在腾不出多余的空间了:总共 100 G 的存储,所有工具都只显示只使用了 40G+,唯独 df 显示剩余空间 4KB…

起初我以为是那些工具没有统计到隐藏或者非权限文件,但我已经是 root 用户,再不济 sudo 命令也用了,依然只使用 40G+。

然后,我怀疑最近编译的项目太多,随便一个都至少需要 1G 空间…

但这些都不是根本原因 :)

原因在这:Ubuntu server: hard drive always full

df 根据文件系统的元数据来统计块大小(所以它出结果很快),而 du/dust/ncdu 之类的统计工具会基于目录树,也就是遍历目录(更慢)。

然而对于在进程中打开的文件,如果直接从文件系统删掉它,那么该文件所占的空间并没有被释放,但会从目录中移除,这会造成 df 和 du 统计结果不一致。

lsof +L1 命令(需要管理员权限),显示所有挂载为延迟卸载(Lazy Unmount)的文件系统。挂载为延迟卸载的文件系统意味着,即使文件系统不再被任何进程使用,它也不会立即被卸载。 这通常用于系统维护或当文件系统需要被安全地卸载时。

我运行它的结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
COMMAND       PID     USER   FD   TYPE DEVICE    SIZE/OFF NLINK   NODE NAME
CmsGoAgen     394     root    2u   REG  252,1           0     0 393345 /usr/local/cloudmonitor/logs/panic.daemon.log (deleted)
CmsGoAgen     394     root    3u   REG  252,1           0     0 393345 /usr/local/cloudmonitor/logs/panic.daemon.log (deleted)
rsyslogd      418   syslog    7w   REG  252,1 49879654878     0 665386 /var/log/syslog (deleted)
rsyslogd      418   syslog    8w   REG  252,1     2977351     0 771662 /var/log/auth.log (deleted)
rsyslogd      418   syslog    9w   REG  252,1      347269     0 669068 /var/log/kern.log (deleted)
ntpd          479      ntp    4w   REG  252,1       17901     0 655822 /var/log/ntp.log (deleted)
unattende     525     root    3w   REG  252,1         339     0 657564 /var/log/unattended-upgrades/unattended-upgrades-shutdown.log.1 (deleted)
apache2       537     root    2w   REG  252,1      805884     0 771623 /var/log/apache2/error.log (deleted)
apache2       537     root    7w   REG  252,1           0     0 656011 /var/log/apache2/other_vhosts_access.log (deleted)
apache2       537     root    8w   REG  252,1     8023582     0 771622 /var/log/apache2/access.log (deleted)
fupan-ser  591608     root    6u   CHR  136,1         0t0     0      4 /dev/pts/1 (deleted)
apache2   1272515 www-data    2w   REG  252,1      805884     0 771623 /var/log/apache2/error.log (deleted)
apache2   1272515 www-data    7w   REG  252,1           0     0 656011 /var/log/apache2/other_vhosts_access.log (deleted)
apache2   1272515 www-data    8w   REG  252,1     8023582     0 771622 /var/log/apache2/access.log (deleted)
apache2   1272516 www-data    2w   REG  252,1      805884     0 771623 /var/log/apache2/error.log (deleted)
apache2   1272516 www-data    7w   REG  252,1           0     0 656011 /var/log/apache2/other_vhosts_access.log (deleted)
apache2   1272516 www-data    8w   REG  252,1     8023582     0 771622 /var/log/apache2/access.log (deleted)
aliyun-se 1805451     root    7uW  REG  252,1           0     0 917509 /tmp/AliyunAssistClientSingleLock.lock (deleted)
tmux:\x20 2674789     root    6u   CHR 136,11         0t0     0     14 /dev/pts/11 (deleted)

我几个月前看到磁盘空间不太够,通过 dust 看到 /var/log 目录下日志文件几十 G,直接 rm -r 删了,但写入日志的系统进程始终在运行,系统日志文件没关闭, 从而磁盘空间没释放,所以这些文件都显示 deleted。其中的罪魁祸首是 rsyslogd 记录的系统日志,它占了 40G 空间,没被 du 统计到。

rsyslogd 是一个系统守护进程,用于在基于 Unix 和类 Unix 系统的计算机上记录消息。它是 rsyslog 软件套件的一部分,是 syslog 协议的一个实现,用于消息的传输和接收。rsyslogd 负责收集和处理来自系统上各种应用程序和服务的日志消息,并将它们写入到日志文件中。

显然,它会让系统日志文件一直打开,直接从磁盘上清理它,并不能释放它的空间。需要一些安全的做法:

  • sudo systemctl stop rsyslog 关闭服务进程,解除进程对文件的占用,然后清理文件,最后 sudo systemctl start rsyslog 恢复服务
  • 或者使用 logrotate 日志管理工具,自动清除太久前的日志

呼~ 这些都是事后才知道的事情,那么回到只剩 4KB 的那种情况,我当时想通过重启系统,让这些进程在系统关机前自己结束,释放磁盘空间。

不过,在你决定重启之前,告知我已经这么做,但会出现问题的一个经验之谈:clickhouse、apache2 之类的服务,在重启时,会确保 /var/log 日志目录已经存在才能拉起,它们不会自动创建日志目录。由于我直接删除了它们的目录,当我通过 root 权限手动重新建立那些目录时,可能造成文件权限不够, 因为服务写入日志很可能不使用管理员权限。

那怎么办?我需要一个个查这些服务创建的账户是什么,然后切换到那些账户去建立吗?或者通过用户组,在同一级别的权限账户建立目录? 幸好我最近在更新系统,apt upgrade 会更新那些软件,到时候程序自己会重建这些日志目录,最终服务终于正常工作。

如果你不想遇到这个麻烦,那么最好不要关机来保持现有的服务运行,使用 lsof +L1 查看进程,想办法正常关闭那些进程来释放磁盘!

本文由作者按照 CC BY 4.0 进行授权

【开发日志】embassy 使用记录

Clickhouse 解决内存受限