我的服务某天凌晨突然全线崩溃、各种写入都报错,登上去一看磁盘被日志撑到了 100%,我对着这个被日志活活塞满的硬盘排查了大半天的复盘

我的服务跑了大半年稳如泰山,某天凌晨突然全线崩溃:写文件、写数据库全失败,SSH 登录都卡。登上去 df -h 一看磁盘 100%、一字节不剩。du 一路找下去发现是日志目录占了 45G、单个 app.log 就 43G——我的服务一直往同一个日志文件追加、从没配过日志轮转和清理,一个文件写了大半年只增不减,终于撑爆磁盘;而磁盘一满,应用写日志、数据库写 redo/binlog、系统写临时文件、SSH 写会话文件全部失败,整个系统被一个日志文件拖垮。这篇从持续增长的数据为何是定时炸弹讲起,到 logrotate/日志框架轮转+只留N份/总量上限的清理+磁盘水位告警+控制日志源头的正解、磁盘满了用 truncate 而非 rm 与 lsof grep deleted 不释放的坑、logrotate 关键选项对照、其他会撑爆磁盘的东西、一个巡检告警小脚本,以及那句最戳心的——系统常不是被高深难题打败,而是被"磁盘会满"这种朴素到被忽略的基础资源问题悄悄拖垮,把简单的基础做扎实才是稳定之道。

我的服务某天凌晨突然全线崩溃、各种写入都报错,登上去一看磁盘被日志撑到了 100%,我对着这个被日志活活塞满的硬盘排查了大半天的复盘

这是一个让我对"日志也会要命"刻骨铭心的故事。我有一个线上服务,跑了大半年,一直稳如泰山。可某天凌晨,监控突然疯狂告警:服务全线崩溃,各种操作都开始报错——写文件失败、写数据库失败、甚至连日志都写不进去了。我赶紧 SSH 登录上去排查,结果连登录都格外卡、命令半天没反应。好不容易进去,df -h 一敲,我的血压瞬间飙升:这台机器的磁盘,使用率 100%,一个字节都不剩了!

我顺着"磁盘满了"这个线索一路 du 下去,才终于揭开真相,补上了我运维知识里一个低级、却极其致命的漏洞:问题的核心,是我的服务,把磁盘用日志活活塞满了。我一直想当然地以为,"日志嘛,写就写呗,能占多大地方";可真相是:我的服务,一直在往同一个日志文件追加写日志,却从来没有配置过任何"日志轮转(log rotation)"和"清理"机制。于是,这个日志文件,在过去大半年里,只增不减、一刻不停地、单调地膨胀,从几 MB,长到几 GB,再到几十 GB……终于,在那个凌晨,它把整块磁盘的最后一点空间,也吃光了磁盘一满,灾难就是全方位:因为几乎所有的操作,本质上都需要"写磁盘"——服务要写自己的日志、数据库要写数据和它自己的日志、系统要写临时文件、甚至你 SSH 登录,都需要写一些会话文件;当磁盘一个字节都没有时,这一切"写"的操作,全都失败,于是服务崩溃、数据库罢工、登录卡顿——整个系统,被一个小小的、不起眼的日志文件,彻底拖垮我这才痛彻地明白:日志,是排查问题的命脉,但失控的日志,本身就是一场灾难;任何会持续写入的文件(日志、临时文件、上传文件……),如果没有配套的"轮转"和"清理"机制,就等于在磁盘上埋下了一颗"迟早会爆"的定时炸弹。运维一个服务,不仅要让它"跑起来",更要管好它产生的每一份会增长的数据,确保它们不会无限膨胀、吃光本就有限的磁盘资源。"磁盘会被写满",是每一个工程师,都必须时刻警惕的、最朴素也最容易被遗忘的风险。

故障现场:日志只增不减,把磁盘吃到 100%

我把这个"磁盘塞满"的现场,摊开给你看:

# ✗ 灾难: 日志只写不清, 磁盘被撑到 100%, 全线崩溃

