LabHub
学习 学习路径 课程

Linux 故障处理

文件描述符与上限诊断

在 LabHub 中继续学习

目标

确认文件描述符限制存在几个层级,并亲手制作追踪 fd 泄漏的工具。

为什么重要

看到 Too many open files 时,几乎所有人都会执行 ulimit -n 65536。但这个值只是当前 shell 的值,对已经运行的服务毫无影响。真正需要查看的是 /proc/<PID>/limits,实际使用量则是 ls /proc/<PID>/fd | wc -llsof -p 还会统计 cwd、可执行文件和 mmap 库,而这些不计入限制)。提高限制很少是真正的答案——多数情况是泄漏,提高限制只是把故障推迟几个小时。泄漏还是正常负载,要根据 fd 数量的增长模式来区分。

步骤

/root/fd 目录中工作。

  1. /proc/1/limits 读取打开文件限制,并按以下两行写入 /root/fd/limits.txt
    • soft=<값>
    • hard=<값>
  2. 在后台启动一个同时打开 /etc/hostname 至少 50 次的进程,并把 PID 写入 /root/fd/holder_pid.txt。该进程必须在后续步骤中始终存活。
  3. 在该进程的 fd 中,统计指向 /etc/hostname 的数量,以及它们所指向的不同目标数量,按以下两行写入 /root/fd/distinct.txt
    • count=<개수>
    • distinct=<개수>
  4. 在降低限制的环境中持续打开文件,重现 Too many open files 错误,并把消息保存到 /root/fd/emfile.txt
  5. 只把整个系统的 fd 上限数字写入 /root/fd/file_max.txt
  6. 在后台启动 python3 -m http.server 8099 --bind 127.0.0.1,并把 PID 写入 /root/fd/http_pid.txt
  7. 创建 /root/fd/fdtop.sh <N>。把打开 fd 数量最多的 N 个进程按 <fd개수> <PID> 格式降序输出。必须正好输出 N 行。
  8. /etc/hostname 的 inode 编号写入 /root/fd/inode.txt

提示

读取真实限制

/proc/1/limits 读取打开文件限制,并按以下两行写入 /root/fd/limits.txt

不要查看当前 shell 的 ulimit,而要查看该进程的 /proc//limits。‘Max open files’行会并排显示 soft 与 hard。

占用 50 个 fd

在后台启动一个同时打开 /etc/hostname 至少 50 次的进程,并把 PID 写入 /root/fd/holder_pid.txt。该进程必须在后续步骤中始终存活。

可以用 python3 多次打开同一个文件,保存到列表中,然后 sleep。如果不保存在变量中,文件会立即关闭。

统计 fd 数量与目标数量

在该进程的 fd 中,统计指向 /etc/hostname 的数量,以及它们所指向的不同目标数量,按以下两行写入 /root/fd/distinct.txt

对 /proc//fd 中的每一项执行 readlink,确认其目标。观察多次打开同一文件时会发生什么。

重现 EMFILE

在降低限制的环境中持续打开文件,重现 Too many open files 错误,并把消息保存到 /root/fd/emfile.txt

在子 shell 中降低 ulimit -n,然后不断打开文件。把错误消息保存到文件。

读取系统整体上限

只把整个系统的 fd 上限数字写入 /root/fd/file_max.txt

/proc/sys/fs/file-nr 包含三个数字,最后一个是最大值。

套接字也是 fd

在后台启动 python3 -m http.server 8099 --bind 127.0.0.1,并把 PID 写入 /root/fd/http_pid.txt

在 127.0.0.1 上启动 python3 -m http.server,再对该进程的 fd 执行 readlink。

列出 fd 数量最多的进程

创建 /root/fd/fdtop.sh <N>。把打开 fd 数量最多的 N 个进程按 <fd개수> <PID> 格式降序输出。必须正好输出 N 行。

统计 /proc/*/fd 中的项目数并排序。跳过发生权限错误的项目。

从 fd 追踪到 inode

/etc/hostname 的 inode 编号写入 /root/fd/inode.txt

用 stat -L 跟随符号链接,就能得知该 fd 指向文件的 inode。