news 2026/9/17 13:13:27

Linux mkdir报No space left on device?真相是inode耗尽

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux mkdir报No space left on device?真相是inode耗尽

1. 问题本质:为什么“磁盘空间不足”报错会出现在 mkdir 这种看似不写数据的操作上?

在 Linux 系统里敲下mkdir testdir,终端却冷不丁甩出一句mkdir: cannot create directory ‘testdir’: No space left on device,你第一反应肯定是——打开df -h看一眼,发现/分区还剩 20GB,/home更有 80GB 余量,明明硬盘没满,怎么就“空间不足”了?这绝不是系统在跟你开玩笑,而是 Linux 文件系统底层机制在发出明确警告:设备级资源已耗尽,连创建一个空目录都做不到

这个报错的核心关键词是No space left on device,注意它说的是device(设备),而不是disk(磁盘)或partition(分区)。它指向的不是我们日常理解的“存储容量”,而是文件系统层面两个独立且并行管理的资源池:块(block)和 inode。绝大多数人只关注块(即df -h显示的“Available”列),却忽略了 inode 这个隐形守门员。而mkdir操作,恰恰是对 inode 资源最敏感的动作之一——它不需要写入任何用户数据块,但必须向文件系统申请一个全新的 inode 来描述这个新目录的元数据(权限、所有者、时间戳、目录项指针等)。如果 inode 池枯竭,哪怕磁盘还有 1TB 空间,mkdirtouchcp(新建文件)、git clone(创建大量小文件)全部都会被无情拒绝。

这个问题在实际运维中高频出现,尤其集中在三类场景:一是日志系统(如 Nginx、Java 应用日志滚动产生海量小文件);二是容器环境(Docker/Kubernetes 的临时卷、镜像层叠加导致 inode 快速消耗);三是开发环境(Node.js 项目node_modules动辄数万甚至数十万个文件,Git 仓库频繁 checkout 切换分支生成大量临时 inode)。我曾在一台 500GB 的生产数据库服务器上见过df -h显示根分区使用率仅 42%,但df -i却显示 inode 使用率高达 99.8%,结果连systemctl restart nginx都失败——因为重启服务时 systemd 会尝试写入新的 journal 日志条目,需要申请新 inode。

所以,当你看到这个报错,第一件事不是删大文件,而是立刻执行df -i。这是诊断的起点,也是区分“真空间不足”和“假空间不足”的唯一金标准。它不是 bug,是 Linux 文件系统设计的严谨性体现:inode 是文件系统的“身份证发放中心”,没有身份证,再大的房子也住不进新人。

2. 根本原因深度拆解:inode 耗尽的五大典型路径与底层逻辑

No space left on device报错背后,inode 耗尽并非偶然,而是有清晰可追溯的成因链条。下面我结合多年处理线上事故的经验,把最常见的五种路径掰开揉碎讲透,不仅告诉你“是什么”,更要说明“为什么偏偏是它”。

2.1 日志风暴:小文件海啸式生成

这是企业级服务器上最经典的 inode 杀手。以 Nginx 为例,每处理一个 HTTP 请求,就会在access.log中追加一行;当开启error.logdebug级别时,单个请求可能生成数十行日志。假设一个高并发 API 服务每秒处理 500 个请求,access.log每天新增约 4300 万行。如果未配置 logrotate 或轮转策略,这些日志会持续追加到同一个文件,看似只占一个 inode。但问题在于:当日志文件被重命名(如mv access.log access.log.1)或截断(> access.log)时,旧文件的 inode 并不会立即释放。Linux 的文件删除机制是“引用计数归零才回收”,只要还有进程(比如正在 tail -f 的监控脚本、或尚未关闭日志句柄的 Nginx worker 进程)持有该文件的打开句柄,这个 inode 就永远处于“已删除但未释放”状态,持续占用 inode 池。

实操验证:lsof +L1命令能直接列出所有被删除但仍被进程占用的文件(即“幽灵文件”)。我曾在一个客户现场执行此命令,发现nginx进程竟持有了 17 个已被logrotate重命名的旧日志文件,每个文件大小从几 MB 到几百 MB 不等,但它们共同吞噬了超过 20 万个 inode。这才是真正的“看不见的消耗”。