# 现象: 服务全线报错, SSH 登录卡顿
df -h
#   Filesystem      Size  Used Avail Use% Mounted on
#   /dev/vda1        50G   50G    0  100% /          ← ✗ 100%! 一字节不剩

# 顺藤摸瓜找谁占的(从根目录往下逐层 du):
du -h --max-depth=1 / | sort -rh | head
#   45G    /www/wwwroot/myapp/logs        ← ✗ 日志目录占了 45G!
du -h /www/wwwroot/myapp/logs/* | sort -rh | head
#   43G    /www/wwwroot/myapp/logs/app.log  ← ✗ 单个日志文件 43G!!

# 根因: 服务一直往 app.log 追加, 从不切割/清理
#   - 没配 logrotate, 没按大小/时间切割。
#   - 一个文件写了大半年 → 只增不减 → 撑爆磁盘。

# 为什么磁盘满会"全线崩溃"?
#   - 几乎所有操作都要写磁盘:
#     * 应用写日志 → 失败 → 可能抛异常甚至崩溃。
#     * 数据库写数据/redo/binlog → 失败 → 拒绝写入(只读/报错)。
#     * 系统写临时文件、SSH 写会话文件 → 失败 → 各种诡异。
#   → 磁盘满是"基础设施级"故障, 影响面极广。

# 更坑的: 删了大日志文件, df 却没释放空间?
#   - 若有进程还"打开着"那个被删的文件, 空间不会立刻释放!
#   - lsof | grep deleted 找到它 → 重启/truncate 该进程的文件句柄才释放。

# 根因: 持续写入的日志无轮转无清理, 单调膨胀, 最终吃光磁盘 → 写操作全失败 → 全线崩。

看着 df -h 里那个刺眼的 100%du 出来的 43G 的单个日志文件,我才算彻底想明白了这场全线崩溃的根源。问题的核心,是我的服务一直往同一个 app.log 追加写日志,从不切割、从不清理——没配 logrotate、没按大小/时间切割,一个文件写了大半年,只增不减,终于撑爆了磁盘为什么磁盘满会导致"全线崩溃"?因为几乎所有操作都要写磁盘:应用写日志失败(可能抛异常甚至崩溃)、数据库写数据/redo/binlog 失败(拒绝写入、变只读或报错)、系统写临时文件和 SSH 写会话文件失败(各种诡异、登录卡顿)——磁盘满是"基础设施级"的故障,影响面极广这里还有个极坑的细节:删了大日志文件,df 却可能不释放空间——如果还有进程"打开着"那个被删的文件,空间不会立刻释放;得 lsof | grep deleted 找到它,重启或 truncate 该进程的文件句柄才释放。归根结底:持续写入的日志无轮转、无清理,单调膨胀,最终吃光磁盘,导致写操作全失败、全线崩溃——这,就是根源。

第一件事:搞懂"持续增长的数据"为什么是定时炸弹

定位到根源,我必须把"磁盘为什么会被写满、该怎么防"从根上彻底搞清楚:

磁盘是有限的; 任何"持续增长且不清理"的数据, 终将撑爆它

# 核心矛盾: 磁盘空间有限, 但很多数据会"持续增长"
#   - 日志: 每条请求都可能写, 7x24 不停 → 增长最快、最易失控。
#   - 上传文件 / 用户数据 / 缓存文件 / 临时文件 / 数据库 binlog。
#   - 监控/链路追踪数据、core dump、备份文件。
#   → 任何"只写不删"的, 都是定时炸弹。

# 日志为什么是头号杀手?
#   - 写得最频繁(每个请求、每个错误都写)。
#   - DEBUG 级别 / 打印大对象 / 循环里打日志 → 暴增。
#   - 一个异常风暴(疯狂报错刷栈)能几小时写满磁盘!

# 磁盘满的连锁反应(为什么这么致命):
#   - 应用、数据库、系统都依赖"写磁盘" → 全部受影响。
#   - 数据库可能进入只读 / 拒绝写 → 业务直接挂。
#   - 有时还会数据损坏(写到一半空间没了)。

# 防范的三道防线:
#   1. 轮转(rotate): 按大小/时间切割日志, 别让单文件无限大。
#   2. 清理(retain): 只保留最近 N 份/N 天, 旧的自动删除/归档。
#   3. 监控告警: 磁盘用到 80%/90% 就告警, 在满之前介入。

# 关键认知: "磁盘会满"不是小概率, 是必然 —— 只要你不主动管理增长的数据。
#   - 上线一个服务, 就要同时规划好它"产生的数据怎么不撑爆磁盘"。

# 核心: 磁盘有限, 日志等持续增长的数据不轮转不清理终将撑爆磁盘、引发全线崩;
#   必须做轮转+清理+监控告警三道防线。

原理终于清晰了。核心矛盾是:磁盘空间有限,但很多数据会"持续增长"——日志(每条请求都可能写、7×24 不停,增长最快最易失控)、上传文件、用户数据、缓存、临时文件、数据库 binlog、监控数据、core dump、备份……任何"只写不删"的,都是定时炸弹日志是头号杀手:写得最频繁;DEBUG 级别、打印大对象、循环里打日志会让它暴增;一个异常风暴(疯狂刷错误栈)能几小时就写满磁盘!磁盘满的连锁反应之所以致命:应用、数据库、系统都依赖"写磁盘",全部受影响;数据库可能进入只读/拒绝写、业务直接挂;有时还会数据损坏(写到一半空间没了)。防范要有三道防线:第一,轮转(rotate)——按大小/时间切割日志、别让单文件无限大;第二,清理(retain)——只保留最近 N 份/N 天、旧的自动删除或归档;第三,监控告警——磁盘用到 80%/90% 就告警、在满之前介入。由此,我刻下一个关键认知:"磁盘会满"不是小概率,而是必然——只要你不主动管理增长的数据;上线一个服务,就要同时规划好它"产生的数据怎么不撑爆磁盘"。归根结底:磁盘有限,日志等持续增长的数据不轮转不清理终将撑爆磁盘、引发全线崩溃;必须做轮转+清理+监控告警三道防线。

第二件事:正解——日志轮转 + 清理 + 监控告警

搞懂了原理,正解就清晰了:给日志配上轮转(切割)、清理(只留 N 份)、监控(快满就告警)这三道防线。

# ✓ 正解一: 用 logrotate 配置日志轮转 + 清理(Linux 通用)
# /etc/logrotate.d/myapp
/www/wwwroot/myapp/logs/*.log {
    daily                # 每天轮转一次
    rotate 7             # ✓ 只保留最近 7 份, 更早的自动删除(清理!)
    size 500M            # ✓ 或超过 500M 就轮转(按大小, 防单文件过大)
    compress             # ✓ 旧日志压缩(省空间)
    delaycompress        # 延迟一轮再压缩(避免压到正在写的)
    missingok            # 文件不存在不报错
    notifempty           # 空文件不轮转
    copytruncate         # ✓ 关键: 复制后清空原文件, 适合"一直打开着写"的程序
    # 或用 postrotate 给应用发信号重开日志文件(如 nginx 用 USR1)
}
# 手动测试配置: logrotate -d /etc/logrotate.d/myapp  (调试, 不实际执行)
#              logrotate -f /etc/logrotate.d/myapp  (强制执行一次)

# ✓ 正解二: 应用层日志框架自带轮转(更推荐, 不依赖外部 logrotate)
#   - Logback(Java): SizeAndTimeBasedRollingPolicy
#       500MB
#       7          ← 保留天数
#       10GB   ← ✓ 总量上限, 超了删最老的(双保险!)
#   - Python: logging.handlers.RotatingFileHandler / TimedRotatingFileHandler
#       maxBytes=500*1024*1024, backupCount=7

# ✓ 正解三: 监控磁盘水位 + 告警
#   - df 监控: 用量到 80% 预警, 90% 告警, 别等 100%。
#   - 监控 inode: df -i (小文件太多会耗尽 inode, 也会"写不进")。

# ✓ 正解四: 控制日志"源头"的产出
#   - 生产别开 DEBUG; 别打印大对象/全量数据; 别在热循环里打日志。
#   - 大量同类错误做"采样/聚合", 别一条不漏地刷。

# 核心: 日志框架/logrotate 配轮转(按大小+时间)+ 只留N份/总量上限的清理
#   + 磁盘水位告警 + 控制日志源头产出, 四管齐下防磁盘被写满。

修复的方案,是层层设防正解一,用 logrotate(Linux 通用):配置每天轮转或超 500M 就轮转(daily/size)、只保留最近 7 份(rotate 7,这是清理)、旧日志压缩(compress);对"一直打开着写"的程序,关键要用 copytruncate(复制后清空原文件),否则程序还往旧 inode 写、轮转无效。正解二,用应用层日志框架自带的轮转(更推荐,不依赖外部):Logback 的 SizeAndTimeBasedRollingPolicy(可设 maxFileSizemaxHistory 保留天数,尤其 totalSizeCap 总量上限——超了就删最老的,是双保险);Python 的 RotatingFileHandler/TimedRotatingFileHandler正解三,监控磁盘水位 + 告警:用量到 80% 预警、90% 告警,别等 100%;还要监控 inode(df -i,小文件太多会耗尽 inode、同样"写不进")。正解四,控制日志"源头"产出:生产别开 DEBUG、别打印大对象、别在热循环里打日志、大量同类错误做采样聚合归根结底:日志框架/logrotate 配轮转(按大小+时间)+ 只留 N 份/总量上限的清理 + 磁盘水位告警 + 控制日志源头产出,四管齐下,防磁盘被写满。

第三件事:磁盘满了的应急处理

除了治本的防范,我也沉淀了一套"磁盘已经满了、火烧眉毛"时的应急处理流程:

磁盘满了的应急处理: 先腾空间救活, 再治本

# 1. 快速定位谁占的(从大往小找)
df -h                                    # 确认哪个分区满了
du -h --max-depth=1 / | sort -rh | head  # 逐层 du 找大目录
# 或一步到位找最大的文件:
find / -type f -size +1G 2>/dev/null -exec ls -lh {} \; | sort -k5 -rh | head

# 2. 安全地腾出空间(优先删"能删的")
#    - 删旧日志(确认不再需要的): rm old.log
#    - ✗ 别直接删"正在写的"大日志! 用 truncate 清空更安全:
truncate -s 0 /path/app.log              # 清空但保留文件(进程继续写不报错)
#    - 清理 /tmp、旧的 .gz 归档、无用的 core dump、旧 docker 镜像:
docker system prune -a                   # 清理无用镜像/容器(docker 环境)

# 3. ⚠ 删了文件 df 没释放? 找"被删但仍被打开"的文件
lsof | grep deleted | sort -k7 -rh | head   # 找占空间的 deleted 文件
#    → 重启持有它的进程, 或对其 truncate, 空间才真正释放。

# 4. 救活后, 立刻做治本(别只救火不防火):
#    - 补上 logrotate / 日志框架轮转配置。
#    - 配磁盘水位告警, 下次在满之前就介入。

# 应急口诀: df 看满 → du/find 找大头 → truncate 清空大日志 → lsof 查 deleted
#           → 救活后补轮转和告警。

# 核心: 磁盘满应急先用 truncate 清空大日志腾空间(别 rm 正在写的)、
#   注意 lsof deleted 不释放的坑; 救活后必须补轮转+告警治本。

这套应急流程,是这次事故给我最实用的"救命手册"。第一步,快速定位谁占的:df -h 看哪个分区满了,再 du 逐层往下找大目录,或 find / -size +1G 直接揪出大文件。第二步,安全地腾空间:删确认不要的旧日志;但千万别直接 rm 那个"正在写的"大日志——用 truncate -s 0 清空它更安全(保留文件、进程能继续写不报错);再清 /tmp、旧 .gz、core dump、无用 docker 镜像。第三步,也是最坑的陷阱:删了文件 df 却没释放?用 lsof | grep deleted 找那些"被删但仍被进程打开"的文件,重启持有它的进程或 truncate 它,空间才真正释放第四步,救活后立刻治本:补上 logrotate/日志框架轮转、配磁盘水位告警,别只救火不防火。归根结底:磁盘满应急,先用 truncate 清空大日志腾空间(别 rm 正在写的)、注意 lsof deleted 不释放的坑;救活后必须补轮转 + 告警来治本。

下面这张图,是这次"磁盘塞满"事故的成因与解法:

第四件事:logrotate 几个关键选项的对照

这次踩坑后,我把 logrotate(及日志轮转)的几个关键选项,整理成一张表,配置时不再抓瞎。

选项 作用 注意
daily/weekly/size 按时间或大小触发轮转 可同时配, 满足任一就轮转
rotate N 保留 N 份历史, 多的删除 这是"清理", 必配! 否则只切不删
compress 旧日志压缩为 .gz 大幅省空间, 文本压缩比很高
copytruncate 复制后清空原文件 适合"一直打开写"的程序; 有极小丢日志窗口
postrotate 发信号 轮转后通知程序重开文件 更可靠(如 nginx -USR1), 但需程序支持
maxsize / totalSizeCap 单文件/总量上限 双保险, 防异常风暴写爆

这张表,把日志轮转的"门道"理清了。最该牢记的两个:第一,rotate N 必须配——它才是真正的"清理",没有它,日志虽然被切成了很多份、却一份都不删,照样占满磁盘(切割 ≠ 清理!);第二,copytruncate vs postrotate 发信号的选择——对那些"一直打开日志文件写"的程序,直接 mv 走文件是无效的(程序还往旧 inode 写),要么用 copytruncate(复制后清空,简单但有极小丢日志窗口),要么用 postrotate 给程序发信号让它重开文件(更可靠,如 nginx 的 -USR1,但需程序支持)。此外,compress 能把文本日志压得很小(压缩比常达 10:1)、maxsize/总量上限是防"异常风暴"瞬间写爆的双保险它给我的启发是:日志轮转看似是个简单的运维配置,但每个选项背后,都对应着一个具体的失败场景(忘了 rotate N 就只切不删、忘了 copytruncate 就轮转无效);理解每个选项"在防什么",才能配出一个真正可靠、不会在某天凌晨把你叫醒的日志方案

第五件事:除了日志,这些"会撑爆磁盘"的东西也要管

这次踩坑让我警醒:能撑爆磁盘的,远不止应用日志。我把项目里其他"会悄悄增长、吃光磁盘"的东西,系统排查了一遍。

会撑爆磁盘的东西 增长来源 管理办法
应用日志 持续写, 异常风暴暴增 轮转+清理+控源头(本文)
数据库 binlog 每次写操作都记 设 expire_logs_days 自动过期
慢查询/错误日志(DB) 慢 SQL 多就暴涨 同样配轮转 + 治理慢 SQL
临时文件 /tmp 程序产生不清理 定期清理 / tmpwatch / 用完即删
上传/用户文件 随业务无限增长 对象存储 + 配额 + 生命周期策略
Docker 镜像/容器/卷 构建/拉取累积 docker system prune 定期清
core dump 程序崩溃就生成大文件 限制大小/路径, 定期清

这张表,让我看清了"磁盘杀手"的全家福它们的共同特征,都是"随时间/业务持续增长,却不会自动消失":应用日志、数据库 binlog 和慢查询日志、/tmp 临时文件、上传的用户文件、Docker 镜像容器卷、崩溃产生的 core dump……每一个,都可能在你不注意时,悄悄把磁盘吃光而它们的管理办法,也都遵循同一套逻辑:要么"自动过期/清理"(binlog 的 expire_logs_days、临时文件定期清、docker prune),要么"限制总量/配额"(上传文件配额、core dump 限大小),要么"挪到专门的地方"(用户文件放对象存储,别堆在应用服务器的本地磁盘)它给我的最大启发是:运维一个系统,要建立一份"磁盘资产清单":清楚地知道,这台机器上,有哪些数据会增长、每一份的增长速度和上限是多少、又分别由什么机制来约束它;对每一份"会增长的数据",都明确地为它配上一个"刹车"磁盘空间,是最容易被遗忘、却又最基础的资源;管好它,是一个工程师从"会写代码"走向"能扛起线上系统"的必修课

第六件事:上线一个服务时,我现在会怎么决策

现在,每当我准备上线一个新服务,脑子里都会过一遍这张关于"磁盘资产"的决策图——核心就一问:它会往磁盘写什么、会涨多快、谁来刹车?

这张图的灵魂,是把"磁盘管理"从"出事后救火"提前到"上线前规划"。第一步,盘点:这个服务会往磁盘写哪些会增长的数据?(日志、临时文件、上传文件、binlog、core dump……)。然后为每一类都配上"刹车":日志——配轮转(按大小+时间切割)+ 清理(只留 N 份/N 天 + 总量上限);临时/上传文件——定期清理/配额/挪到对象存储;binlog/core dump——设自动过期/限制大小。再加上兜底的监控:配磁盘水位告警(80%/90%),在满之前介入;并控制日志源头(生产别 DEBUG、别打大对象)最后,上线后定期 review 磁盘用量趋势,看有没有什么在悄悄异常增长。这套流程,让我以后上线服务时,磁盘不再是一个"被遗忘的角落",而是一个"从一开始就被规划和约束好"的资源

我立下的几条规矩

这场"磁盘被日志撑爆"的事故,换来了我做运维时,刻进骨子里的几条铁律:

  1. 任何持续写入的日志,必须配轮转 + 清理。切割(按大小/时间)+ 只留 N 份/总量上限,缺一不可——切割不删等于没用。
  2. 磁盘水位必须有告警。80% 预警、90% 告警,绝不能等到 100% 才被业务崩溃告知。
  3. copytruncate 或 postrotate 信号,二选一。对一直打开写的程序,直接 mv 文件轮转无效,必须让它重开文件或清空原文件。
  4. 控制日志源头。生产别开 DEBUG、别打印大对象、热循环别打日志、错误风暴要采样,从源头压住产出。
  5. 磁盘满了用 truncate 而非 rm。清空正在写的大日志用 truncate -s 0;rm 后空间没释放就查 lsof grep deleted。
  6. 盘点全部"会增长的数据"。不只应用日志,binlog、临时文件、上传文件、镜像、core dump 都要各配刹车。
  7. 磁盘是基础资源,上线前就规划。别等它满了全线崩溃才想起来——它是 100% 会满的,除非你主动管。

附:一个磁盘水位巡检与告警的小脚本

与其等磁盘满了被业务崩溃叫醒,不如写个小脚本主动巡检、提前告警。下面这个,挂到 cron 里定时跑,就是一道简单有效的"早期预警线":

#!/bin/bash
# disk_check.sh —— 磁盘水位巡检, 超阈值告警 + 顺手列出大文件
# 用法: 挂到 crontab, 如每 10 分钟跑一次: */10 * * * * /path/disk_check.sh

