如何查找服务/用户打开的文件(lsof 显示的结果非常不一致)

如何查找服务/用户打开的文件(lsof 显示的结果非常不一致)

我遇到了一个问题,可能是由于服务打开了太多文件造成的。我试图检查它打开了哪些文件,并监控它随时间的变化。这是在 CentOS 7 上,所以我猜lsof是我的朋友 - 但是,我无法理解结果。

我的服务以富有想象力的“service_user”名称运行。它是该机器上唯一一个以该名称运行的进程。

我假设使用lsof -u service_user会给我该用户打开的文件,我只需计算它们(最初,然后可能检查详细信息)。这里的数字对于服务来说是合理的,当然不表示存在问题。但是,如果我进行全面lsof过滤,只保留提及 service_user 的文件,我会得到三个数量级以上的文件!

[root ~]# lsof -u service_user | wc -l
1442
[root ~]# lsof | grep service_user | wc -l
1631673

我想看看机器上每个进程和用户的总数(以确认我的进程是否是罪魁祸首)并尝试对输出进行一些简单的操作,lsof但如果使用了标志或未使用了标志,则显示的列会有所不同-u- 完整lsof包含一个time通常是空白的列,并且使提取列变得棘手。

我尝试使用 -F 标志来指定列,并编写了以下脚本,我将输出导入其中,lsof -F pcLf以便尝试将其处理为我可以处理的内容。这些结果与数字大致一致- 比结果lsof | grep service_user大三个数量级lsof -u service_user

#!/bin/bash

IFS=""
echo -e "PID\tCommand\tUser\tNumber of Files"
OUTPUT=
N=0


function add_tab() {
        OUTPUT+=$(echo -e "\t")
}

function write_out_and_reset() {
        if [[ -n "$OUTPUT" ]]; then
                echo "$OUTPUT$N"
        fi
        OUTPUT=
        N=0
}

function add_value_to_output() {
        local LINE="$1"
        OUTPUT+="${LINE:1}"
        add_tab
}

while read -r LINE || [ -n "$LINE" ]; do
        case "${LINE:0:1}" in
                'p')
                        write_out_and_reset
                        add_value_to_output "$LINE"
                        ;;
                'c')
                        add_value_to_output "$LINE"
                        ;;
                'u')
                        add_value_to_output "$LINE"
                        ;;
                'L')
                        add_value_to_output "$LINE"
                        ;;
                'f')
                        N=$((N+1))
                        ;;
                *)
                        echo
                        echo "Unknown line $LINE"
                        ;;
        esac
done

write_out_and_reset

问题

  1. 如何才能可靠地找出给定进程或用户打开了多少个文件?
  2. 如何才能可靠地获得每个用户/进程在机器上打开的所有文件的总和?
  3. 如何可靠地列出特定用户或进程打开的所有文件?

我也想了解为什么我会得到如上所述的不同结果,但主要问题是应该相信哪一个,这样我才能继续调查我的实际问题。

答案1

打开文件的限制是针对每个进程的,因此我认为计算每个用户的打开文件数是没有意义的 - 特定的守护进程要么达到其限制,要么没有。

要查看特定进程的打开的文件,请使用以下方法之一:

  • ls -l /proc/<pid>/fd
  • lsof -p <pid> -d fd -a -n
  • lsfd -p <pid> -Q "FD >= 0"
    (lsfd 在 CentOS 7 上不存在,但可以在较新的发行版中找到)

要按用户列出它们,请使用:

  • lsof -u <user> -d fd -a -n
  • lsfd -Q "(USER == '<user>') && (FD >= 0)"

但请注意,lsof 和 lsfd 还显示各种其他资源,例如内存映射,不要计算打开文件数限制。您只需要计算文件描述符。

但是,如果我使用完整的 lsof 并过滤掉那些提到 service_user 的文件,我会得到多三个数量级的文件!

如果没有-u过滤器,lsof 也会报告每个线每个进程的 - 这会导致重复输出,因为进程中的所有线程共享相同的文件描述符和大多数其他资源(特殊情况除外)。因此,如果一个进程有 10 个线程(包括主线程),lsof则会报告相同的文件描述符 10 次。添加-Ki选项以避免这种情况。

相关内容