2.2 容器与临时文件系统:overlay2 的 inode 陷阱

Docker 默认使用overlay2存储驱动,其工作原理是在宿主机上为每个容器创建一层“upperdir”(可写层)和“lowerdir”(只读镜像层)。每次容器内执行apt installnpm installpip install,都会在 upperdir 中创建海量小文件(.so库、.pyc字节码、package.json等)。更致命的是,容器退出时,upperdir 目录本身不会被自动清理。如果你频繁启停测试容器(比如 CI/CD 流水线每构建一次就起一个新容器),/var/lib/docker/overlay2/下会堆积成千上万个残留的 upperdir 目录,每个目录本身就是一个 inode,其内部文件又消耗更多 inode。docker system prune -a可以清理,但很多团队只记得prune镜像,忘了-v参数(--volumes)才能清理 volumes,而 upperdir 的 inode 就卡在 volumes 的阴影里。

一个量化案例:一个基础 Ubuntu 镜像docker run -it ubuntu:22.04 bash启动后,df -i /var/lib/docker显示 inode 使用率 12%;执行apt update && apt install -y curl后,飙升至 28%;若重复此过程 10 次(模拟 10 个不同构建环境),即使删除所有容器,inode 使用率仍停留在 65% 以上——因为 overlay2 的 cleanup 机制并不彻底。

2.3 临时文件与缓存:/tmp 和 /var/tmp 的“黑洞”

/tmp目录通常挂载为tmpfs(内存文件系统),其 inode 数量默认与内存大小强相关。例如,一台 16GB 内存的机器,tmpfs的 inode 上限可能是 200 万。但问题在于:很多程序(尤其是 Java 应用、Python 的tempfile.mkstemp())会在此创建临时文件,却因异常退出未能清理。这些文件在tmpfs中不占磁盘块,但每个文件都独占一个 inode。更隐蔽的是/var/tmp,它通常是磁盘分区的一部分,但常被忽略。systemd-tmpfiles服务负责定期清理/tmp,但/var/tmp的清理策略由管理员自定义,一旦配置疏漏(如AgeSec=设置过大),数月积累的临时文件就能填满 inode。

经验判断:find /tmp -type f -mtime +30 | wc -l如果返回值超过 10000,基本可以判定/tmp是 inode 消耗大户。而/var/tmp则需检查ls -la /var/tmp,重点关注systemd-private-*开头的目录——这是 systemd 为每个服务实例创建的私有 tmp 目录,若服务崩溃未清理,它们就是永久性 inode 占位符。

2.4 文件系统碎片化与小文件密集型应用

Ext4/XFS 等现代文件系统虽支持海量文件,但 inode 分配并非无限。创建文件系统时,mkfs.ext4默认按每 16KB 数据块分配 1 个 inode(可通过-i参数调整)。这意味着一个 100GB 的分区,若按默认比例,最多只能创建约 650 万个 inode。当你的应用是典型的“小文件密集型”时,这个上限很快见顶。典型代表包括:

  • Git 仓库:每个 commit 对象、tree 对象、blob 对象都是独立文件,一个中等规模仓库(10k commits)轻松生成 50 万+ objects;
  • 数据库 WAL 日志:PostgreSQL 的pg_wal目录下,每个 WAL 段文件(通常 16MB)就是一个 inode,高负载下每分钟生成多个;
  • 编译缓存:ccache默认将每个编译单元的缓存存为独立文件,C++ 项目头文件爆炸式增长时,cache 目录 inode 消耗速度惊人。

关键洞察:df -i显示的IUse%是全局统计,但它无法告诉你 inode 分布在哪。debugfs -R "stat /" /dev/sda1(Ext4)或xfs_info /dev/sda1(XFS)能查看文件系统创建时的 inode 总数,而find /path -xdev -type f | wc -l才是定位具体目录的精确手段。

2.5 用户态文件系统(FUSE)与挂载点污染

