概述

凌晨三点,你被告警吵醒——线上数据库写入失败,Nginx 起不来,SSH 登录卡顿。登上服务器一查,df -h 显示根分区 100%。这种事每个运维都遇到过,磁盘满大概是生产环境最高频的故障类型之一,根据实际运维统计,磁盘相关告警占比约 15%-20%。

但磁盘满不是一个简单问题。df -h 看到的 100% 可能并不是全部真相:

  • inode 耗尽:磁盘空间还有剩余,但文件系统inode用完了,照样报 No space left on device。这种问题更隐蔽,排查难度也更大。
  • 已删除文件未释放rm 删了大文件,df 显示空间没变。因为还有进程持有文件描述符,数据块并没有真正释放。
  • 预留空间:ext4 默认预留 5% 空间给 root,400GB 的数据盘就有 20GB 被"藏"起来了。

这篇文章把磁盘空间和 inode 管理的排查思路、清理策略、预防机制一次说透。所有命令都在 Ubuntu 22.04 和 CentOS 7.9 上实测过,能直接拿去用。

磁盘空间的两个维度:blocks 与 inode

很多人对磁盘空间的理解只停留在"还剩多少 GB"这个层面。但 Linux 文件系统管理的是两个独立资源:数据块(blocks)索引节点(inode)

打个比方:文件系统像一个停车场。blocks 是停车位,inode 是停车记录。停车场可能还有空车位(blocks 没满),但记录本写满了(inode 耗尽),新来的车也停不进去。

inode 是什么

inode(Index Node,索引节点)是文件系统里描述文件元数据的数据结构。每个文件或目录对应一个 inode,存储了以下信息:

元数据字段说明
文件类型普通文件、目录、符号链接等
权限信息rwx 权限位
所有者uid 和 gid
文件大小字节数
时间戳atime / mtime / ctime
数据块指针指向实际数据存储位置的索引
硬链接数指向该 inode 的目录项数量

注意一个关键点:inode 不存储文件名。文件名存在目录项(dentry)中,目录项将文件名映射到 inode 编号。这也是为什么硬链接能存在——多个文件名可以指向同一个 inode。

inode 总数在文件系统创建时就固定了。ext4 默认每 16KB 空间分配一个 inode,也就是说一个 100GB 的分区大约有 655 万个 inode。对于存大文件来说足够了,但如果你的系统上堆了几百万个小文件(比如邮件队列、日志碎片、Session 文件),inode 就可能先于 blocks 耗尽。

xfs 和 ext4 的 inode 策略差异

ext4 的 inode 数量在 mkfs 时固定,后期无法调整。如果创建时没预估好,后面只能重新格式化。

xfs 的策略不同——它采用动态 inode 分配。当需要新 inode 时,xfs 会自动从空闲空间中分配。这意味着 xfs 理论上不会遇到"inode 耗尽但空间还有"的问题。但代价是 xfs 的 inode 不像 ext4 那样有固定大小,某些需要大 inode 的场景(如存储大量 ACL)可能受限。

# 查看文件系统类型
df -T

# 查看 ext4 的 inode 配置
tune2fs -l /dev/sda1 | grep -i "inode\|block count\|block size"

# 查看 xfs 的 inode 信息
xfs_info /dev/sda1 | grep -i "imax\|inodes"

实际案例:inode 耗尽但空间充足

某天收到告警,应用报 No space left on device。登上服务器:

$ df -h /
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        50G   20G   30G  40% /

$ df -i /
Filesystem     Inodes  IUsed IFree IUse% Mounted on
/dev/sda1     3276800 3276800    0  100% /

磁盘空间剩 30GB,但 inode 100% 用完了。这种矛盾现象在 Linux 系统中并不罕见,根因往往是大量小文件堆积(参考:Linux 磁盘明明有空间,却报 No space left on device)。

排查第一步:快速确认磁盘状态

收到磁盘告警后,第一件事不是删文件,而是搞清楚到底什么满了。

同时检查 blocks 和 inode

# 查看磁盘空间使用情况
df -h

# 查看 inode 使用情况(关键!)
df -ih

df -ih 加了 -h 参数,以人类可读的格式显示 inode 使用率。如果只看 df -h 不看 df -i,很容易漏掉 inode 耗尽的问题。