WARN=80          # 预警阈值(%)
CRIT=90          # 告警阈值(%)
WEBHOOK="https://your-alert-webhook"   # 钉钉/飞书/Slack 等告警地址

# 遍历每个挂载点检查使用率
df -h --output=pcent,target | tail -n +2 | while read -r line; do
    pct=$(echo "$line" | awk '{print $1}' | tr -d '%')
    mount=$(echo "$line" | awk '{print $2}')
    [ -z "$pct" ] && continue

    if [ "$pct" -ge "$CRIT" ]; then
        level="CRITICAL"
    elif [ "$pct" -ge "$WARN" ]; then
        level="WARNING"
    else
        continue   # 没超阈值, 跳过
    fi

    # 顺手找出该挂载点下最大的几个文件/目录, 一并报出来便于定位
    top=$(du -h -x "$mount" 2>/dev/null | sort -rh | head -5 | tr '\n' ';')
    msg="[$level] 磁盘 $mount 使用率 ${pct}%! Top: $top"

    echo "$msg"                                   # 输出到日志
    curl -s -X POST "$WEBHOOK" \
         -H 'Content-Type: application/json' \
         -d "{\"text\":\"$msg\"}" >/dev/null 2>&1  # 推送告警
done

# 也检查 inode(小文件太多会耗尽 inode, df 显示有空间却"写不进")
df -i --output=ipcent,target | tail -n +2 | while read -r line; do
    ipct=$(echo "$line" | awk '{print $1}' | tr -d '%')
    mount=$(echo "$line" | awk '{print $2}')
    [ -z "$ipct" ] && continue
    [ "$ipct" -ge "$CRIT" ] && echo "[CRITICAL] $mount inode 用尽 ${ipct}%!"