这是一个容易被忽视的“高级陷阱”。当你使用sshfsrclone mountgocryptfs挂载远程或加密文件系统时,这些 FUSE 实现会在内核中注册一个新的虚拟文件系统。每个挂载点本身会消耗少量 inode,而更重要的是,挂载点下的文件操作,其 inode 申请行为完全由 FUSE 后端控制,不受宿主机df -i统计约束。例如,rclone mount gdrive:/myfolder /mnt/gdrive后,在/mnt/gdrivemkdir test,实际是向 Google Drive API 发起请求,成功与否取决于云端配额,而非本地 inode。但此时,如果挂载过程出错(如网络中断导致 FUSE 进程僵死),/mnt/gdrive目录会变成一个“不可访问的黑洞”,ls /mnt/gdrive可能卡住,df -i却看不到它——因为它不属于任何本地块设备。这种情况下,No space left on device报错往往伴随Transport endpoint is not connected,提示你问题不在本地 inode,而在挂载点本身。

排查口诀:遇到报错,先mount | grep fuse,再ps aux | grep rclone\|sshfs,确认所有 FUSE 进程状态。强行umount -l /mnt/gdrive(lazy unmount)往往是最快恢复手段。

3. 排查全流程:从现象到根因的七步精准定位法

面对No space left on device,盲目rm -rf可能引发灾难。我总结了一套经过上百次线上故障验证的七步法,确保每一步都有明确目标、可执行命令和预期输出,帮你像侦探一样锁定真凶。

3.1 第一步:确认报错根源——区分 block 与 inode

这是所有后续动作的前提。执行两条命令,缺一不可:

df -h # 查看磁盘块使用率 df -i # 查看 inode 使用率

重点观察Use%列。如果df -h显示Use%在 85% 以下,而df -i显示Use%接近或等于 100%,则 100% 确定是 inode 耗尽。反之,若df -hUse%也高达 95% 以上,则需优先处理大文件。永远不要跳过这一步。我曾见过运维同事直接du -sh /* 2>/dev/null | sort -hr | head -20扫描大文件,结果发现/var/log只有 2GB,却花了 20 分钟,而df -i早在 5 秒内就指出/var/lib/docker的 inode 使用率是 99.3%。

提示:df -iIUsed列是已用 inode 数,IFree是剩余 inode 数。计算公式:IUse% = (IUsed / (IUsed + IFree)) * 100。注意,IFree为 0 并不意味着绝对无法创建文件——文件系统会保留少量 inode(通常是 5%)给 root 用户,所以IUse%达到 95% 就该预警。

3.2 第二步:定位高 inode 消耗分区——聚焦根因所在

df -i输出可能包含多个挂载点(/,/home,/var,/boot等)。找出IUse%最高的那个。例如:

Filesystem Inodes IUsed IFree IUse% Mounted on /dev/sda1 5242880 5242879 1 100% / /dev/sdb1 26214400 12000000 14214400 46% /home

显然,根分区/是问题核心。此时,切勿在/下盲目搜索,因为/proc/sys等虚拟文件系统会干扰结果。正确做法是限定搜索范围:

# 只扫描真实块设备挂载点,排除虚拟文件系统 find / -xdev -type d 2>/dev/null | head -20

-xdev参数是关键,它告诉find不要跨越文件系统边界,确保只在/分区内部搜索。接下来,我们需要找到哪个目录下的文件最多。

3.3 第三步:揪出 inode 密集目录——按文件数量排序

在确定的高消耗分区(如/)内,执行:

# 统计每个子目录下的文件总数(含子目录) find / -xdev -type f 2>/dev/null | cut -d "/" -f 2 | sort | uniq -c | sort -nr | head -10

这条命令的精妙之处在于:

  • find / -xdev -type f:只找普通文件,排除目录、设备文件、socket 等;
  • cut -d "/" -f 2:提取路径的第二段(即/var/log中的var/usr/bin中的usr),这是顶层目录;
  • sort | uniq -c | sort -nr:统计每个顶层目录的文件数,并按降序排列。

典型输出:

428912 var 210345 usr 87654 home

这说明/var是罪魁祸首。接着,我们深入/var

# 进入 /var,统计其下二级目录文件数 find /var -maxdepth 2 -type f 2>/dev/null | cut -d "/" -f 3 | sort | uniq -c | sort -nr | head -10

输出可能显示log占比最高。此时,ls -l /var/log会看到一堆app.log.1,app.log.2.gz,nginx-access.log等文件。但这还不够,我们需要确认是否是“幽灵文件”。

3.4 第四步:检测幽灵文件——被进程占用的已删除文件

执行:

lsof +L1 2>/dev/null | awk '{print $1,$9}' | sort | uniq -c | sort -nr | head -10

+L1lsof的专属参数,专门列出链接数(link count)为 0 的文件,即已被rm删除但仍有进程打开的文件。awk '{print $1,$9}'提取进程名和文件路径,sort | uniq -c统计每个进程占用的幽灵文件数。

常见结果:

17 nginx 8 java 3 rsyslogd

这直接指向了 Nginx 和 Java 应用。下一步,查看 Nginx 具体持有哪些文件:

lsof -p $(pgrep nginx) | grep deleted

输出类似:

nginx 1234 root 5w REG 0,41 123456789 12345678 /var/log/nginx/access.log (deleted)

12345678是 inode 号,(deleted)是关键标识。此时,重启 Nginx (systemctl restart nginx) 就能释放这批 inode。切记:重启前务必确认日志轮转配置已生效,否则重启后问题会重现

3.5 第五步:分析容器残留——Docker overlay2 深度清理

如果df -i指向/var/lib/docker,执行:

# 查看 overlay2 下各目录的 inode 占用 du -s --inodes /var/lib/docker/overlay2/*/diff 2>/dev/null | sort -n | tail -10

