日本VPS的磁盘空间告急,通常不是一夜之间发生的。它更像一个缓慢累积的过程:日志文件每天追加几十兆,包管理器缓存悄悄膨胀,某个服务忘了配置轮转,等到df -h报出100%的时候,往往连SSH登录都开始卡顿。这时候最忌讳的是慌不择路地rm -rf一通,删错了正在写入的日志文件,空间没释放,服务反而先崩了。下面从定位到清理,重点落在日志排查和journalctl的真空操作上,步骤按紧急程度排列。
先判断是空间满了还是inode满了?
登录之后第一件事,跑两条命令,分别看空间和inode:
df -h
df -i
df -h看的是块设备使用率。如果/或/var的Use%到了100%,说明数据确实写满了。但还有一种容易被忽略的情况:df -h显示还有空间,但创建文件时报“No space left on device”。这时候看df -i,如果Inodes一栏的IUse%满了,说明是大量小文件耗尽了inode,而不是存储块本身。日本VPS上常见于缓存目录、会话文件、或者某个失控的日志切分脚本产生了海量小文件。两种情况的清理思路不同,先确认再动手。
定位大头目录,别急着删
确认是块空间满之后,用du逐层排查。不要一上来就扫全盘,从根目录的一级子目录开始:
du -sh /* 2>/dev/null | sort -rh | head -20
2>/dev/null把权限不足的报错吞掉,sort -rh按人类可读的大小倒序排列。通常排在前面的会是/var、/usr、/home。进入占用最高的那个目录,再跑一次:
du -sh /var/* 2>/dev/null | sort -rh | head -20
如果/var/log排在前列,那日志就是主要嫌疑。如果/var/lib/docker很大,问题在容器层。如果/var/cache突出,包管理器缓存是元凶。这一步的目的是把清理范围收窄,而不是直接产生删除动作。
日志文件:先看清谁在写,再决定怎么清
进入/var/log,先列一下当前最大的日志文件:
find /var/log -type f -size +50M -exec ls -lh {} \; 2>/dev/null
常见的几个大户:/var/log/syslog或/var/log/messages(取决于发行版)、/var/log/auth.log、/var/log/nginx/access.log、/var/log/mysql/error.log。找到大文件之后,不要直接rm。如果进程还持有该文件的写句柄,rm之后空间不会释放,df -h依然显示满,而你已经看不到这个文件了,反而更麻烦。
正确的做法分两种。如果只是想立刻释放空间且不关心旧日志内容,用truncate清空文件但保留文件本身:
truncate -s 0 /var/log/某文件.log
进程继续往同一个inode写,空间瞬间回收。如果日志有保留价值,用logrotate做一次强制轮转,把当前文件归档并通知进程重新打开新文件。以Nginx为例:
logrotate -f /etc/logrotate.d/nginx
-f是强制执行。执行后当前access.log会被重命名并压缩,Nginx收到信号后打开一个新的access.log继续写。前提是/etc/logrotate.d/nginx的配置存在且postrotate脚本正确发送了USR1信号或执行了nginx -s reopen。如果该文件不存在,说明Nginx日志从未被轮转过,需要先补一份配置,否则清理只是暂时的,过几周又会满。
对于/var/log下那些已经确认无用的旧归档文件(.gz、.1、.2后缀),可以按时间清理:
find /var/log -type f \( -name "*.gz" -o -name "*.1" \) -mtime +30 -delete
-mtime +30表示修改时间在30天以前。先跑一遍把-delete换成-ls看看会删哪些,确认无误再执行真删。
journalctl:systemd日志的真空操作
现代Linux发行版上,systemd的journal日志是另一个容易被忽视的占用源。它不写在/var/log下面一个显眼的文本文件里,而是存在/var/log/journal/下的二进制文件中,用du扫/var/log时可能看到一个不小的目录但不知道从何下手。
先看它到底占了多少:
journalctl --disk-usage
输出类似Archived and active journals take up 1.2G in the file system.。如果这个数字比你预期的大很多,就该做真空清理了。
journalctl提供了两个维度的真空参数,按时间或按大小。按时间保留最近7天:
journalctl --vacuum-time=7d
按总大小限制在200M以内:
journalctl --vacuum-size=200M
两个参数选一个用就行。--vacuum-time适合有合规或排查需求、需要保留一定天数日志的场景;--vacuum-size适合对磁盘占用有硬性上限的场景。执行后它会删除超出条件的归档日志文件,但当前正在写入的活跃日志不受影响。
有一个细节值得注意:如果/etc/systemd/journald.conf里的SystemMaxUse没有设置,journal默认最多可以占用文件系统10%的空间(上限4G)。对于小磁盘的日本VPS来说,这个默认值可能偏大。可以编辑该文件,取消SystemMaxUse=的注释并设一个合理值,比如200M,然后重启服务:
systemctl restart systemd-journald
这样即使不手动跑vacuum,journal也不会无限膨胀。
包管理器缓存:最安全的一刀
日志清理完之后如果空间还不够,包管理器缓存是下一个目标,因为删了完全不影响运行。Debian/Ubuntu系:
apt-get clean
apt-get autoremove --purge
apt-get clean清空/var/cache/apt/archives/下所有已下载的.deb包,这些包安装完就没用了。autoremove --purge移除不再被依赖的旧内核和库文件,--purge连配置文件一起清。RHEL/CentOS系对应的是:
yum clean all
或者dnf clean all。这一步通常能回收几百兆到几个G,取决于上次清理距今多久。
清理之后确认空间真的回来了
做完上述操作,再跑一次df -h。如果空间释放了但数字对不上你删掉的量,大概率是某个进程还占着已删除文件的句柄。用lsof查一下:
lsof | grep deleted
输出里会列出哪些进程持有已删除但未释放的文件。找到对应的服务,重启它(比如systemctl restart nginx),空间就会真正回收。如果不想重启服务,那就只能等进程自己释放句柄,或者接受这部分空间暂时“悬空”。
最后,如果清理完没过几天又满了,说明问题不在“清理”而在“预防”。检查/etc/logrotate.d/下是否覆盖了你实际在跑的服务,检查journald的SystemMaxUse是否设置,检查有没有某个应用在往/tmp或/home里疯狂写东西。日本VPS的磁盘通常不大,默认配置下日志和缓存把盘吃满是迟早的事,把轮转和真空策略配好,比每次满了再救火省心得多。
常见问答:
Q:清空了Nginx的access.log,但df -h显示空间没变,为什么?
A:Nginx进程还持有旧文件的写句柄,truncate清空的是文件内容,但如果你用的是rm删除,inode不会被释放直到Nginx关闭该句柄。解决方法是nginx -s reopen让Nginx重新打开日志文件,或者直接重启Nginx。用lsof | grep deleted可以确认是否有进程在占用已删除文件。
Q:日本VPS上/var/log不大,但磁盘就是满了,还可能是什么?
A:检查/var/lib/docker(如果跑了容器)、/var/lib/mysql或/var/lib/postgresql(数据库文件)、/home下的用户数据、以及/tmp。另外用df -i确认是不是inode耗尽而非块空间耗尽。du -sh /*从根目录逐层排查是最直接的方法。
Q:apt-get autoremove --purge会不会删掉正在用的内核?
A:默认不会。autoremove只移除被标记为自动安装且不再被任何包依赖的包,当前运行的内核被元包(如linux-image-generic)依赖,不会被移除。但保险起见,执行前可以用apt-get autoremove --purge --dry-run预览一下会删哪些包,确认列表里没有你手动装的东西再执行。
Q:清理日志需要先停掉服务吗?
A:用truncate清空文件不需要停服务,进程会继续写。用logrotate -f强制轮转也不需要停服务,但前提是配置里的postrotate脚本正确发送了重新打开文件的信号。直接rm删除正在被写入的日志文件才需要停服务或重启进程来释放句柄,不推荐这种做法。
相关内容
