Linux 文件系统 inode 耗尽故障排查实战

故障现象

某生产服务器出现无法创建新文件的情况,具体表现为:

1
2
3
4
5
6
7
8
# 尝试创建文件失败
$ touch test.txt
touch: cannot touch 'test.txt': No space left on device

# 但磁盘空间显示充足
$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 100G 20G 80G 20% /

磁盘使用率仅 20%,但系统提示”No space left on device”,这通常意味着 inode 耗尽而非磁盘空间不足。

故障诊断

1. 确认 inode 使用情况

1
2
3
4
5
# 查看各分区 inode 使用率
$ df -i
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/sda1 6553600 6553500 100 100% /
/dev/sdb1 131072000 1000000 130072000 1% /data

根分区 inode 使用率已达 100%,确认为 inode 耗尽故障。

2. 定位 inode 消耗源

1
2
3
4
5
# 从根目录开始,逐层统计各目录下的文件数量
$ for i in /*; do echo $i; find $i -xdev -type f | wc -l; done | sort -k2 -nr | head -20

# 或使用更高效的命令
$ find / -xdev -type f | cut -d "/" -f 2-3 | sort | uniq -c | sort -rn | head -20

常见的高 inode 消耗目录:

  • /var/log/ - 日志文件过多
  • /var/spool/postfix/ - 邮件队列堆积
  • /tmp/ - 临时文件未清理
  • /var/cache/ - 缓存文件积累
  • 应用数据目录 - 小文件过多

3. 深入分析具体目录

1
2
3
4
5
# 统计某目录下各子目录的文件数量
$ find /var/log -type f | cut -d "/" -f 4 | sort | uniq -c | sort -rn | head -20

# 查找特定类型的小文件
$ find /var -type f -size -1k | wc -l

故障处理

方案一:清理无用文件(临时解决)

1
2
3
4
5
6
7
8
9
10
11
# 清理旧日志文件(保留最近 7 天)
$ find /var/log -type f -name "*.log" -mtime +7 -delete

# 清理空文件
$ find /var -type f -empty -delete

# 清理临时文件
$ find /tmp -type f -atime +3 -delete

# 清理邮件队列(谨慎操作)
$ find /var/spool/postfix -type f -delete

方案二:日志轮转优化(长期解决)

检查并优化 logrotate 配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 查看当前 logrotate 配置
$ cat /etc/logrotate.conf
$ ls /etc/logrotate.d/

# 示例:优化 nginx 日志轮转
$ cat /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
create 0640 www-data adm
sharedscripts
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
endscript
}

方案三:应用层优化

针对产生大量小文件的应用:

1
2
3
4
5
6
7
# 1. 调整应用日志级别,减少日志输出
# 2. 使用日志聚合工具(ELK、Loki 等)
# 3. 对小文件进行归档压缩
$ tar -czf archive_$(date +%Y%m%d).tar.gz /path/to/small/files/
$ rm -rf /path/to/small/files/*

# 4. 使用数据库替代文件存储(适用于配置、会话等数据)

方案四:文件系统调优(根本解决)

1
2
3
4
5
6
7
8
9
# 查看当前文件系统 inode 配置
$ tune2fs -l /dev/sda1 | grep -i inode

# 重新格式化时调整 inode 比例(需备份数据)
# 默认 ext4 每 16KB 创建一个 inode,可调整为每 8KB 或 4KB
$ mkfs.ext4 -i 8192 /dev/sda1

# 或使用 xfs 文件系统(动态 inode 分配)
$ mkfs.xfs /dev/sda1

监控与预防

1. 添加 inode 监控告警

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# Prometheus 监控指标
# node_filesystem_files{mountpoint="/"} - 总文件数
# node_filesystem_files_free{mountpoint="/"} - 剩余文件数
# node_filesystem_filesize{mountpoint="/"} - 文件系统大小

# 告警规则示例
$ cat /etc/prometheus/rules/inode_alert.yml
groups:
- name: inode_alerts
rules:
- alert: InodeUsageHigh
expr: (1 - (node_filesystem_files_free / node_filesystem_files)) * 100 > 80
for: 5m
labels:
severity: warning
annotations:
summary: "Inode 使用率过高"
description: "{{ $labels.instance }} 的 {{ $labels.mountpoint }} 分区 inode 使用率超过 80%"

- alert: InodeUsageCritical
expr: (1 - (node_filesystem_files_free / node_filesystem_files)) * 100 > 90
for: 2m
labels:
severity: critical
annotations:
summary: "Inode 使用率危急"
description: "{{ $labels.instance }} 的 {{ $labels.mountpoint }} 分区 inode 使用率超过 90%"

2. 定期巡检脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/bin/bash
# /usr/local/bin/inode_check.sh

THRESHOLD=80
EMAIL="admin@example.com"

while read -r line; do
filesystem=$(echo "$line" | awk '{print $1}')
inodes=$(echo "$line" | awk '{print $2}')
iused=$(echo "$line" | awk '{print $3}')
ifree=$(echo "$line" | awk '{print $4}')
iusepct=$(echo "$line" | awk '{print $5}' | tr -d '%')
mounted=$(echo "$line" | awk '{print $6}')

if [ "$iusepct" -gt "$THRESHOLD" ]; then
echo "警告:$mounted 分区 inode 使用率 ${iusepct}%" | mail -s "Inode 告警" $EMAIL
fi
done < <(df -i | tail -n +2)

3. 添加定时任务

1
2
3
# 每天凌晨 2 点检查 inode 使用情况
$ crontab -e
0 2 * * * /usr/local/bin/inode_check.sh

故障复盘

根因分析

  1. 直接原因:某应用日志配置不当,未启用日志轮转,导致日志文件无限增长
  2. 间接原因
    • 缺少 inode 使用率监控
    • 未设置日志保留策略
    • 文件系统选型不当(ext4 固定 inode 数量)

改进措施

  1. ✅ 优化应用日志配置,启用 logrotate
  2. ✅ 添加 inode 监控告警(阈值 80% 警告,90% 危急)
  3. ✅ 编写定期清理脚本,清理 30 天前的日志
  4. ✅ 新服务器采用 xfs 文件系统(动态 inode)
  5. ✅ 将 inode 检查纳入日常巡检清单

总结

inode 耗尽是 Linux 运维中常见但容易被忽视的问题。关键要点:

  1. 诊断:使用 df -i 快速确认是否为 inode 问题
  2. 定位:使用 find 命令逐层统计文件数量
  3. 处理:清理无用文件 + 优化日志轮转 + 应用层优化
  4. 预防:添加监控告警 + 定期巡检 + 合理选型

记住:磁盘空间充足 ≠ 可以正常写入,inode 同样重要!