--inodes参数让du统计 inode 数而非磁盘大小。输出可能显示某个long-hash-string/diff目录占用 50 万个 inode。这极大概率是已停止但未清理的容器。此时,安全清理步骤是:

# 1. 列出所有已停止但未删除的容器 docker ps -a --filter "status=exited" --format "{{.ID}}" # 2. 删除所有已退出容器(谨慎!确认无重要数据) docker rm $(docker ps -a -q --filter "status=exited") # 3. 清理 dangling 镜像和 build cache docker image prune -f docker builder prune -f # 4. 最后,强制清理 overlay2(仅当上述无效时) # 注意:此操作会删除所有未运行容器的文件系统层 docker system prune -a -f --volumes

注意:docker system prune -a -f --volumes是“核武器”,执行前必须docker volume ls确认无重要持久化卷。我建议先用docker system df -v查看详细磁盘使用,它会明确列出Local VolumesBuild Cache的大小和数量,比盲目prune更安全。

3.6 第六步:检查挂载点健康——FUSE 与 NFS 的隐形故障

如果df -i无异常,但mkdir仍报错,立即检查挂载状态:

# 列出所有挂载点,特别关注 type 为 fuse.* 或 nfs 的 mount | grep -E "(fuse|nfs)" # 检查对应挂载点是否可访问 ls -la /mnt/myfuse 2>/dev/null || echo "Mount point inaccessible"

ls卡住或报错Transport endpoint is not connected,则问题在挂载点。解决方案:

  • 对于sshfsfusermount -u /mnt/sshfs卸载,然后重新sshfs user@host:/path /mnt/sshfs
  • 对于rclonekillall rclone,再umount -l /mnt/gdrive,最后重启rclone mount
  • 对于 NFS:showmount -e nfs-server-ip测试服务端可达性,umount -f /mnt/nfs强制卸载。

3.7 第七步:终极验证——创建测试文件确认修复

所有清理操作完成后,必须进行闭环验证:

# 1. 创建一个新目录 mkdir /tmp/test_inodes_$(date +%s) # 2. 在其中创建 100 个空文件 for i in {1..100}; do touch /tmp/test_inodes_$(date +%s)/file$i; done # 3. 检查是否成功 ls -l /tmp/test_inodes_$(date +%s) | wc -l # 应输出 100 # 4. 清理测试目录 rm -rf /tmp/test_inodes_$(date +%s)

如果mkdirtouch全部成功,且df -iIFree值明显上升(例如从 12 增加到 10000),则问题已解决。不要跳过验证。我曾遇到一次案例,df -i显示IFree从 0 变为 5,但mkdir仍失败——原因是文件系统保留的 5 个 inode 只供 root 使用,普通用户权限不足。此时需sudo mkdir测试,或调整sysctl fs.inotify.max_user_watches(虽然这不直接影响 inode,但常被误认为相关)。

