我的服务某天凌晨突然全线崩溃、各种写入都报错,登上去一看磁盘被日志撑到了 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(可设 maxFileSize、maxHistory 保留天数,尤其 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 磁盘用量趋势,看有没有什么在悄悄异常增长。这套流程,让我以后上线服务时,磁盘不再是一个"被遗忘的角落",而是一个"从一开始就被规划和约束好"的资源。
我立下的几条规矩
这场"磁盘被日志撑爆"的事故,换来了我做运维时,刻进骨子里的几条铁律:
- 任何持续写入的日志,必须配轮转 + 清理。切割(按大小/时间)+ 只留 N 份/总量上限,缺一不可——切割不删等于没用。
- 磁盘水位必须有告警。80% 预警、90% 告警,绝不能等到 100% 才被业务崩溃告知。
- copytruncate 或 postrotate 信号,二选一。对一直打开写的程序,直接 mv 文件轮转无效,必须让它重开文件或清空原文件。
- 控制日志源头。生产别开 DEBUG、别打印大对象、热循环别打日志、错误风暴要采样,从源头压住产出。
- 磁盘满了用 truncate 而非 rm。清空正在写的大日志用 truncate -s 0;rm 后空间没释放就查 lsof grep deleted。
- 盘点全部"会增长的数据"。不只应用日志,binlog、临时文件、上传文件、镜像、core dump 都要各配刹车。
- 磁盘是基础资源,上线前就规划。别等它满了全线崩溃才想起来——它是 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