done

# 核心: 定时巡检每个挂载点的磁盘%和inode%, 超阈值就告警并附上大文件Top,
#   在磁盘满之前主动介入 —— 把"被动崩溃"变成"主动预警"。

这个小脚本,虽然简单,却是我现在每台机器上的"标配哨兵"。它的核心思路,是把"磁盘满"这件事,从"事后被动地被业务崩溃告知",变成"事前主动地被预警发现":定时巡检每个挂载点的使用率,超过 80% 就预警、90% 就告警,而且顺手把该挂载点下最大的几个文件/目录(du | sort | head)一并报出来,让你收到告警时,就已经知道"是谁占的"了,大大缩短了排查时间。它还特意检查了一个容易被忽略的维度——inode:小文件太多会耗尽 inode,这时 df 显示明明还有空间,却"写不进"任何新文件,是个比"空间满"更隐蔽的坑。这,正是我想用这个脚本,留给每一个运维者的最后一句话:对于"磁盘满"这类"100% 会发生、且后果严重"的问题,最好的策略,永远是"主动监控、提前预警",而不是"等它爆了再去救火"。一道几十行的巡检脚本、一条提前两小时的告警,换来的,可能就是一个能安稳睡到天亮、而不是在凌晨被叫起来手忙脚乱地 truncate 日志的夜晚把功夫下在"事前",才是真正的稳定之道