典型输出:

Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1       100G   95G  5.0G  95% /
/dev/sdb1       500G  120G  380G  24% /data
tmpfs           7.8G  1.2M  7.8G   1% /run
Filesystem     Inodes IUsed IFree IUse% Mounted on
/dev/sda1      6.5M   6.5M     0  100% /
/dev/sdb1      3.2M   125K  3.1M    1% /data
tmpfs          512K   105   512K    1% /run

上面这个输出说明根分区同时存在空间不足和 inode 耗尽两个问题。

找出空间占用最大的目录

# 从根目录逐级排查
du -h --max-depth=1 / 2>/dev/null | sort -rh | head -20

# 针对特定目录深入排查
du -h --max-depth=1 /var 2>/dev/null | sort -rh | head -20

这条命令的原理:du 统计每个一级子目录的大小,sort -rh 按人类可读格式逆序排列,head -20 只看前 20 个。通过逐级深入,通常 3-4 次就能定位到罪魁祸首。

找出 inode 占用最多的目录

# 统计各目录下的文件数量
find / -xdev -type f 2>/dev/null | \
  awk -F/ '{print "/"$2}' | \
  sort | uniq -c | sort -rn | head -20

或者用更直观的方式,逐级排查:

# 查看根目录下每个一级目录的文件数
for d in /*; do
  [ -d "$d" ] && echo "$(find "$d" -xdev 2>/dev/null | wc -l) $d"
done | sort -rn | head -10

实际生产中,inode 杀手通常是这几类:

场景典型目录特征
日志碎片/var/log大量 KB 级小文件
邮件队列/var/spool/postfix数万到数百万个邮件文件
Session 文件/tmp/var/lib/php/sessions海量会话文件
Docker 层/var/lib/docker/overlay2容器镜像层和容器文件系统
定时任务残留/var/spool/croncron 执行残留的临时文件

已删除文件未释放:最隐蔽的坑

这是磁盘排查中最经典的坑之一。用 rm 删除了一个大文件,但 df 显示空间没有释放。原因是有进程还持有这个文件的文件描述符(参考:Linux 磁盘空间满了怎么办?超详细排查指南)。

原理

Linux 文件系统中,文件的数据块在所有持有它的文件描述符都关闭后才会真正释放。rm 只是从目录项中删除了文件名到 inode 的映射,但如果某个进程还在通过文件描述符读写这个文件,inode 和数据块就不会被回收。

这就像你把书架上书的标签撕了(rm),但书还放在那里(数据块还在),直到有人把它拿走(文件描述符关闭)才会真正腾出位置。

定位已删除但未释放的文件

# 列出已删除但仍被进程占用的文件
lsof +L1 2>/dev/null

# 或者用更精确的方式
lsof -nP | grep -i "(deleted)"

输出示例:

COMMAND   PID  USER   FD   TYPE  DEVICE  SIZE/OFF  NODE NAME
nginx    1234  root   8w   REG   8,1     10G      12345 /var/log/nginx/access.log (deleted)
java     5678  app   42w   REG   8,1     5G       12346 /opt/app/logs/gc.log (deleted)

从输出可以看到,nginx 进程(PID 1234)还持有 /var/log/nginx/access.log 的写句柄,这个文件已经被删了但 10GB 的空间没释放。java 进程也类似,占着 5GB 的 GC 日志。

释放空间的三种方式

方式一:重启进程(推荐)

# 平滑重启 nginx
nginx -s reload

# 重启 java 应用
systemctl restart app

重启后进程释放文件描述符,空间立即回收。这是最安全的方式。

方式二:清空文件内容(不重启进程)

如果进程不能重启(比如生产环境的数据库),可以通过 /proc 清空文件内容:

# 通过 /proc 文件系统清空文件
cat /dev/null > /proc/1234/fd/8

其中 1234 是 PID,8 是文件描述符编号(来自 lsof 输出的 FD 列,去掉字母后缀)。

这个操作的效果等同于 > /var/log/nginx/access.log,但不需要文件名——直接通过 fd 操作。文件内容被清空,空间释放,但文件描述符保持打开状态,进程不会报错。

方式三:使用 truncate 命令

# 通过 /proc 截断文件
truncate -s 0 /proc/1234/fd/8

效果和 cat /dev/null > 一样,但语法更清晰。

注意:千万不要直接 kill -9 进程来释放文件描述符。在生产环境中,强杀进程可能导致数据损坏或服务中断。优先使用优雅重启或 /proc 方式。

ext4 预留空间:被"藏"起来的 5%

ext4 文件系统默认预留 5% 的空间给 root 用户。这个设计是为了防止普通用户把磁盘写满后,root 用户连登录都登不了——因为登录需要写 /var/log/wtmp 等文件。在根分区上这个设计很合理,但在纯数据盘上就是浪费。

查看预留空间

# 查看预留块比例
tune2fs -l /dev/sda1 | grep "Reserved block count"

# 输出示例:
# Reserved block count:     2621440
# Block size:               4096
# 预留空间 = 2621440 * 4096 / 1024 / 1024 / 1024 ≈ 10GB

调整预留空间

# 将预留比例设为 1%(数据盘推荐)
tune2fs -m 1 /dev/sdb1

# 完全取消预留(仅用于临时盘或测试盘)
tune2fs -m 0 /dev/sdb1

# 指定预留块数(精确控制)
tune2fs -r 0 /dev/sdb1

400GB 的数据盘从 5% 调到 1%,能多出 16GB 可用空间。如果是纯日志盘或备份盘,设为 0% 也没问题——上面跑不了用户进程,不存在 root 登不了的风险。

xfs 文件系统没有这个预留机制,所以不需要调整。

日志清理:磁盘满的头号元凶

生产环境磁盘满,根因统计下来大概率是日志。Nginx access log、Java GC log、应用业务日志——这些文件持续增长,如果不管控迟早出事。

手动清理策略

# 清空日志文件(保留文件本身,只清内容)
cat /dev/null > /var/log/nginx/access.log

# 删除 7 天前的日志文件
find /var/log -name "*.log" -mtime +7 -delete

# 删除超过 100MB 的日志文件
find /var/log -name "*.log" -size +100M -delete

# 压缩 3 天前的日志
find /var/log -name "*.log" -mtime +3 -exec gzip {} \;

cat /dev/null >rm 的区别:前者清空文件内容但保留文件本身,正在写入的进程不会报错;后者删除文件,进程的下次写入会触发重建(如果配置了的话)或报错。对于正在运行的服务的日志文件,优先用清空方式。

logrotate:生产级日志管理

手动清理是临时手段,长期方案是配置 logrotate。logrotate 是 Linux 自带的日志轮转工具,能自动按大小或时间切割、压缩、删除旧日志。

# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
    daily              # 每天轮转
    rotate 14          # 保留 14 天
    compress           # 压缩旧日志
    delaycompress      # 延迟一天压缩(防止和当前写入冲突)
    missingok          # 文件不存在不报错
    notifempty         # 空文件不轮转
    create 644 nginx adm  # 轮转后创建新文件
    sharedscripts      # 多个文件匹配时脚本只执行一次
    postrotate
        if [ -f /var/run/nginx.pid ]; then
            kill -USR1 $(cat /var/run/nginx.pid)
        fi
    endscript
}

关键参数解释:

参数作用推荐值
daily/weekly/monthly轮转频率根据日志量选择
rotate N保留份数7-30 天
compressgzip 压缩旧日志必开
delaycompress延迟一天压缩防止和当前写入冲突
size 500M按大小轮转大流量日志推荐
copytruncate复制后截断原文件不支持 postrotate 的场景

copytruncatecreate 的选择是关键。create 模式会创建新文件,需要通过 postrotate 通知进程重新打开日志(比如 nginx 的 kill -USR1)。copytruncate 模式直接把当前日志复制一份然后清空原文件,进程不需要重启也不需要信号——但代价是复制和清空之间有一个极短的时间窗口可能丢日志。

对于不能发信号的服务(比如某些 Java 应用),用 copytruncate

# /etc/logrotate.d/myapp
/opt/app/logs/*.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    copytruncate
    size 500M
}

测试 logrotate 配置

# 调试模式(不实际执行,只显示会做什么)
logrotate -d /etc/logrotate.d/nginx

# 强制执行
logrotate -f /etc/logrotate.d/nginx

Docker 磁盘清理

Docker 是另一个磁盘空间大户。镜像层、容器可写层、日志、Volume,每一层都可能堆积 GB 级数据。

快速诊断

# 查看 Docker 整体磁盘使用
docker system df

# 查看详细信息
docker system df -v

输出示例:

TYPE            TOTAL   ACTIVE  SIZE      RECLAIMABLE
Images          45      12      52.3GB    38.1GB (72%)
Containers      23      8       1.2GB     800MB (66%)
Local Volumes   15      10      8.5GB     2.3GB (27%)
Build Cache     0       0       0B        0B

RECLAIMABLE 列就是可回收的空间。上面这个例子有 38GB 镜像和 800MB 容器数据可以清理。

清理命令

# 一键清理:停止的容器 + 无用网络 + 悬空镜像 + 构建缓存
docker system prune

# 更彻底:包括未被容器引用的镜像
docker system prune -a

# 清理未被使用的 Volume(谨慎!确认没有需要保留的数据)
docker volume prune

# 清理构建缓存
docker builder prune

# 只清理悬空镜像(<none> 标签的)
docker image prune

清理容器日志

Docker 容器的日志默认存在 /var/lib/docker/containers/<id>/<id>-json.log,如果不限制大小,一个高流量容器的日志能吃掉几十 GB。

// /etc/docker/daemon.json
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "3"
  }
}

这个配置限制每个容器的日志文件最大 100MB,保留 3 个文件。修改后需要重启 Docker:

systemctl restart docker

注意daemon.json 的日志限制只对新建的容器生效。已有容器需要重建才能应用新配置。如果急需清理某个容器的日志,可以直接清空对应文件:

cat /dev/null > /var/lib/docker/containers/<container-id>/<container-id>-json.log

自动化磁盘巡检脚本

手动排查是基本功,但生产环境不能靠人肉巡检。下面是一个可以直接用的磁盘巡检脚本,配合 cron 定期执行,超过阈值就告警。

#!/bin/bash
# disk-check.sh - 磁盘空间与 inode 巡检脚本
# 用法: ./disk-check.sh [阈值百分比,默认85]

THRESHOLD=${1:-85}
HOSTNAME=$(hostname)
ALERT_LIST=""

# 检查磁盘空间
while read -r line; do
    USAGE=$(echo "$line" | awk '{print $5}' | tr -d '%')
    MOUNT=$(echo "$line" | awk '{print $6}')
    if [ "$USAGE" -ge "$THRESHOLD" ] 2>/dev/null; then
        ALERT_LIST="${ALERT_LIST}磁盘空间: ${MOUNT} 使用率 ${USAGE}%\n"
    fi
done < <(df -h | grep -v "^Filesystem" | grep -v "tmpfs")

# 检查 inode 使用率
while read -r line; do
    USAGE=$(echo "$line" | awk '{print $5}' | tr -d '%')
    MOUNT=$(echo "$line" | awk '{print $6}')
    if [ "$USAGE" -ge "$THRESHOLD" ] 2>/dev/null; then
        ALERT_LIST="${ALERT_LIST}inode: ${MOUNT} 使用率 ${USAGE}%\n"
    fi
done < <(df -ih | grep -v "^Filesystem" | grep -v "tmpfs")

# 检查已删除未释放的大文件
DELETED_FILES=$(lsof +L1 2>/dev/null | awk 'NR>1 && $7+0 > 104857600 {print $1, $2, $7/1024/1024 "MB", $NF}')
if [ -n "$DELETED_FILES" ]; then
    ALERT_LIST="${ALERT_LIST}已删除未释放文件:\n${DELETED_FILES}\n"
fi

# 输出告警
if [ -n "$ALERT_LIST" ]; then
    echo -e "[磁盘巡检告警] ${HOSTNAME}\n"
    echo -e "$ALERT_LIST"
    # 这里接入告警通道(企业微信/钉钉/邮件等)
    # send_alert "$ALERT_LIST"
    exit 1
else
    echo "[磁盘巡检] ${HOSTNAME} 正常"
    exit 0
fi

配合 cron 使用:

# 每天上午 9 点巡检
0 9 * * * /opt/scripts/disk-check.sh 85 >> /var/log/disk-check.log 2>&1

# 每小时检查一次(适合磁盘增长快的环境)
0 * * * * /opt/scripts/disk-check.sh 90 >> /var/log/disk-check.log 2>&1

inode 恢复:inode 耗尽后怎么办

inode 耗尽比磁盘空间满更棘手,因为不能简单删除文件——你可能连 touch 一个临时文件都做不到。

紧急恢复步骤

# 第一步:找出文件最多的目录
for d in /*; do
  [ -d "$d" ] && echo "$(find "$d" -xdev 2>/dev/null | wc -l) $d"
done | sort -rn | head -10

# 第二步:深入到子目录,逐级定位
# 假设 /var 文件最多,继续往下查
for d in /var/*; do
  [ -d "$d" ] && echo "$(find "$d" -xdev 2>/dev/null | wc -l) $d"
done | sort -rn | head -10

# 第三步:批量删除小文件
# 先确认文件数量和类型
find /var/log/app -type f -name "*.tmp" | wc -l

# 删除(先用 -print 确认,再换 -delete)
find /var/log/app -type f -name "*.tmp" -delete

高效批量删除大量文件

当文件数量达到百万级时,rm -rf 可能会因为参数过长而失败,或者耗时极长。更高效的方式:

# 方法一:find -delete(推荐,最快)
find /path/to/dir -type f -delete

# 方法二:find + xargs(适合需要额外处理时)
find /path/to/dir -type f -print0 | xargs -0 rm -f

# 方法三:rsync 清空目录(性能极好)
mkdir /tmp/empty_dir
rsync -a --delete /tmp/empty_dir/ /path/to/dir/

实测在 500 万文件的场景下,find -deleterm -rf 快 3-5 倍,rsync --delete 更快,因为它不走 unlink 系统调用,直接在文件系统层面操作。

长期方案:调整 inode 数量

如果业务确实需要存储大量小文件,可以在创建文件系统时调整 inode 比例:

# ext4:每 4KB 空间分配一个 inode(默认 16KB)
mkfs.ext4 -i 4096 /dev/sdb1

# 或者指定每 2KB 一个 inode(更激进)
mkfs.ext4 -i 2048 /dev/sdb1

# 查看调整效果
tune2fs -l /dev/sdb1 | grep "Inode count"

代价是每个 inode 占用 256 字节,inode 数量翻倍意味着元数据开销翻倍。对于大文件存储场景不划算,需要根据实际文件大小分布权衡。

注意:ext4 的 inode 数量在 mkfs 时固定,事后无法调整。如果已经格式化好的分区 inode 不够,只能重新格式化或迁移数据。xfs 支持动态 inode 分配,不存在这个问题。

监控体系:Prometheus + node_exporter

光靠巡检脚本还不够,需要一个持续监控的体系。Prometheus + node_exporter 是事实上的标准方案。

关键监控指标

指标说明PromQL
磁盘空间使用率各挂载点空间占比100 - (node_filesystem_avail_bytes / node_filesystem_size_bytes * 100)
inode 使用率各挂载点 inode 占比100 - (node_filesystem_files_free / node_filesystem_files * 100)
磁盘写入速率每秒写入字节数rate(node_disk_written_bytes_total[5m])
已删除文件大小通过自定义 exporter需要自定义脚本

告警规则

# disk-alerts.yml
groups:
  - name: disk_alerts
    rules:
      # 磁盘空间使用率 > 85%
      - alert: DiskSpaceHigh
        expr: |
          100 - (node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"} 
          / node_filesystem_size_bytes{fstype!~"tmpfs|overlay"} * 100) > 85          
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "磁盘空间使用率高: {{ $labels.mountpoint }}"
          description: "{{ $labels.instance }} 的 {{ $labels.mountpoint }} 使用率 {{ $value }}%"

      # 磁盘空间使用率 > 95%(紧急)
      - alert: DiskSpaceCritical
        expr: |
          100 - (node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"} 
          / node_filesystem_size_bytes{fstype!~"tmpfs|overlay"} * 100) > 95          
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "磁盘空间严重不足: {{ $labels.mountpoint }}"
          description: "{{ $labels.instance }} 的 {{ $labels.mountpoint }} 使用率 {{ $value }}%"

      # inode 使用率 > 85%
      - alert: InodeUsageHigh
        expr: |
          100 - (node_filesystem_files_free{fstype!~"tmpfs|overlay"} 
          / node_filesystem_files{fstype!~"tmpfs|overlay"} * 100) > 85          
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "inode 使用率高: {{ $labels.mountpoint }}"
          description: "{{ $labels.instance }} 的 {{ $labels.mountpoint }} inode 使用率 {{ $value }}%"

实测发现,inode 使用率告警比磁盘空间告警更容易被忽略。很多团队只配了磁盘空间告警,没有配 inode 告警,等出了问题才发现监控盲区。别踩这个坑——两个维度都要监控。

常见问题速查表

把生产环境高频问题整理成速查表,遇到问题时按图索骥:

现象可能原因排查命令解决方案
df -h 显示 100%日志/临时文件堆积`du -h –max-depth=1 /sort -rh`
df -h 有空间但报 No spaceinode 耗尽df -ih清理小文件
rm 后空间未释放进程持有文件描述符lsof +L1重启进程或 cat /dev/null > /proc/PID/fd/N
磁盘使用率突增Docker 镜像/日志docker system dfdocker system prune -a
根分区空间被预留ext4 5% 预留tune2fs -l /dev/sdX | grep Reservedtune2fs -m 1 /dev/sdX
应用写日志失败磁盘满或 inode 耗尽df -h && df -ih清理空间或增加 inode
SSH 登录卡顿磁盘满导致写 wtmp 失败df -h /清理根分区

生产环境磁盘管理清单

基于实际运维经验,整理一份生产环境磁盘管理清单,建议逐项落实:

监控层面

  • 同时监控 blocks 和 inode 使用率,阈值设为 85% 告警、95% 紧急告警
  • 监控磁盘写入速率突变(可能预示日志暴涨或异常)
  • 配置已删除未释放文件的定期检查

日志管理

  • 所有日志服务配置 logrotate,按天或按大小轮转
  • Docker 容器配置 daemon.json 日志限制(max-size + max-file)
  • 应用日志按天切割,压缩保留 7-30 天

清理策略

  • 定期执行 docker system prune 清理无用镜像
  • 临时文件目录配置 tmpwatch 或 systemd-tmpfiles 自动清理
  • 数据库 binlog 配置过期时间(如 MySQL expire_logs_days = 7

容量规划

  • 数据盘使用 ext4 时根据文件大小分布调整 inode 比例
  • 大量小文件场景优先使用 xfs(动态 inode 分配)
  • 预留 15%-20% 的空间余量,不要等到满了再处理

总结

磁盘空间管理看着简单,实际坑不少。总结几条实战经验:

排查要全面df -h 只是第一步,必须同时查 df -ih。inode 耗尽的表现和磁盘满一样,但排查思路完全不同。别只看一个维度就下结论。

删文件不等于释放空间。有进程持有的文件删了也不释放,这个坑踩过的人都印象深刻。lsof +L1 应该成为磁盘排查的标配命令。

预防胜于治疗。logrotate、Docker 日志限制、Prometheus 监控——这些配置在出事之前花十分钟搞定,能避免凌晨三点被叫起来。生产环境最大的风险不是技术难度,而是"知道该做但没做"。

inode 要提前规划。ext4 的 inode 数量创建后不可改,格式化前就要预估。大量小文件场景用 xfs 更省心。这个决策做错了,后面改起来代价很大。

最后一条:磁盘满了不要慌。先 df -h 看空间、df -ih 看 inode、lsof +L1 看幽灵文件、du 定位大目录——四步走完,问题基本就定位了。

参考资料与致谢

本文在撰写过程中参考了以下资料,感谢原作者的贡献:

  1. Linux 磁盘空间满了怎么办?超详细排查指南 — 腾讯云开发者社区,提供了磁盘空间排查的系统化流程和已删除文件未释放的原理分析
  2. Linux 磁盘明明有空间,却报 No space left on device — CSDN,详细解析了 inode 耗尽的诊断方法和 inode 机制原理
  3. Linux 文件系统深度解析:ext4、XFS、inode、硬链接 vs 软链接 — CSDN,提供了 ext4 块组布局和 xfs 动态 inode 分配机制的深入分析
  4. 记录一次 inode 耗尽造成的生产事故 — CSDN,真实生产事故复盘,展示了 inode 耗尽的定位过程和 logrotate 治理方案