拨号VPS的存储空间不足导致的服务中断问题?
你有没有经历过这种场景:一觉醒来,发现自己的网站打不开了,或者之前跑得好好的脚本突然报错退出。你赶紧登录VPS一看,系统倒是能连上,但敲了几个命令之后,屏幕上出现了“No space left on device”这行字。再一看磁盘使用率,好家伙,100%。
这种感觉挺无力的。明明CPU还有余量,内存也没满,带宽更是绰绰有余,就因为硬盘塞满了,整个服务就这么“憋”死了。而且这种中断往往来得悄无声息,不像CPU飙升那样会报警,也不像网络断开那样立刻就能发现。等你意识到问题的时候,可能已经中断好几个小时了。
我管了这么多年拨号VPS,存储空间不足导致的服务中断,是我遇到过频率最高、也最容易被人忽视的一类故障。今天就把这类问题的前因后果、排查方法和长效解决思路,好好跟你聊一聊。
一、为什么服务会“突然”中断?
很多人觉得奇怪,磁盘空间不足怎么就能让服务中断呢?又不是死机蓝屏。这里面的逻辑其实不复杂。
现代操作系统和应用程序,在运行过程中都离不开“写文件”这个动作。你的网站要写访问日志,数据库要写数据文件,脚本要写中间结果,就连SSH登录都要在/var/log里记上一笔。当磁盘满了,任何写入操作都会失败。
数据库遇到写入失败,会选择自我保护,有的会直接崩溃退出,有的会切换到只读模式。Web服务器写不了日志,可能会抛出异常或者干脆拒绝新的连接。定时任务执行的时候,如果无法写入日志文件,整个任务就可能静默失败。最麻烦的是系统层面的写入失败,比如某个核心服务需要写pid文件或者锁文件,写不了就直接起不来了。
我遇到过一台跑着MySQL的拨号VPS,磁盘不知不觉被慢查询日志撑满了。MySQL写不了数据文件,直接crash掉。等我发现的时候,业务已经中断了将近一天。而这一切的起因,只是几个月前我随手开启的一个慢查询日志功能。
拨号VPS的存储空间普遍不算大,系统盘可能就二三十个G。在这个有限的空间里,要装操作系统、装应用软件、存日志文件、跑业务数据,稍不注意就捉襟见肘。存储空间不足导致的服务中断,本质上不是“事故”,而是“必然”——只要你没有做好容量管理,这一天早晚会来。
二、空间去哪了?四大“吞金兽”
找到问题的根源,才能对症下药。根据我的经验,拨号VPS的存储空间被耗尽,罪魁祸首往往是下面这四个。
第一个是日志文件
日志是存储空间的“头号杀手”。系统日志、应用日志、访问日志、错误日志……每一个都在默默地往硬盘里写东西。而且很多程序默认的日志级别是INFO或者DEBUG,这意味着你跑一天任务,可能产生几百兆甚至几个G的日志。
最要命的是,日志文件是“只增不减”的。你今天不删,它就在那儿。你下个月不删,它还在那儿。你忘了这回事,半年之后它可能已经吃掉了一半的磁盘。
第二个是数据库文件
如果你在VPS上跑了MySQL、PostgreSQL或者SQLite,数据库文件的大小会随着数据量的增加而稳步增长。有些人建了数据库从不做清理,也没配置过自动过期机制,结果就是数据表越来越大,文件越来越肥。
还有一个容易被忽略的点是数据库的binlog。MySQL的二进制日志用于主从复制和数据恢复,但如果没有设置自动过期,这些日志文件会无限堆积,几天之内就能吃掉十几个G。
第三个是软件包缓存和临时文件
Linux系统的包管理器会缓存下载过的deb或者rpm包。apt的缓存在/var/cache/apt/archives,yum的在/var/cache/yum。半年不清理,攒出几个G的缓存文件是常有的事。
还有/tmp目录和各种临时目录,有些程序写临时文件很“大方”,用完又不主动删除。时间长了,这些“没人管”的临时文件就成了一堆垃圾。
第四个是用户数据
自己的业务数据当然也要算进去。有时候是我们自己忘记清理了,比如下载了一堆文件放在home目录,跑完的任务产生的中间结果没有及时删除,或者备份文件越攒越多。这些“自己放进去”的东西,往往是最容易被忽视的。
三、空间不足如何一步步杀死你的服务?
存储空间从“够用”到“耗尽”,并不是一瞬间完成的。中间有一个逐渐恶化的过程,如果你能在这个过程的早期发现问题,完全来得及避免服务中断。
第一阶段:轻度告警
磁盘使用率超过80%,系统还在正常运行,但你已经能在监控或者命令行里看到红色的告警了。这时候服务没受影响,只是“房价有点紧张”。很多人在这个阶段会选择忽略——“还能用,不急”。
第二阶段:中度压力
使用率超过90%,系统开始出现一些微妙的变化。日志写入变慢,数据库插入操作的延迟增加,某些服务的响应时间比以前长了。如果你用的是SSD,高占用下读写性能也会有所下降。
第三阶段:严重告急
使用率达到95%以上,系统开始拒绝核心文件的写入。有些程序会开始报错,比如“cannot write to file”。但服务可能还能凑合运行,只是状态已经很脆弱了。
第四阶段:服务中断
磁盘满了,100%。任何需要写入磁盘的操作都会失败。数据库崩溃、Web服务报500错误、定时任务无法执行、SSH虽然还能连,但你在bash里按Tab补全都会报错。业务全面中断。
从第一阶段到第四阶段,可能是几天,也可能是几个月。区别只在于你的业务写入数据的速度有多快。如果你每天产生1个G的日志,而磁盘空闲只有5个G,那五天之后你就完蛋了。
四、现场急救:服务已经中断了怎么办?
如果已经到了服务中断的阶段,不要慌,按下面的步骤来操作。
第一步,立刻释放一点紧急空间
服务已经挂了,你要做的是用最快的方式释放哪怕几十兆的空间,让系统缓过这口气来。
最快的办法是清理包管理器缓存。Debian系执行apt clean,RedHat系执行yum clean all。这个操作是绝对安全的,只是删除已经安装过的软件包缓存,不会影响现有系统。
如果还不够,清理journal日志。执行journalctl --vacuum-size=100M,这条命令会把systemd的日志压缩到100M以内。效果立竿见影,绝大多数情况下能释放好几个G。
如果还不行,进/var/log目录,找最大的那个日志文件,用> 文件名清空它,而不是删除。清空之后空间立刻释放,系统就能恢复写入了。
第二步,重启关键服务
空间释放出来之后,之前因为写入失败而崩溃的服务不会自己活过来。你需要手动重启它们。比如如果你用的是MySQL,执行systemctl restart mysql;如果是Nginx,systemctl restart nginx。检查一下各个服务的状态,确保都正常运行了。
第三步,尽快查明原因
服务恢复之后,别急着收工。立刻找出是哪个目录、哪个文件占用了大量空间。用之前说的du命令层层定位,找到那个“罪魁祸首”。看清楚之后,决定是清理、压缩还是搬家。
五、长效治本:不要再让同样的事情发生
急救只能解决眼前的问题,你需要建立一套机制,让存储空间保持在健康的水位。这套机制不需要多复杂,但一定要“自动化”。
第一招:让日志自己管自己
用logrotate做好日志轮转。对于主要的日志文件,设置好轮转频率和保留份数。我个人的习惯是:每天轮转一次,保留七份,开启压缩。这样日志最多占用七天的量,而且压缩之后体积小很多。
对于journald,在/etc/systemd/journald.conf里设置SystemMaxUse,限制日志的最大占用空间。我一般设成500M或者1G,看磁盘总容量。
第二招:管好数据库
如果你在用MySQL,一定要设置binlog的过期时间。在my.cnf里加上expire_logs_days = 7,意思是只保留七天的二进制日志。定期执行OPTIMIZE TABLE,回收删除数据后释放的空间。
对于SQLite,定期执行VACUUM命令,重新整理数据库文件,回收空闲空间。
第三招:清理包管理器缓存
设置一个cron定时任务,每个月执行一次apt clean或者yum clean all。缓存文件不需要长期保留,装完软件之后它就没用了。
第四招:监控告警,提前介入
这条最重要。在你的VPS上配置简单的磁盘监控,比如用df -h检查使用率,超过80%就发个邮件或者消息提醒。很多服务商的控制面板也自带监控功能,设置好阈值就行。
不要等到90%甚至95%再去处理。80%的时候你有大把的时间从容应对,到了95%你就是在跟时间赛跑了。
六、一个真实的“抢救”案例
去年年底,一个做海外营销的朋友突然给我打电话,语气很急。他说他的一台Windows拨号VPS上的某个关键服务不响应了,客户那边已经炸锅了。
我让他用VNC连上去看了一眼。系统C盘红了,只剩不到200M可用。他说上周看的时候还有四五个G,怎么突然就没了。
我们打开WinDirStat扫描C盘,很快发现了问题所在。C:\ProgramData\MySQL目录下面,有一个叫mysql-bin的文件序列,体积大得惊人。每个文件1G,有二十几个,加起来占了二十多个G。这是MySQL的binlog日志,他从来没有设置过自动过期,系统默认是永久保留。
数据库本身倒是还能连上,但因为磁盘满了,binlog写不进去,MySQL主动把自己锁在了只读模式。这就是为什么服务能连但写不了数据。
解决方案很简单。先进MySQL执行PURGE BINARY LOGS BEFORE NOW(),把旧的binlog清理掉,只保留当天的。一下子释放了二十多个G的空间。然后修改my.cnf,加上expire_logs_days = 7,以后binlog只保留七天。重启MySQL,服务恢复正常。
整个过程不到半个小时。朋友后来心有余悸地说,如果他出差那几天磁盘满了,等他回来再处理,损失就大了。从那以后,他给自己所有VPS都加上了磁盘监控告警。
总结
拨号VPS的存储空间不足导致服务中断,这是一个完全可以预防的问题。它不像硬件故障那样不可控,也不像网络攻击那样需要对抗外部力量。它更像是一个“卫生习惯”问题——只要你平时稍微花点心思打理,就不会出大乱子。
我建议你今天就做三件事:第一,登录你的VPS看一眼磁盘使用率,如果超过80%,立刻动手清理。第二,检查一下logrotate和journald的配置,确保日志不会无限膨胀。第三,如果有数据库,确认binlog的过期时间设置好了。
这三件事花不了二十分钟,但它们能帮你省下一个又一个通宵抢救的夜晚。存储空间不会自己变多,但你可以让它用得明明白白、干干净净。