4. 解决方案与长效防护:从急救到免疫的完整体系

排查只是开始,真正体现专业性的,是建立一套既能快速止血又能杜绝复发的防护体系。下面是我为不同角色(开发者、运维、SRE)定制的解决方案矩阵,覆盖从命令行急救到架构级预防。

4.1 立即生效的急救命令集(5 分钟内恢复业务)

当报警响起,业务中断,你需要的是“开箱即用”的救命命令。以下命令均经过生产环境千锤百炼,按优先级排序:

第一优先级:释放幽灵文件(最常见,最快见效)

# 一键查找并 kill 占用 deleted 文件的进程(慎用!先确认进程可重启) lsof +L1 2>/dev/null | awk '{print $2}' | sort -u | xargs -r kill -HUP # 更安全的做法:针对特定进程重启 sudo systemctl restart nginx apache2 rsyslog sudo pkill -f "java.*application.jar" && sudo systemctl start myapp

第二优先级:清理容器垃圾(Docker 环境必做)

# 安全清理:只删已退出容器、悬空镜像、构建缓存 docker container prune -f docker image prune -f docker builder prune -f # 彻底清理(确认无数据后执行) docker system prune -a -f --volumes

第三优先级:日志轮转强制触发(Nginx/Apache/Java 通用)

# 对于 logrotate 管理的日志 sudo logrotate -f /etc/logrotate.conf # 对于 systemd-journald sudo journalctl --vacuum-size=500M # 限制日志总大小 sudo journalctl --vacuum-time=2weeks # 删除 2 周前日志

第四优先级:临时扩容 inode(应急之选,不推荐长期使用)

# Ext4 文件系统:在线扩容 inode(需有足够未分配空间) # 此操作风险极高,必须先 `e2fsck -f /dev/sda1`,且无法缩减 # 生产环境强烈建议重建文件系统,而非在线扩容 # (此处不提供具体命令,因误操作将导致数据丢失)

注意:所有killrestart操作前,务必systemctl status service-name确认服务状态,并评估业务影响。kill -HUP是平滑重启信号,比kill -9安全得多。

4.2 长效防护机制:从配置到监控的三层防线

急救解决当下,防护保障未来。我将防护体系分为三个层级,层层递进:

