ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

阿里云ECS磁盘使用率过高排查:定位、清理与在线扩容实战

阿里云ECS磁盘使用率过高排查:定位、清理与在线扩容实战 运维干了几年最怕半夜收到阿里云的短信告警其中磁盘使用率超过80%这条尤其让人头疼。很多新手同学第一反应是直接扩容结果扩完没两天又满了其实核心问题是没搞明白数据到底是谁占的。这篇文章就把我处理阿里云ECS磁盘使用率过高的一套完整流程写出来从定位分析到在线扩容、日志清理、监控预防全是生产环境实打实的经验适合运维、开发、以及自己折腾服务器的同学参考照着做基本能把水位稳稳控制在安全线以内。1. 磁盘使用率过高的常见场景与初步判断1.1 现象与影响服务器磁盘使用率过高不是小事它不像CPU偶尔飙一下能忍。根分区满了以后最直接的表现是数据库写入报错、临时文件创建失败、日志直接丢数据严重的时候连SSH登录都困难因为登录过程也要写历史记录和临时会话文件。我遇到过最夸张的一次某台ECS磁盘100%满掉应用进程直接hang住重启之后又起不来循环崩溃就是因为系统d目录需要写pid文件但磁盘没有空间。另外要特别注意“磁盘使用率”和“磁盘IO”不是一回事。使用率过高代表存储空间不足IO过高代表读写吞吐跑满了这两个是不同的告警处理方式也完全不同。我们这轮只讨论使用率。1.2 判断思路是数据量大还是文件异常收到告警后先别急着重启或扩容先用脑子想一个关键问题磁盘是慢慢涨上去的还是突然一下就满了如果是慢慢涨大概率是业务数据累积或者日志文件一直在写没有轮转。如果是突然满掉优先怀疑有人上传了大文件、临时目录被灌满、系统生成了巨大的core dump文件或者是某个服务异常写入了超大日志。我处理过的案例里有npm缓存把空间干满的有Docker容器日志json文件膨胀到几十个GB的还有MySQL的binlog没清理导致磁盘爆掉的。这里给你一个初期排查的顺序先看整体容量df -h看哪个分区满了以及总容量多大。再看文件系统inode是否够用df -i如果inode也满了小文件多到爆炸。用du逐层统计目录定位哪个目录最大。用lsof L1查看被删除但仍被进程打开的文件。1.3 排查前的准备工作快照备份与信息收集开始动任何清理动作之前务必先创造磁盘快照。阿里云ECS控制台里左侧菜单找“云盘”选中当前系统盘或数据盘点“创建快照”这个过程不影响线上业务一般几秒钟就能提交。快照是低成本保险万一删错了文件还能原地恢复。同时把当前告警时段记录下来顺手把df -h、df -i、du -sh /的输出保存到一个文本文件。这不是形式主义出现连续告警时这些基线数据能帮你判断清理后空间是否真的降下来了还是说某个进程又在继续写数据。有一次我清理掉30GB日志结果第二天又满了回看当时的df记录才发现根分区在十分钟内涨了5GB于是顺藤摸瓜找到了失控的Java进程。2. 两步定位先用命令查清楚谁占用了磁盘2.1 df与du结合使用找到大头上服务器第一件事不用花里胡哨直接df -h先确认到底是哪个分区满了。很多ECS默认系统盘就40GB数据盘单独挂载在 /data 之类的目录如果系统盘满了而数据盘还很空完全可以通过迁移目录的方式解决而不一定非得扩容。确定分区之后用du逐级往下找。比较快的定位命令du -h --max-depth1 / 2/dev/null | sort -rh | head -20这个命令列出根目录下第一层子目录的大小从大到小排列。看输出你会非常直观地发现到底是 /var、/home、/usr、/root 哪个目录占用超标。注意加上2/dev/null否则一些没有权限的目录会刷出大量错误信息干扰视线。之后逐层进去继续执行同样的du命令比如发现 /var 很大就执行du -h --max-depth1 /var 2/dev/null | sort -rh | head -20如此迭代三四次大头基本就锁定了。这套思路不看监控面板也能精准定位是运维的基本功。2.2 find与大文件排查日志文件特殊处理目录级别定位到大头之后还要找到具体的巨型文件。推荐两个方向我惯用的命令是find / -type f -size 100M -exec ls -lh {} \; 2/dev/null | sort -k5 -rh | head -30这个会找出所有大于100MB的文件并按大小排序显示前30个。看到结果你就清楚是哪个应用、哪个路径下的文件最占空间。日志文件是最常出现的问题源。如果你的ECS装了Docker一定要检查容器日志很多情况是容器长期不重启stdout日志全被写进 host 的/var/lib/docker/containers/id/*-json.log里单个日志轻松上10GB。定位到之后可以临时执行cat /dev/null 文件路径清空但注意不要直接用rm删除因为有些进程还握着文件描述符删了空间也不一定释放后面第5节详细说。正确的长期方案是配置日志轮转控制单个日志文件大小和保留份数。2.3 inode耗尽问题与排查除了容量满还有一种隐蔽的“磁盘满”其实是inode耗尽。df -h 看容量还剩好几个GB但df -i 显示/目录 inode 100% 已用应用一样会报“No space left on device”。这种情况常见于小文件极多的目录比如邮件队列、缓存目录、PHP会话文件、Docker容器层文件等。排查时用df -i for d in /*; do echo -n $d: ; find $d -xdev | wc -l; done 2/dev/null统计每个一级目录的文件数量文件数量最大的就是问题目录。处理inode耗尽没有捷径只能删除废旧的小文件或者重新规划把文件移到容量更大的磁盘并换用支持更多inode的文件系统。阿里云默认的ext4在格式化时其实已经根据磁盘大小设置了足够的inode数量绝大多数情况是业务本身制造了百万级小文件属于设计问题建议从应用层根治比如把文件存储切换到对象存储OSS而不是无脑扩充inode。3. 在线扩容云盘扩容的正确打开方式3.1 扩容前需要确认的几件事清理之后如果空间依然紧张或者业务增长趋势明确扩容是最终解法。阿里云ECS的云盘扩容非常成熟基本支持在线扩容不需要停机。但有多件事必须提前确认踩过坑的同学都懂第一确认当前ECS实例本身支持在线扩容。大部分新一代规格都支持部分老规格可能只支持离线扩容控制台如果提示不支持就老老实实先停机再操作。第二确认云盘类型。高效云盘、SSD云盘、ESSD云盘基本都支持按需扩容但不同地域的步长可能不同有的按1GB递增有的按整量级递增下单前看一下费用变化就好。第三也是最重要的扩容前一定要观察数据盘的分区方式是MBR还是GPT。MBR分区最大只支持2TB如果你当前数据盘已经是MBR扩容量一旦让总容量超过2TB就必须先改成GPT这个操作非常麻烦可能需要数据迁移。所以创建数据盘时如果能选GPT尽量直接选GPT省得后面折腾。3.2 控制台扩容量与分区扩容步骤在控制台的操作路径很简单云服务器ECS → 实例 → 磁盘 → 找到目标云盘 → 点“扩容” → 输入目标容量 → 支付。这一步只是把云盘的底层容量变大操作系统里的分区和文件系统还需要手动扩展很多第一次操作的同学就是卡在这里说扩容了但df看到的大小没变。Linux系统的后续操作分两段一是分区扩容二是文件系统扩容。如果数据盘当初是一整块分区占满全盘直接执行growpart扩展分区再resize2fs扩展文件系统。举例数据盘是 /dev/vdb1挂载在 /data# 安装growpart工具不同发行版包名不同CentOS用 cloud-utils-growpart yum install -y cloud-utils-growpart # 查看分区情况 lsblk # 扩展分区 growpart /dev/vdb 1 # 扩展文件系统ext4用resize2fsxfs用xfs_growfs /data resize2fs /dev/vdb1如果是系统盘扩容思路一样但根分区在线扩容时尽量保持系统负载较低防止元数据更新期间出现问题。扩容完成后df -h就能看到新容量。3.3 扩容后文件系统是否自动扩好的判断很多用户用的是自动扩容工具或者买了包含“云助手”功能的镜像阿里云在某些镜像里会自动执行扩容脚本但不要迷信这一点以df -h输出为准。如果发现容量没变手动执行一次上面的命令即可不会丢数据。这里特别提醒resize2fs必须在分区已经扩大的前提下运行不要顺序搞反。我曾经遇到一位用户直接对原分区执行resize2fs结果报错说设备忙他还以为失败了后来发现他的分区本身就是整盘分区不需要growpart直接resize2fs /dev/vdb1就行。所以操作前一定先lsblk看清楚磁盘结构和分区号。4. 清理与治理从数据面把使用率真正降下来4.1 日志轮转与定时清理扩容只能解决一时之痛日志不轮转扩多少都能给你写满。Linux自带的logrotate是最方便的轮转工具配置文件一般在/etc/logrotate.d/。以Nginx日志为例我一般这样配/var/log/nginx/*.log { daily rotate 7 missingok notifempty compress delaycompress create 0640 nginx nginx sharedscripts postrotate /bin/kill -USR1 $(cat /var/run/nginx.pid 2/dev/null) 2/dev/null || true endscript }这段配置的意思是每天轮转一次保留最近7天的日志超过的自动压缩并清理最老的。注意postrotate里的信号一定要写对Nginx需要USR1重新打开日志文件否则轮转后继续往旧文件里写等于没轮转。Docker容器日志则建议在/etc/docker/daemon.json里配置全局限制{ log-driver: json-file, log-opts: { max-size: 100m, max-file: 3 } }然后重启Docker使配置生效。注意这个配置只对之后新建的容器生效已有容器要 recreate 才会应用。4.2 临时目录与缓存文件清理系统的 /tmp、/var/tmp 也是垃圾重灾区。有些程序异常退出后会在 /tmp 留下几百MB的临时文件还有一些下载上传的临时切片文件。建议在crontab里加一条每天凌晨清理超过3天未访问的临时文件find /tmp -type f -atime 3 -delete 2/dev/null这条命令我用了很多年基本没出过问题。但有个坑要提醒如果服务器上有正在运行的长时间任务比如视频转码的临时文件atime超过3天但任务还没结束删除会导致任务异常所以执行前最好确认业务没有低频写入 /tmp 的进程。稳妥起见也可以把范围缩小到/tmp/xxx这种专用子目录。另外包管理器缓存也很占空间。CentOS的yum缓存、Ubuntu的apt缓存安装大量依赖后可能有几个GB。定期清理yum clean all apt-get clean还有pip和npm的缓存目录~/.cache/pip和~/.npm/_cacache用户目录下积攒多了也很可观清理时不会影响已安装的包。4.3 数据库与备份文件归档策略生产环境的ECS上多少都跑着数据库MySQL的binlog是特别常见的磁盘杀手。如果不需要基于时间点的完整恢复就不要长期保留binlog可以在MySQL配置里设置过期时间[mysqld] expire_logs_days 7MySQL 8.0以上建议用binlog_expire_logs_seconds 604800。已经积累的binlog用PURGE BINARY LOGS BEFORE NOW() - INTERVAL 7 DAY;手动清理。同样逻辑适用于MongoDB的journal和PostgreSQL的WAL长期不清理都会让磁盘使用量线性上涨。业务备份文件也要养成好习惯本地备份保留最新的2份就够了历史备份全部挪到阿里云OSS。用ossutil写一个定时同步脚本比如每天凌晨把本地备份目录 sync 到OSS然后删除本地超过3天的文件。OSS按量计费比数据盘便宜得多还能额外拿到跨区域容灾能力。5. Linux/Windows系统特有的“坑”与处理5.1 Linux误删文件后空间未释放这是一条高频问题明明rm -rf 大文件了但df -h看到空间一点没变。原因是文件被某个进程打开着删除的只是目录项文件本身还被进程的文件描述符引用着空间自然不释放。我见过最典型的场景是删Nginx日志后Nginx进程不重新打开文件磁盘空间死活不降。排查命令lsof L1找出 deleted 状态且被进程持有的文件。处理办法有两种要么重启对应进程让文件描述符释放要么通过/proc/pid/fd/fd方式清空文件: /proc/pid/fd/fd但这属于比较侵入式的操作生产环境建议先重启服务如果服务不便重启可以用清空的方式顶一下之后找业务低峰期重启。另外教训是大日志文件不要直接rm用cat /dev/null file清空才是正道。5.2 Windows Server磁盘管理中的初始化与分区Windows Server的ECS同样会遇到磁盘满和“磁盘必须经过初始化逻辑磁盘管理器才能访问”的提示。这个提示一般出现在新挂载了数据盘但还没初始化时。Windows上操作最简单右键“此电脑” → “管理” → “磁盘管理” → 找到未初始化的磁盘 → 右键“初始化磁盘”磁盘分区类型选择GPT然后新建简单卷分配盘符格式化。注意格式化时文件系统选NTFS分配单元大小保持默认就好。很多时候Windows C盘满了常见的占用大头是系统更新缓存、Windows.old目录、用户临时文件。可以搜“磁盘清理”选择清理系统文件能快速清掉 Windows 更新留下的旧版本。对于C盘空间实在不够的情况思路和Linux一样把users目录或某些应用的数据目录迁移到D盘用目录符号链接mklink /J实现无缝迁移。5.3 虚拟化环境磁盘扩展后的识别问题阿里云ECS本身是云盘扩容后直接lsblk能看到新容量。但如果你是在本地虚拟化环境比如VMware、KVM里用阿里云镜像装的系统虚拟机磁盘扩容后Windows和Linux都可能“看不到”新空间。Windows的处理是到磁盘管理里右键分区选择“扩展卷”Linux则需要重新扫描SCSI设备echo 1 /sys/class/scsi_disk/0:0:0:0/device/rescan然后再lsblk确认容量识别到继续走growpart和resize2fs流程。这个坑非常多同学踩过总以为是系统坏了其实就是虚拟机没重新扫描磁盘。6. 预防监控与常见问题速查6.1 监控告警设置磁盘使用率处理的最高境界是让它在发生之前就被处理掉。阿里云ECS自带云监控默认就有磁盘使用率监控但很多同学没设置阈值等于没有。建议在云监控控制台创建自定义告警规则磁盘使用率超过70%就发钉钉或短信告警超过85%提升告警级别。给一个我自己的参考阈值级别阈值建议动作预警磁盘使用率 70%观察趋势安排时间排查告警磁盘使用率 85%立即登录定位必要时扩容紧急磁盘使用率 92%业务面临写入风险立刻处理有人觉得70%就告警太敏感其实对于没有批量清理机制的服务器从70%涨到100%可能只要一两天提前预警才有缓冲窗口。6.2 常见问题与排查技巧速查表以下是我这几年处理磁盘问题的高频清单直接收藏当速查表用现象可能原因优先处理方案df -h显示满但du看不出大文件被删除文件仍被进程占用lsof L1 定位进程重启服务df -h有空间但应用报磁盘满inode耗尽df -i确认删除小文件/var目录持续膨胀系统日志或容器日志无限增长配置logrotate和docker日志限制扩容后df容量没变化分区/文件系统未扩展growpart resize2fs动手扩系统盘满数据盘空应用数据默认写在系统盘迁移目录到数据盘并用软链数据盘刚挂载无法访问磁盘未初始化/未格式化Windows磁盘管理初始化Linux mkfs后挂载每一条我都亲手处理过至少一次不是从文档里抄的。尤其是第一条最容易让人怀疑人生明明du显示就那点文件df却说满了。6.3 个人经验磁盘水位怎么定更合理根据我个人经验给所有ECS用户一个非常实用的建议不要把磁盘规划得“刚刚好”。系统盘至少留20%余量数据盘也尽量保持30%以上空闲因为数据库临时排序、应用缓存、日志峰值都是不可预测的。与其在磁盘97%满的时候手忙脚乱处理不如在60%的时候花十分钟写一个脚本。我知道很多人会觉得大磁盘费钱但算一下宕机损失和半夜加班的时间成本就知道这个钱花得值。最后再分享一个小技巧处理完每一次磁盘告警后花一点时间把根因、清理命令、结果写成一段笔记。阿里云控制台里其实有操作审计日志但那只记录操作不记录原因。我自己有一个本地文档记录了每次磁盘问题的关联进程、目录和命令几乎每次都第一个推荐给同事。磁盘问题的本质都是“某个目录的数据增长超出预期”只要把增长源找到清理和扩容都是辅助手段这个思路比任何一条命令都重要。
返回列表