我遇到的问题可能是服务打开的文件过多所致。我正在尝试检查它打开了哪些文件并监视它如何随时间变化。这是在 CentOS 7 上,所以我认为lsof
是我的朋友——但是,我无法理解结果。
我的服务在富有想象力的标题“service_user”下运行。这是该机器上唯一的进程。
我假设 usinglsof -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
问题
- 我怎样才能可靠地找出给定进程或用户打开了多少文件?
- 对于机器上所有打开的文件,我如何可靠地获得每个用户/进程打开了多少文件的总和?
- 如何可靠地列出给定用户或进程打开的所有文件?
我还想了解为什么我会得到如上所述的不同结果,但主要问题是该信任哪个,以便我可以继续调查我的实际问题。
打开文件限制是每个进程的,所以我认为计算每个用户的打开文件没有意义——特定的守护进程达到了它的限制,或者没有。
要查看特定进程的打开文件,请使用以下之一:
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 还显示各种其他资源,例如内存映射,这些资源不计入打开文件限制。您只想计算文件描述符。
如果没有
-u
过滤器,lsof 还会报告每个进程的每个线程——这会导致重复输出,因为进程中的所有线程共享相同的文件描述符和大多数其他资源(奇怪的情况除外)。所以如果一个进程有10个线程(包括主线程),lsof
将报告同一个文件描述符10次。添加-Ki
选项以避免这种情况。