第一层:配置加固——在问题发生前就筑墙

  • 日志轮转(Log Rotation)
    编辑/etc/logrotate.d/nginx(或其他服务配置),确保包含:

    /var/log/nginx/*.log { daily missingok rotate 30 # 保留 30 天 compress delaycompress notifempty create 0644 nginx nginx # 确保新文件权限正确 sharedscripts postrotate if [ -f /var/run/nginx.pid ]; then kill -USR1 `cat /var/run/nginx.pid` fi endscript }

    关键点:rotate 30限制数量,compress减少磁盘块占用,postrotate中的kill -USR1通知 Nginx 重新打开日志文件,避免幽灵文件。

  • 容器生命周期管理
    在 Docker Compose 或 Kubernetes YAML 中,强制设置restart: unless-stoppedstop_grace_period: 30s,确保容器异常退出后能被自动拉起,且优雅终止。对于 CI/CD 流水线,添加docker system prune -f作为 job 结束步骤。

  • 临时目录自动清理
    编辑/etc/tmpfiles.d/custom.conf

    # Type Path Mode UID GID Age d /tmp/appcache 0755 root root 1d d /var/tmp/build 0755 root root 3d

    systemd-tmpfiles --create会按此规则自动清理。

第二层:监控告警——让问题在爆发前就浮现

仅靠人工df -i是落后的。必须接入监控系统:

  • Prometheus + Node Exporter
    关键指标:node_filesystem_files_free{mountpoint="/",fstype="ext4"}node_filesystem_files{mountpoint="/",fstype="ext4"}
    告警规则(PromQL):

    (node_filesystem_files{mountpoint="/"} - node_filesystem_files_free{mountpoint="/"}) / node_filesystem_files{mountpoint="/"} * 100 > 90

    触发阈值设为 90%,留出 10% 缓冲。

  • Zabbix 自定义监控项
    vfs.fs.inode.pfree[/](inode 空闲百分比),触发器表达式:{HOSTNAME:vfs.fs.inode.pfree[/].last()}<10

  • Shell 脚本轻量监控(无监控系统时)

    # /usr/local/bin/check-inodes.sh THRESHOLD=90 INODE_USE=$(df -i / | awk 'NR==2 {print $5}' | sed 's/%//') if [ "$INODE_USE" -gt "$THRESHOLD" ]; then echo "ALERT: Inode usage on / is ${INODE_USE}%" | mail -s "Inode Alert" admin@example.com logger "Inode usage critical: ${INODE_USE}%" fi

    加入 crontab:0 * * * * /usr/local/bin/check-inodes.sh

第三层:架构优化——从源头消灭小文件

这是最高阶的防护,需要开发与运维协同:

  • 日志聚合
    放弃文件日志,改用fluentd+ElasticsearchLoki。日志以流式方式发送,后端按时间分片存储,单个日志条目不再对应一个文件 inode。

  • 对象存储替代本地存储
    node_modulesvendorbuild artifacts等非核心数据,通过rclone同步到 S3/MinIO。本地只保留符号链接或 manifest 文件,彻底规避 inode 消耗。

  • 数据库替代文件系统
    对于需要“海量小文件”的场景(如用户上传的头像、文档),设计为将文件内容存入 PostgreSQL 的BYTEA字段或使用pg_largeobject,文件元数据存入表。一个INSERT操作只消耗 1 个 inode,而非n个。

4.3 开发者避坑指南:代码层面的 inode 友好实践

作为一线开发者,你的代码习惯直接影响服务器健康。以下是必须遵守的铁律:

  • 禁止在/tmp创建永久性文件
    tempfile.mkstemp()创建的文件,必须用try/finally确保os.unlink();Node.js 的fs.writeFileSync('/tmp/cache.json', data)后,必须fs.unlinkSync('/tmp/cache.json')。更好的方案是使用with tempfile.NamedTemporaryFile(delete=False)(Python)或fs.promises.mkdtemp()(Node.js),让框架管理生命周期。

  • 压缩小文件集合
    Java 的maven-assembly-plugin、Python 的setuptools,都支持将依赖打包成单个 JAR/WHEEL 文件。npm pack生成 tarball 也比node_modules目录节省 99% 的 inode。

  • Git 优化
    对于大型二进制文件,启用git-lfs;对历史仓库,用git filter-repo --strip-blobs-bigger-than 10M清理大文件。git gc --aggressive能合并松散对象,减少 inode。

  • 构建缓存共享
    CI/CD 中,ccachesccache的缓存目录应挂载为网络共享存储(如 NFS),而非每个 runner 独立一份,避免缓存副本爆炸。

5. 常见问题与独家排错技巧实录:那些文档里找不到的真相

在上千次No space left on device故障处理中,我积累了大量“只可意会不可言传”的实战技巧。这些不是教科书知识,而是踩过坑、流过血后的真实记录。

5.1 “df -i 显示有剩余,但 mkdir 仍失败” —— root 保留 inode 的迷雾

现象:df -i显示IFree为 1234,IUse%为 99.8%,但sudo mkdir /test成功,mkdir /test却失败。
真相:Ext4 文件系统默认保留 5% 的 inode 给 root 用户(reserved blocks percentage的 inode 版本)。df -iIFree包含这部分,但普通用户无法使用。计算公式:
可用 inode(普通用户) = IFree - (Total Inodes * 0.05)
因此,当IFree < Total * 0.05时,普通用户就彻底失去创建权限。
独家技巧sudo tune2fs -l /dev/sda1 | grep "Reserved block count"查看保留值,sudo tune2fs -m 1 /dev/sda1可将保留比例降至 1%(仅限非系统分区,谨慎操作)。

5.2 “lsof +L1 什么都没输出,但 inode 还是满了” —— XFS 文件系统的特殊性

现象:在 XFS 文件系统上,lsof +L1返回空,但df -i显示 100%。
真相:XFS 的 inode 管理机制与 Ext4 不同,lsof +L1对 XFS 的支持不完善。XFS 的“幽灵文件”更常表现为xfs_info显示ino64(64 位 inode)但df -i统计异常。
独家技巧:XFS 下,优先执行xfs_info /dev/sda1确认文件系统状态,然后用xfs_db -r -c "freesp -d" /dev/sda1检查空闲空间位图,再结合xfs_spaceman -t /dev/sda1查看详细分配。更简单的方法是xfs_info /dev/sda1 | grep "imaxp"imaxp值过低(如 < 1000)表明 inode 分配组已满。

5.3 “重启服务后,inode 使用率不降反升” —— 日志轮转的“假释放”

现象:systemctl restart nginx后,df -iIUse%从 99.2% 变成 99.5%。
真相:logrotate 的copytruncate模式会先复制日志文件,再清空原文件。复制操作本身会创建一个新 inode,而原文件的 inode 因被进程持有并未释放,导致“一进一出”,净增 1 个 inode。
独家技巧:禁用copytruncate,改用create模式,并在postrotate中用kill -USR1通知服务 reopen 日志。这样,旧文件 inode 被释放,新文件 inode 被创建,总量不变。

5.4 “容器内 mkdir 失败,但宿主机 df -i 正常” —— cgroups 的 inode 配额

现象:Docker 容器内执行mkdir报错,但docker exec -it container df -i显示IUse%仅 20%,宿主机df -i也正常。
真相:Kubernetes 或 Docker 的--ulimitcgroups v2可能对容器设置了pids.maxio.max,间接影响 inode 分配。更常见的是,容器使用的overlay2lowerdir 是只读的,upperdir 的 inode 配额由overlay2自身管理,df -i无法反映。
独家技巧:进入容器,执行cat /proc/1/mountinfo | grep overlay,找到upperdir路径,然后在宿主机上df -i /var/lib/docker/overlay2/xxx/diff查看真实 inode 使用。

5.5 “vscode 在 WSL2 中提示 no space left on device” —— WSL2 的虚拟磁盘膨胀

现象:Windows 上的 VS Code 连接 WSL2 Ubuntu,编辑文件时弹窗报错,但wsl -d Ubuntu df -i显示一切正常。
真相:WSL2 底层是一个ext4.vhdx虚拟磁盘文件。当大量小文件被创建(如npm install),vhdx文件会动态增长,但 Windows 的磁盘空间不足时,vhdx无法扩展,

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/17 13:13:20

Oracle数据库归档模式开启与运维实战指南

1. 归档模式是什么&#xff0c;生产库为什么要开先讲一个真实的教训。我早年间接手过一套跑了两年的业务系统&#xff0c;数据库跑在非归档模式下&#xff0c;每天凌晨做一次全量备份。当时觉得备份有了就万事大吉&#xff0c;结果某天凌晨磁盘阵列突然坏了两块盘&#xff0c;数…

作者头像 李华
网站建设 2026/9/17 13:12:08

Java+Vue+SpringBoot构建高校讲座预约系统全解析

学生时代最头疼的事之一&#xff0c;就是去听一场热门讲座。我记得那时候&#xff0c;学术报告厅门口经常堵成一锅粥&#xff0c;工作人员拿着纸质名单挨个核对&#xff0c;有人提前一小时去占座&#xff0c;有人临时来却发现座位已满。后来我帮学校信息化中心做了一个高校学习…

作者头像 李华
网站建设 2026/9/17 13:10:27

SCI论文返修回复模板:结构化响应提升录用率

简介&#xff1a;本资源是一份专为SCI论文作者设计的审稿意见回复模板文档&#xff0c;面向科研人员、硕博研究生及高校教师&#xff0c;解决SCI投稿过程中如何专业、得体、高效回应审稿人质疑与修改要求的核心痛点。文档以Word&#xff08;.docx&#xff09;格式提供&#xff…

作者头像 李华
网站建设 2026/9/17 13:09:09

Mac双网卡路由配置详解:有线内网与Wi-Fi外网轻松分流

先说结论&#xff1a;这个需求在企业办公、开发调试场景里特别常见——Mac通过有线网卡连公司内网&#xff0c;同时用Wi-Fi连外网。很多人一上来就插两根网线或者连上两个网络&#xff0c;结果发现要么内网通外网断&#xff0c;要么外网通内网断&#xff0c;甚至两个都不通&…

作者头像 李华