☰
阿里云ECS磁盘使用率过高怎么办?从排查到扩容的完整指南
2026/10/1 17:50:07 网站建设 项目流程

阿里云ECS磁盘使用率过高处理方案

磁盘写满这件事,几乎每个用过阿里云ECS的人都会碰到。轻则服务报错、网站打不开,重则数据库直接挂掉,连SSH都登不进去。我之前就有一次凌晨两点被报警电话叫醒,起因就是一台ECS的数据盘使用率到了98%,MySQL写入直接卡死,日志文件疯狂滚动把最后一点空间也吃掉了。那次之后我花了整整一个下午梳理了一套完整的排查和处理流程,后面再遇到类似问题,基本都能在半小时内搞定。今天就把这套方案完整写出来,从排查、清理到扩容、预防,所有步骤都经过实际验证,照着操作你也能处理大部分磁盘告警。

这篇文章适合谁看?如果你是刚接手阿里云ECS的运维新人,或者项目里跑着业务却总担心磁盘突然爆满,那这篇内容值得你花十五分钟读完。我会先教你怎么快速定位空间被什么东西占掉,再给出几种立竿见影的清理手段,然后详细讲清楚在线扩容的正确姿势,最后是防止"磁盘又满了"的监控思路。哪怕你只有基础Linux命令行知识,跟着一步步执行也能操作。

1. 先搞清楚磁盘是真满还是假满

1.1 第一反应不要慌,先看整体状态

收到磁盘使用率过高告警时,我最常看到的现象是:人一着急,直接跑到服务器上随便删文件,结果删了半天使用率纹丝不动。所以第一步不是动手清理,而是把系统的真实状态看清楚。

登录ECS后,先执行两条最基本的命令:

df -h df -i

第一条看的是块设备的使用率,也就是我们日常理解的磁盘空间;第二条看的是inode使用率,这个很多人容易忽略。inode是什么?简单说它是文件系统用来记录文件元数据的存储结构,每个文件或目录都要占用一个inode。如果小文件特别多,可能出现磁盘空间还有剩余,但inode已经耗尽的情况,表现就是明明df -h显示还有空间,却创建不了新文件、报"no space left on device"。

我见过一个实际案例:某台服务器上部署了定时任务,每天生成几万个几KB的小日志文件,跑了大半年,磁盘空间用了60%,但inode使用率到了100%,系统直接拒绝写入。所以看到磁盘告警,先两条命令一起跑,确认是空间问题还是inode问题,方向不对后面的努力全白费。

1.2 用du找出真正的"空间大户"

确认是块设备空间不足后,接着就要定位是哪个目录吃了空间。这里我有一个固定套路:

