收到告警平台的推送时,我正在处理另一台设备的性能报表。PowerStor500T,根目录空间使用率超过96%。第一反应不是慌,而是疑惑,因为上个月刚巡检过,这台设备的数据池余量还很充足。带着这个反差感,我登录管理界面看了一眼,存储池正常,再SSH进后台df -h一看,根分区确实岌岌可危。无论你是存储运维、系统工程师,还是被同样告警困扰的同行,这篇复盘应该能省下你不少弯路。
这种"管理界面很好看、后台却要爆了"的问题,在存储设备上不算罕见,但处理起来很讲究。我这次从收到告警到定位根因、清理恢复、再到布置预防机制,走了完整的排查链路。下面把整个过程拆开讲清楚,尤其是几个容易让人绕远路的环节。
1. 告警反差现场:数据池还有大量空闲,根目录却濒临写满
1.1 管理界面显示的是"数据池",和系统根目录是两套体系
PowerStor500T这类企业级存储,硬件结构上其实分成两个完全独立的部分:一个是承载用户数据的磁盘阵列/存储池,容量通常几百TB;另一个是系统盘,一般由两块SSD或SATA DOM组成镜像,容量只有几十GB,用来放操作系统、数据库配置、日志、告警库等。管理界面里的容量条显示的是数据池,后台df -h显示的是系统盘根分区。很多人被"存储池还剩一大半空间"误导,以为告警是误报,恰恰是因为没意识到这是两套体系。
我当时在管理界面上看到的数据池使用率只有40%左右,看起来非常健康。但进入SSH后台执行df -h之后,/dev/root挂载的/分区确实已经到了96%,可用空间只剩几GB。也就是说,报警不是误报,只是管理界面的监控维度没有覆盖到系统分区——很多存储设备的默认监控面板只展示数据池,系统盘的告警要单独立项。
提示:遇到存储设备报"根目录空间高",不要先用管理界面判断是否误报。先SSH进后台,用df -h确认系统盘真实水位,再谈下一步。
另外,系统盘的容量设计本来就偏保守。它不需要为数据增长预留大量空间,只要保证操作系统、配置和日志的正常运转即可。所以根目录的使用率变化,本质上和"存了多少用户数据"没有关系,只和"系统自身运行产生了多少文件"有关系。这也是为什么存储池再空闲,也左右不了根目录告警。
1.2 96%不是"还有4%":系统分区写满的现实后果
系统分区被写满的后果是渐进的。最先受影响的一般是日志写入——系统日志服务发现磁盘空间不足,会停止写入或降级;接着是配置变更,比如修改网络参数、创建快照策略、升级固件,这些操作都要在系统分区写入临时文件和数据库记录,空间不足直接报错;再往后,告警通知本身也可能因为待发送的邮件或SNMP trap队列积压而卡住,造成"存储明明告警了,但通知发不出来"的尴尬局面。极端情况下,某些服务会异常重启,形成更复杂的问题。
所以遇到96%这个水位,我的建议是:把优先级提到"需要当天处理、但不用慌到立刻停业务"的档位。如果设备正在执行重要任务(如RAID重建、数据迁移),先评估清理动作会不会影响这些任务;如果没有,就可以按下面章节的排查流程一步步走。切忌一上来就rm -rf某个目录——系统分区的文件和用户数据分区不一样,乱删可能直接把系统搞到起不来。
注意:处理前,先确认系统盘是否还有安全余量可以撑住清理过程中的临时写入。如果可用空间已经低于1GB,优先清理/tmp和日志,先"挤出"一点空间再继续排查。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 根目录为什么会被塞爆:三个最典型的"元凶"画像
2.1 日志异常增长:故障期最容易忽视的头号嫌疑
存储设备的日志体系比我最初想象的复杂得多。系统日志、内核日志、磁盘巡检记录、审计日志、各种组件的调试日志,平时各自安静地写在/var/log下,一天可能也就几十MB。但是一旦出现磁盘错误、RAID降级、硬盘拔插、卷扩容这类"故障性事件",日志量会指数级增长。我之前处理过一台设备,一块硬盘反复掉线又上线,两天时间里/var/log下面光是链路相关的日志就长了几十GB,直接把根分区逼到95%。
为什么会涨这么多?一方面,很多存储组件的日志级别是"动态调整"的,检测到异常后会自动把日志调成debug级别,方便工程师后续分析;另一方面,一些重复报错会在同一秒钟内写好几条,循环刷屏。正常情况下这个细节不会引起注意,但恰恰是这类故障期日志,最容易在空间告警时成为"隐形杀手"。
2.2 升级包、临时文件与核心转储的残留堆积
第二个典型问题是"一次性文件"没有及时清走。固件升级包通常有1到2GB,很多升级流程会把压缩包解压到系统分区下的临时目录里,比如/var/tmp或者专门的升级目录。如果升级流程正常走完,这些文件会被自动清理;但如果升级中断、校验失败、或者某个进程卡住,残留文件就会一直躺在那里。
临时文件目录也有类似情况。存储设备上的/tmp或/var/tmp,经常被各组件用来放下载缓存、会话文件、导出报表。某些导出任务如果失败,会产生不完整的临时文件,占空间但没人管。还有核心转储(core dump)文件,一般出现在/var/crash或类似目录,一次内核异常转储就可能产生几百MB甚至几GB的文件,如果系统配置了"保留现场"策略,这类文件会被长时间留存。
2.3 被删除却"仍然占用"的文件:空间不释放的假象
这类问题最迷惑人。某个大文件确实被删了,ls和du都看不到它,但df显示的已用空间纹丝不动。原因是:某个进程还持有这个文件的打开句柄。Linux/Unix的文件删除机制是"标记删除",真正回收空间要等所有打开该文件的进程都关闭句柄之后。在存储设备上,某些后台服务长时间不重启,文件句柄就一直挂着,空间也就一直占着。
我见过一个新手运维在类似问题上栽过跟头:他以为删除没成功,反复清理,甚至把同一个目录下其他文件也误删了几次,最后发现根本原因是某个服务还开着句柄。所以排查时,除了看哪些文件大,还要专门检查"deleted但被占用"的文件。后面的命令链路里会专门演示这一步。
3. 从96%到定位元凶:完整的SSH排查命令链路
3.1 先看挂载点:df -h 怎么读才不会被误导
登录后台后,我习惯先跑一条df -h,把整体挂载情况看一遍。我的目标是确认三件事:报警挂载点是否就是系统根分区;该分区剩余空间到底还剩多少;数据池挂载点是否正常(用于对比,确认用户数据没受影响)。
输出大概长这样:
bash复制Filesystem Size Used Avail Use% Mounted on
/dev/root 47G 45G 2.1G 96% /
tmpfs 5.8G 4.2M 5.8G 1% /dev/shm
/dev/dsdata 480T 188T 292T 40% /data
这里有个反直觉的地方:/dev/root的大小显示47G,而数据池是480T,两者天差地别。所以"存储池还有60%空间"对根目录告警没有任何缓解作用,因为它们根本不在一个文件系统里。同时可以看到根目录可用空间只有2.1G,这个余量非常紧张,意味着清理过程中要避免产生大量临时写入,比如解压、复制等操作尽量别放在根目录下进行。
另外注意,有的设备根目录可能显示为overlay、/dev/mapper/xxx等,不用被名字绕晕,只要挂载点是/,就统称为"系统根分区"。如果设备启用了快照或overlay文件系统,清理时还要考虑底层存储层。不过PowerStor500T这套设备比较直白,根目录就是普通分区,处理起来相对简单。
3.2 逐目录扫描:用 du 递归找出真正的"空间大户"
df确认水位后,下一步是定位空间占在哪里。我用的是:
bash复制du -x -h --max-depth=1 / 2>/dev/null | sort -rh | head -20
解释一下参数:-x限制在根文件系统内统计,不会跨到/data这类数据池挂载点,免得把几百TB的数据池也扫进来;-h以人类可读方式显示;--max-depth=1只统计第一级子目录;sort -rh按大小排序,从大到小。这条命令的输出直接告诉我该去哪个子目录深挖。
我当时看到的结果里,/var和/usr排在最前面。继续往下钻:
bash复制du -x -h --max-depth=1 /var 2>/dev/null | sort -rh | head -20
很快发现真正的"大头"集中在/var/log。/usr目录虽然也不小,但那是系统安装本来就占用的空间,不是"异常增长"。真正的排查重点是那些"应该小却很大"的目录。
这里我想强调一下"基线意识":平时系统正常时,最好记录一次"各目录空间基线"。我这个习惯是后来养成的——没有基线,排障时很难判断当前数字是否异常。建议大家在存储设备稳定运行期间,手动跑一次上面的du命令,把结果存到本地,将来排障就是现成的对照组。
3.3 揪出在写的进程和挂起的文件句柄
锁定/var/log后,我进一步列出了里面最大的几个文件:
bash复制du -x -h /var/log 2>/dev/null | sort -rh | head -10
结果发现某个组件的审计日志文件已经超过20GB,而且还在增长。到这里先不要急着删,先看看有没有进程正在写它。我用的命令是:
bash复制lsof +L1 /var/log 2>/dev/null
+L1表示只列出"已被删除但仍然被进程占用"的文件,这是排查空间不释放的关键。同时用lsof定位正在写日志的进程:
bash复制lsof /var/log 2>/dev/null | grep -E 'audit|systemd|log'
在我这次处理的现场,审计服务和日志轮转进程都开着同一个日志文件。这解释了为什么直接删文件不靠谱——进程还握着句柄呢。我把"目录 + deleted句柄 + 在写进程"三者的对应关系理清楚后,才算真正定位了元凶。
顺带提一个排查思路:很多人习惯于"看到大文件就删",但更专业的方式是"先看到底是谁在写、为什么写"。删除只是止损,不搞清楚写入源头,空间很快又会涨回来。我这次就是因为先找到了"某个组件的审计日志在持续膨胀",才没有陷入"删了又满、满了又删"的循环。
4. 清理动作拆解:截断、归档与安全删除的边界
4.1 日志文件:宁可截断也不要直接删除
对正处于写入状态的日志文件,我的首选是截断,而不是删除。截断的意思是把文件内容清空,但保留文件本身和进程的文件句柄:
bash复制truncate -s 0 /var/log/xxx/audit.log
或者用更保守的方式:
bash复制cat /dev/null > /var/log/xxx/audit.log
这样做的好处是进程可以继续写入,不会被"文件不见了"干扰;空间立刻释放;风险极低。如果直接rm删除,进程仍然拿着句柄写入,空间不会释放,要等进程重启或服务重启;有些组件还会在文件被删除后反复重建同名文件,但那已经是新的句柄,旧句柄占用的空间依然存在,反而更难清理。
对于已经轮转过的历史日志(比如以日期或序号结尾的.gz,或.old后缀的日志文件),删除没有句柄占用问题,可以放心清。清理逻辑一般按时间:
bash复制find /var/log -type f -name "*.gz" -mtime +30 -delete
如果担心误删,可以先移到数据池里留档,确认设备运行正常后再从数据池里手动清理。我自己的习惯是:能留档的先留档,特别是那些可能用于故障分析的审计日志,不要一删了之——否则下次排查时没有日志可用,反而更被动。
4.2 升级残留与临时文件:先确认状态再动手
清理升级残留前,先确认当前没有正在进行的升级任务。我一般会用管理界面或后台命令看看升级锁文件是否存在,比如:
bash复制ls -l /var/upgrade/lock 2>/dev/null
如果锁文件存在且有进程占用,说明可能有升级或校验任务正在跑,这时候清理要格外谨慎。确认没有任务后,残留的升级包和解压目录就可以删除了。临时文件目录的清理相对安全,但也要有个度——我习惯只清理超过7天以上没更新的临时文件:
bash复制find /var/tmp /tmp -type f -mtime +7 -delete 2>/dev/null
不建议无差别清空/tmp,有些组件会在系统分区放"运行时临时套接字或PID文件",虽然不大,但删掉可能导致服务状态异常。同样,core dump文件如果确认对应的问题已经处理完,可以直接清理;如果拿不准,可以压缩后挪到数据池存放。压缩的好处是保留现场,同时不占系统盘空间。
4.3 空间释放后的验证与告警解除
清理完成后,需要一项一项验证,而不是只看df的数字降下来了就觉得完事。我的验证顺序是:
bash复制df -h /
确认根分区使用率降到安全区间(比如60%以下),同时留出足够余量。然后检查这几次清理是否影响了正在运行的服务——看看管理界面能不能正常刷出页面、告警平台有没有新增的系统服务异常项、系统日志里有没有新的"空间不足/IO错误"类报错。如果一切正常,告警会在下个采集周期自动恢复;有些平台需要手动确认告警,也顺手处理一下。
这次清理完,我的根分区从96%降到了42%,释放了约25GB。这个数字没有什么统一标准,纯粹是"元凶文件有多大,就能回收多少"。只要降到75%以下,就算进入安全区间。剩下的治理动作,才真正决定这台设备未来几个月还会不会再次告警。
5. 事后治理:轮转策略、分级告警与巡检脚本
5.1 让日志轮转成为系统自动行为
清理只是止血,要让根目录长期健康,必须把"日志轮转"变成系统自己的自动行为。PowerStor500T这类存储设备,底层还是Linux系统,通常自带logrotate。关键是把规则配置到位。我改的是系统日志的轮转策略,主要调了两个参数:按大小轮转(比如超过500MB就轮转),以及保留轮转份数(比如保留7份)。
对于使用systemd-journald来管理日志的设备,还需要限制journal日志的体积上限:
bash复制journalctl --vacuum-size=500M
或者写入配置:
bash复制SystemMaxUse=500M
这里要注意,修改轮转参数后,最好手动触发一次轮转验证效果:
bash复制logrotate -vf /etc/logrotate.d/xxx
确保轮转正常,生成的归档文件能按预期压缩和清理。别等到下次告警时才发现配置写错了、轮转没跑起来。
5.2 告警阈值分级:别等96%才收到通知
这次告警提示是96%,但理想情况下,根目录使用率根本不该走到这一步。我的建议是把告警做成多级分层的:
| 阈值 | 级别 | 处置动作 |
|---|---|---|
| 75% | 提示 | 记录日志,安排一次常规巡检 |
| 85% | 警告 | 当天排查,定位增长点 |
| 92% | 严重 | 立即处理,必要时清理临时文件 |
具体阈值可以根据设备系统盘的实际容量微调——系统盘只有30GB时,75%就已经很紧张;如果系统盘有80GB,75%还可以再观察。重点是让告警平台在"问题还可以从容处理"的阶段就通知到人,而不是等到96%这种火烧眉毛的档位才介入。告警渠道方面,能接邮件、SNMP trap就都接上,有条件的话再接入统一监控平台,短信或IM通知按团队习惯配置。
5.3 巡检脚本与后续几个月的稳定性观察
治理的最后一步,是建立固定的巡检机制。我没有引入复杂的监控系统,就用了每天定时执行的shell脚本,逻辑很简单:跑一次df -h,解析根分区使用率,超过阈值就发通知。脚本本身不复杂,核心就是"防呆"——避免把根目录检查遗漏在人力巡检之外。
脚本的一个简化示例:
bash复制#!/bin/bash
THRESHOLD=75
USAGE=$(df -h / | awk 'NR==2 {print $5}' | tr -d '%')
if [ "$USAGE" -ge "$THRESHOLD" ]; then
echo "PowerStor root partition usage: ${USAGE}%" | mail -s "Storage Root Space Warning" ops@example.local
fi
实际生产里还可以把脚本挂到计划任务里,每天上午八点跑一次。这台设备处理完之后,我连续观察了几个月:根分区使用率稳定在40%-55%之间,没有再次出现异常增长。日志轮转正常工作,升级残留也会每个月顺手检查一次。
最后分享一点个人体会:存储设备的"根目录告警"和"数据池告警"是完全不同类型的故障。数据池告警常常伴随业务容量的紧张,属于明面上的问题;根目录告警更像"后院着火",平时看不见、不影响业务,但真到了系统盘写满的那一刻,可能连告警都发不出来了。处理这种问题,第一步不是删文件,而是搞清楚空间被什么、被谁、为什么占用。把这条路径走通,96%这种告警就再也不会让你手忙脚乱了。