写在最后

回头看,这场由"一个日志文件"引发的、整台服务器全线崩溃的事故,真正教给我的,是一个比"配 logrotate"本身更深的道理:一个系统的稳定性,常常不是被那些"高深复杂的技术难题"打败的,而是被这种"低级、朴素、人人都懂、却又最容易被忽略"的基础资源问题,悄无声息地拖垮的我曾花大量精力,去优化算法、去打磨架构、去应对各种"看起来很厉害"的技术挑战;却恰恰是"磁盘会被写满"这个连新手都知道的常识,因为我从未把它当回事、从未主动去管它,而在某个凌晨,给了我最沉重的一击。这让我深刻地意识到:工程的可靠性,是由它最薄弱的那一环决定的;而那"最薄弱的一环",往往不在你精心设计的地方,而在你因为"太简单"而压根没去设计的地方所以,做一个能扛起线上系统的工程师,既要有仰望星空、攻克技术难题的能力,更要有脚踏实地、把"磁盘、内存、连接数、文件句柄"这些最基础的资源,一个一个管好耐心和敬畏:对每一份有限的资源,都清楚它的上限、它的增长、以及约束它的机制;不让任何一个"不起眼的小角色",有机会成为"压垮整个系统的最后一根稻草"。把那些"简单到不值得一提"的基础,认认真真地做扎实——这,是我用一次"磁盘塞满"的崩溃,换来的、关于运维、也关于工程的、最朴素也最深刻的领悟。如果这篇复盘,能让你在下一次上线服务时,顺手为它的日志配上轮转、为磁盘配上告警,那我对着那个 100% 的硬盘熬的这大半天,就值了。

—— 别看了 · 2026
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理 邮箱1846861578@qq.com。
技术教程

我的服务用域名连下游,对方机器扩缩容换了 IP 之后,我的服务却死活还在连那台早已下线的旧机器、疯狂报连接失败,我排查了大半天才发现是 DNS 被永久缓存了的复盘

2026-6-2 2:53:09

技术教程

我让大模型帮我查一个库的 API,它信誓旦旦地给了我一个方法名、连参数都写得有模有样,结果那个方法根本不存在,我对着这场一本正经的胡编排查了大半天的复盘

2026-6-2 3:05:48

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索