df -h du -sh /* 2>/dev/null | sort -hr | head -10

第一行先看挂载点情况,确认哪个分区告警;第二行统计根目录下一级目录的大小,把最大的十个列出来。du执行时会读磁盘上所有文件,如果磁盘文件特别多,这个命令可能会跑几分钟,耐心等它跑完,期间不要中断,中断了反而要重新扫。2>/dev/null是屏蔽权限不足的报错信息,避免刷屏。

如果告警的是数据盘,挂载在比如/data目录,那就把第二行命令改成:

du -sh /data/* 2>/dev/null | sort -hr | head -10

这样一层层往下钻,很快就能锁定问题目录。我遇到的情况里,空间被占的大头往往是这几种:应用日志、数据库数据文件、用户上传文件、备份文件、docker容器日志、core dump文件。前三种属于业务真实数据不能乱删,后面的基本都在可以清理的范围。

2. 清理磁盘空间的手段,从安全到激进排序

2.1 日志文件清理的三种姿势

日志是最常见的磁盘杀手,尤其是那些日积月累不打折的nginx访问日志、Java应用日志、系统journal日志。清理方式分三种,我按安全性从高到低排一下。

第一种是清理systemd journal日志,这是系统自身的管理日志。很多服务器跑着跑着,/var/log/journal目录能涨到好几个GB。在CentOS 7或Ubuntu 18.04+系统上执行:

journalctl --vacuum-size=200M

这条命令会把journal日志压缩清理到200MB以内,非常安全,不会影响系统运行。如果你希望以后限制journal日志的最大体积,可以编辑/etc/systemd/journald.conf,找到SystemMaxUse=选项,改成SystemMaxUse=200M,保存后重启systemd-journald服务生效。

第二种是清理应用日志和nginx访问日志。对于应用日志,正确的做法不是直接rm删除,因为如果Java进程还开着那些日志文件句柄,直接删掉文件后磁盘空间并不会释放,这就是很多人觉得"删了日志空间没变化"的原因。我一般用truncate方式清空:

> /var/log/app/app.log # 或者用 truncate -s 0 /var/log/app/app.log

清空后文件大小为0,磁盘空间立刻释放,进程写日志也不受影响。对于老的日志文件,比如nginx的access.log.20240101.gz这类滚动备份,确认不需要了可以删除,或者用find /var/log/nginx -name "*.gz" -mtime +30 -delete只删30天前的压缩日志。

第三种是配置logrotate自动化日志轮转,这才是治本的办法。在/etc/logrotate.d/目录下为应用日志创建配置,比如:

/var/log/app/*.log { daily rotate 7 compress delaycompress missingok notifempty copytruncate }

这段配置的含义是:每天轮转一次,保留7份旧日志,旧日志压缩存储,copytruncate方式适合那些不重新打开日志文件的进程。配置好后可以执行logrotate -f /etc/logrotate.d/app强制测试一次。

2.2 系统包缓存和临时文件

yum、apt这些包管理器在安装软件时会下载很多rpm包或deb包,这些缓存用完之后就躺在那,积少成多也是几个GB的量。

CentOS系统执行:

yum clean all rm -rf /var/cache/yum/*

Ubuntu系统执行:

apt clean rm -rf /var/cache/apt/archives/*.deb

临时目录/tmp和/var/tmp下面的文件也值得看一眼,有些程序运行时会往这里写临时文件,退出后没清理干净。可以查看哪些文件比较大,确认不是正在使用的再删除:

du -sh /tmp/* 2>/dev/null | sort -hr | head -20

还有一类容易被忽略的是core dump文件,进程崩溃时生成的核心转储文件,一个可能就好几个GB。检查系统有没有开启core dump,以及已有的core文件:

cat /proc/sys/kernel/core_pattern find / -name "core.*" -type f -size +100M 2>/dev/null

如果确认不需要分析崩溃现场,直接删除即可,并在/etc/sysctl.conf里加上fs.suid_dumpable=0或调整core_pattern路径限制生成。

2.3 docker日志清理的特殊处理

如果你的ECS上跑着docker容器,那docker日志占用空间的速度可能远超你的想象。docker的日志驱动如果是json-file,默认情况下不会自动切割,一个容器能写几百MB甚至上GB的日志。查看各个容器日志大小:

find /var/lib/docker/containers -name "*-json.log" -exec ls -lh {} \; | sort -k5 -hr | head -10

清理方式有两种。临时方案是清空日志文件:

truncate -s 0 /var/lib/docker/containers/*/*-json.log

治本方案是给docker配置日志轮转,创建/etc/docker/daemon.json,写入:

{ "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } }

这个配置的意思是单个日志文件最大10MB,最多保留3个文件。改完后需要重启docker服务才能生效,注意重启会中断容器,务必要在业务低峰期操作。

2.4 大文件定位与删除决策

清理完上面这些常规项目后,如果使用率还是高,那就必须用工具全盘扫描大文件了。我常用的命令是:

find / -xdev -type f -size +100M -exec ls -lh {} \; 2>/dev/null | sort -k5 -hr | head -30

这条命令会找出根文件系统下所有超过100MB的文件,按大小排序。处理这些文件时要非常谨慎,我的决策逻辑是这样的:扩展名带.log、.tmp、.core的基本可以清理;路径在/tmp、/var/tmp下的基本可以清理;应用目录下的数据文件不要动;数据库目录下的ibd文件绝对不要动,那是数据文件本体。有一个案例我记得很清楚:某个用户自己写的一个导出程序,每次运行都会在/data/export下生成一个几GB的CSV文件,跑了几十次空间就满了。这种情况光删文件不够,得找到生成源,在程序里加上定期清理逻辑。

3. 清洁不掉了,直接扩容

3.1 扩容前必须搞清楚的三种情况

清理完垃圾后使用率还是高,比如数据盘本身容量就小,业务增长又快,那就得扩容了。阿里云ECS扩容操作本身不复杂,但有几个前置条件必须搞清楚,否则会出现"控制台点了扩容但系统里看不到新空间"的情况。

第一种情况:系统盘满了。系统盘扩容在控制台上操作,但有一个前提——系统盘必须是包年包月实例,按量付费的实例不支持直接扩容系统盘。而且系统盘扩容只支持升配,不支持降配,操作前要谨慎确认。

第二种情况:数据盘满了,而且数据盘是单独购买的标准云盘或高效云盘。这种扩容在控制台直接操作就行。

第三种情况:数据盘是随实例创建的,并且数据盘和实例是"同生命周期"的关系。这种盘扩容前,需要先在控制台把云盘从实例上卸载,再执行扩容操作,否则按钮是灰的。这里特别提醒一句:卸载数据盘前,一定要先在服务器内部执行umount命令卸载挂载点,否则数据可能损坏。

3.2 在线扩容完整步骤

阿里云大部分云盘类型支持在线扩容,也就是不停机扩容。操作流程分两大步:控制台扩容、系统内扩展文件系统。

控制台部分的操作路径是:登录阿里云控制台,进入ECS实例列表,点击实例ID进入详情页,找到"云盘"标签页。在目标云盘的操作列点击"扩容",填写期望的容量(比如从40GB扩到60GB)。确认费用后提交工单,扩容任务一般几秒到几分钟完成。注意扩容后的容量需要下一次"重启"或者内部操作后才对系统可见。

系统内部操作才是最关键的。扩容完成后,回到服务器上执行:

df -h lsblk

df -h看到的还是旧容量,因为文件系统还没有扩展。lsblk会显示块设备的真实容量,如果看到/dev/vdb已经是60GB,说明云盘扩容已在底层完成。接下来要扩展分区和文件系统,这里分两种情况。

情况一:云盘只有一个分区,且分区占满整个盘。执行:

growpart /dev/vdb 1 resize2fs /dev/vdb1

growpart命令的作用是把分区扩展到整个磁盘大小。如果没有安装growpart,先执行yum install -y cloud-utils-growpart(CentOS)或apt install -y cloud-guest-utils(Ubuntu)。resize2fs用于扩展ext4文件系统。

情况二:文件系统是xfs。ext4用resize2fs,xfs必须用xfs_growfs,命令是:

xfs_growfs /dev/vdb1 # 如果xfs挂在/data目录,可以 xfs_growfs /data

xfs和ext4在扩容时不能混用命令,我就见过有人用resize2fs去扩xfs文件系统,结果报错说"Filesystem has unsupported feature(s)"。执行完后再次df -h确认,容量应该已经刷新。

3.3 系统盘扩容的额外坑

系统盘扩容相比数据盘多一个步骤:扩容后需要在控制台重启实例,而且系统盘的扩容只能在离线状态下操作,也就是说实例必须处于"已停止"状态。在停止实例前,务必到阿里云控制台确认一下当前实例是不是"节省停机"模式,如果是,停止后可能涉及公网IP变化或磁盘快照计费的变化。我之前在一个生产环境上忘记确认这个,重启后IP变了,一堆白名单和客户端配置全部要改。

系统盘扩容的具体操作:先停止实例,然后在云盘列表里找到系统盘对应的那块盘,点"扩容",输入目标容量。扩容完成后,启动实例,再到系统内执行文件系统扩展。系统盘扩容同样遵循前面的文件系统类型匹配原则,看清楚是ext4还是xfs再动手。

4. 各种疑难杂症与避坑指南

4.1 为什么删除文件后空间没释放?

这个坑我前前后后踩了三次。现象是:你明确删除了一个大文件,文件也确实不在目录里了,但df -h显示使用率一点没降。原因是有一个进程还持有这个文件的句柄,文件被删除了,但进程还在写入或锁定它,占用的空间不会被系统回收,只有进程退出或关闭文件句柄后才释放。验证方法:

lsof | grep deleted

查到持有句柄的进程PID后,确认这个进程可以重启,再执行kill -HUP <pid>或者重启服务。停掉进程后你会发现磁盘空间瞬间就吐出来了。还有一种相对少见的情况:日志文件被删除后,进程重启时又重新创建了新文件,但老文件句柄还在,空间一样不释放。所以处理占用空间的日志文件,优先用truncate而不是rm。

4.2 扩容后在系统里看不到新容量怎么办?

控制台操作扩容成功,lsblk也能看到新容量,但df显示的还是老容量。这种一般是文件系统扩展步骤没执行或者执行失败。排查步骤:

# 1. 确认分区表大小 cat /sys/block/vdb/size # 2. 查看分区信息 fdisk -l /dev/vdb # 3. 重新执行分区扩展 growpart /dev/vdb 1

如果growpart报错"unexpected output",多半分区不是以标准方式开始的,这时需要手动用fdisk删除分区再重建,操作非常危险,非专业人员不建议尝试,直接提交工单给阿里云售后处理更稳。顺便说一句,阿里云工单里面,磁盘扩容这类问题售后支持响应很快,不要不好意思提工单。

4.3 数据盘没分区直接格式化,怎么扩容?

有些用户买完数据盘后直接mkfs整块盘,没有分区(比如直接格式化/dev/vdb而不是/dev/vdb1)。这种情况下growpart无从下手,正确的处理方式是:先扩充云盘容量,然后直接扩展文件系统。对ext4:

resize2fs /dev/vdb

对xfs:

xfs_growfs /dev/vdb

不需要走分区扩展的步骤,因为整块盘就是一个"超级大分区"。这一点很多人不知道,跟着网上的教程非要给无分区的盘做growpart,结果报错才开始找别的路。

4.4 磁盘IO和空间不足的区别

最后补充一个常被混淆的概念:磁盘使用率过高和磁盘IO过高不是一回事。磁盘使用率看的是空间,磁盘IO看的是每秒读写次数和吞吐量。如果空间充足但服务还是很卡,检查IOPS:

iostat -x 3

重点看%util、await、svctm这几列。%util接近100%说明磁盘一直在满负荷运转,这时候扩容反而正确;如果%util不高但await很高,可能是磁盘性能不足或者有随机读写冲突,这种情况要换ESSD或者优化业务读写模式,不是扩容能解决的。查询阿里云控制台上的实例监控,可以看到磁盘IOPS和BPS的历史曲线,判断性能瓶颈很直观。

5. 一劳永逸的监控预防方案

5.1 设置云监控告警

处理完一次磁盘告警后,如果不做监控,下次业务量增长时肯定还会爆。阿里云自带云监控服务,不需要额外部署agent就能采集ECS的磁盘使用率指标。打开云监控控制台,创建告警规则:

  • 告警规则名称:ECS磁盘使用率告警
  • 关联资源:选择你的ECS实例
  • 指标:磁盘使用率
  • 触发条件:使用率超过85%,持续3个周期(1个周期5分钟)
  • 通知方式:邮件+短信+钉钉机器人

阈值我建议设两个:85%为警告,95%为紧急。85%是提醒你开始排查,95%是亮红线提醒你必须马上处理。间隔太短容易误报,5分钟一个周期比较合理,既不会漏掉快速增长的场景,也不会被瞬时波动干扰。

5.2 定期巡检脚本思路

云监控负责实时告警,我还要搭配一个定时巡检脚本,每周跑一次,自动输出磁盘使用Top10目录,发到运维群里。写一个简单的Shell脚本放在/etc/cron.daily/下:

#!/bin/bash echo "===== 磁盘使用情况 $(date) =====" >> /var/log/disk_check.log df -h >> /var/log/disk_check.log echo "===== 目录Top10 =====" >> /var/log/disk_check.log du -sh /home/* /var/* /data/* 2>/dev/null | sort -rh | head -10 >> /var/log/disk_check.log

然后配合钉钉机器人的webhook,把内容推送到群里。这种方式成本很低,但能保证每周都有人注意到磁盘变化的趋势,而不是等到告警响了才被动处理。

5.3 容量规划经验

根据我的经验,数据盘的使用率长期维持在60%以下是比较健康的。超过70%就值得警惕,超过85%基本要在两周内处理,否则遇到业务高峰极易触发写满。如果业务数据增长明显,处理时优先考虑扩容而不是反复清理,因为清理只能解决眼前的问题,业务在增长,磁盘总会被吃完。扩容时有一个小技巧:一次扩容的容量建议至少翻倍或者扩到当前容量的1.5倍以上,不要50GB变55GB这种挤牙膏式扩容,每次都要付人工成本,不如一步到位。

我个人在实际操作中还有一个心得:所有涉及磁盘的操作,特别是删除大文件、扩容文件系统这种,操作前都必须确认快照已经打好或者至少确认备份可用。阿里云控制台给磁盘打快照很快,一个40GB的盘做快照也就几分钟,但万一操作失误,快照就是唯一的后悔药。我见过因为没打快照直接fdisk删分区,最后数据全没了的案例,那种代价远大于几分钟的快照等待时间。

最后说一个很多人不知道的功能:阿里云控制台的"磁盘分析"工具,可以针对每个云盘生成空间分析报告,哪些目录占用大、哪些文件增长快,都看得清清楚楚。这是阿里云售后工程师教我的,比用命令行一个个翻高效得多。处理磁盘问题的第一原则就是"先把情况看清楚再动手",这句话你可能觉得啰嗦,但绝大多数翻车现场都是因为没看情况就乱删东西。先把排查流程过一遍,再根据实际占用来决定清理还是扩容,你的ECS磁盘就不会再频繁亮红灯。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询