为何root所使用的打开文件描述符的数量(或如何)超过ulimit -n?


13

我们的服务器最近用尽了文件描述符,对此我有些疑问。ulimit -n应该给我最大数量的打开文件描述符。这个数字是1024。我通过运行检查了打开文件描述符的数目,lsof -u root |wc -l得到了2500 fds。那远比1024多得多,所以我猜想那意味着1024是每个进程而不是每个用户的数量。好吧,我跑到lsof -p$PidOfGlassfish|wc -l了1300点。这是我没有得到的部分。如果ulimit -n不是每个用户或每个进程的最大进程数,那有什么用?不适用于root用户吗?如果是这样,那么我该如何获取有关文件描述符用尽的错误消息?

编辑:我唯一能理解的方法ulimit -n是,如果它应用打开文件的数量(如bash手册中所述),而不是文件句柄的数量(不同的进程可以打开同一文件)。如果是这种情况,那么仅列出打开文件的数量(在“ /”上增加,从而排除内存映射文件)是不够的

lsof -u root |grep /|sort  -k9  |wc -l #prints '1738'

要实际查看打开文件的数量,我需要仅在打印唯一条目时对名称列进行过滤。因此,以下可能更正确:

lsof -u root |grep /|sort  -k9 -u |wc -l #prints '604'

上面的命令期望lsof以以下格式输出:

java      32008 root  mem       REG                8,2 11942368      72721 /usr/lib64/locale/locale-archive
vmtoolsd   4764 root  mem       REG                8,2    18624     106432 /usr/lib64/open-vm-tools/plugins/vmsvc/libguestInfo.so

这至少使我的电话号码小于1024(由所报告的号码ulimit -n),因此这似乎是朝着正确方向迈出的一步。“不幸的是”我在用尽文件描述符时没有遇到任何问题,因此我将很难验证这一点。


2
lsof报告内存映射以及打开的文件,因此您的“ wc”管道会高估该进程使用的文件描述符的数量。
理查德·基特韦尔

啊哈!现在,这是个好信息。但是我不确定我是否理解。“内存映射”是指内存映射文件吗?根据我的理解,这将需要文件句柄,否则操作系统将如何更新文件?
oligofren 2012年

后续二:找到所有打开的文件句柄的最佳方法是什么-实际上受“ ulimit -n”施加的限制影响的那些句柄?
oligofren 2012年

1
内存映射不需要打开的文件。如果只想列出打开的文件,则过滤lsof的输出可能是最简单的方法。
理查德·凯特韦尔

谢谢,编辑了我的答案。使用“ lsof -u root | grep / | sort -k9 -u”似乎可以给出合理的答案。这至少比ulimit -n小。
oligofren 2012年

Answers:


9

我在Linux版本2.6.18-164.el5-Red Hat 4.1.2-46中进行了测试。我可以看到每个进程都应用了ulimit。

该参数在用户级别设置,但适用于每个过程。

例如:1024是限制。启动了多个进程,并使用计数了每个进程打开的文件

ls -l /proc/--$pid--/fd/ | wc -l

当多个进程打开的文件总数超过1024时,没有错误。我还验证了唯一文件计数,该计数结合了不同进程的结果并对唯一文件进行计数。仅当每个进程的计数超过1024时,错误才开始出现。(java.net.SocketException:进程日志中打开的文件太多)


感谢您对此进行测试。你知道为什么lsof -p$PidOfGlassfish|wc -l给我1300吗?我猜这两种计数方法有所不同。如果不是,那么限制可能不适用于root用户?
oligofren 2014年

只是好奇,为什么要使用ls -l代替lstotal 5当有5个文件时,后者有一个额外的行(例如)。在这种情况下ls -l ,在上面的示例中使用将报告6而不是5。我使用ls /proc/<pid>/fd | wc -l
starfry

@starfry那只是我的草率。我通常是逐步进行的,ls -l每行给我一个条目,然后将其输入其他内容。对于cours,这在正常管道传输时也会发生ls(但没有其他情况)。
oligofren

3

ulimit用于文件句柄。它适用于文件,目录,套接字,管道轮询,eventfds,timerfds等。

在过程启动期间的任何时候,限制都可能已更改。访问/proc/<pid>/limits并查看值是否已更改。


3

@oligofren

我也进行了一些测试,以确定如何"ulimits -Sn""open files"被执行。

  • 就像链接中提到的选择的海报一样,ulimit 确实适用于每个进程。要查看该流程的当前限制是什么:"open files"

    cat /proc/__process_id__/limits

  • 要确定一个进程已打开多少文件,您需要使用以下命令:

    lsof -P -M -l -n -d '^cwd,^err,^ltx,^mem,^mmap,^pd,^rtd,^txt' -p __process_id__ -a | awk '{if (NR>1) print}' | wc -l

上面的解释以及我的测试方法/结果

lsof"-P -M -l -n"参数只是为了使lsof尽可能快地运行。随时将它们取出。

-P - inhibits the conversion of port numbers to port names for network files
-M - disable reporting of portmapper registrations for local TCP, UDP and UDPLITE ports
-l - inhibits the conversion of user ID numbers to login names
-n - inhibits the conversion of network numbers to host names for network files

"-d '^cwd,^err,^ltx,^mem,^mmap,^pd,^rtd,^txt'"参数指示lsof排除类型为cwd / err / ltx / mem / mmap / pd / rtd / txt的文件描述符。

从lsof手册页:

   FD         is the File Descriptor number of the file or:

                   cwd  current working directory;
                   Lnn  library references (AIX);
                   err  FD information error (see NAME column);
                   jld  jail directory (FreeBSD);
                   ltx  shared library text (code and data);
                   Mxx  hex memory-mapped type number xx.
                   m86  DOS Merge mapped file;
                   mem  memory-mapped file;
                   mmap memory-mapped device;
                   pd   parent directory;
                   rtd  root directory;
                   tr   kernel trace file (OpenBSD);
                   txt  program text (code and data);
                   v86  VP/ix mapped file;

我认为"Lnn,jld,m86,tr,v86"不适用于Linux,因此不必理会将它们添加到排除列表中。我不确定"Mxx"

如果你的应用程序使用的内存映射文件/设备,那么你可能需要删除"^mem",并"^mmap"从排除列表中。

编辑---开始剪-

编辑:我发现以下链接指示:

从技术上讲,内存映射的.so文件与应用程序可以控制的文件句柄不同。/ proc // fd是打开文件描述符的测量点

因此,如果您的进程确实使用了内存映射文件,则需要过滤掉* .so文件。

另外,Sun的JVM将存储映射jar文件

内存映射的JAR文件,在这种情况下为包含“ JDK类”的文件。对JAR进行内存映射时,可以非常有效地访问其中的文件(与每次从头开始读取相比)。Sun JVM将在类路径上对所有JAR进行内存映射。如果您的应用程序代码需要访问JAR,则还可以对其进行内存映射。

因此,诸如tomcat / glassfish之类的内容也会显示内存映射的jar文件。我尚未测试这些数字是否会计入"ulimit -Sn"上限。

编辑-剪断-

根据经验,我发现每个进程文件限制(ulimit -Sn)"cwd,rtd,txt"不算在内

我不确定是否"err,ltx,pd"计入文件限制,因为我不知道如何创建这些描述符类型的文件句柄。

"-p __process_id__"参数限制lsof为仅返回__process_id__指定信息。如果要计数所有进程,请删除此选项。

"-a"参数用于AND的选择(即“-p”和“-d”参数)。

"awk '{if (NR>1) print}'"语句用于跳过lsof在其输出中打印的标题。

我使用以下perl脚本进行了测试:

File: test.pl
---snip---
#!/usr/bin/perl -w
foreach $i (1..1100) {
  $FH="FH${i}";
  open ($FH,'>',"/tmp/Test${i}.log") || die "$!";
  print $FH "$i\n";
}
---snip---

我必须在perl调试器中执行脚本,以确保脚本不会终止并释放文件描述符。

执行: perl -d test.pl

在perl的调试器中,您可以通过输入c并按Enter键来运行该程序,如果您ulimit -Sn的值是1024,您会发现该程序在中创建Test1017.log文件后停止了/tmp

如果现在确定perl进程的pid并使用上面的lsof命令,您将看到它也输出1024

删除"wc -l"并替换为"less"以查看计入1024个限制的文件列表。"-d ^....."还要删除该参数,以查看cwd,txtrtd描述符计入限制。

如果现在运行"ls -l /proc/__process_id__/fd/ | wc -l",则将返回1025的值。这是因为在其输出中添加了已计入ls"total 0"标头。

注意:

要检查操作系统是否用尽了文件描述符,最好比较以下值:

cat /proc/sys/fs/file-nr | awk '{print $1}'

cat /proc/sys/fs/file-max

https://www.kernel.org/doc/Documentation/sysctl/fs.txt文件什么file-nrfile-max平均值。


0

看来您的推理是这样的:“我必须降低该限制,以免耗尽宝贵的描述符”。事实恰恰相反—如果服务器用尽了文件描述符,则需要将该限制从1,024 提高到更大。对于实际的glassfish实现,32,768是合理的。

就我个人而言,我总是将系统范​​围的限制提高到8,192左右-1,024太荒谬了。但是你会想要提高glassfish。检查/etc/security/limits.conf。您可以为用户glassfish运行方式添加特殊条目。


我不确定您如何解释我的意思:-)我想知道的是为什么它似乎不适用。我将其设置得更高,但是我想了解它的工作原理。如果限制为1024,那么Glassfish如何拥有1300个句柄?
oligofren 2012年

'lsof -u root | grep / | sort -k9 -u'打印唯一的文件描述符条目。我猜想从中得到的行数是ulimit -n适用的实际数。
oligofren

0

您想查看在/ proc / sys / fs / file-max中设置的系统范围限制,并在那里进行调整(直到下次重新启动),或者在sysctl.conf中设置fs.file-max使其永久不变。这可能会有所帮助-http: //www.randombugs.com/linux/tuning-file-descriptors-limits-on-linux.html


1
关于bash的评论并不准确。ulimit为通过外壳程序启动的进程设置了每个用户ID的限制集,实际上这几乎是所有东西,这要归功于进程树如何在Unix之类的操作系统上生成。这不是猛击。
AugustBitTony 2012年

抱歉-将进行编辑,但是关于系统范围限制的评论仍然存在。
rnxrx 2012年

他极不可能达到系统范围的极限。可能,但不可能。
David Schwartz 2012年

EightBitTony:ulimit不会为每个用户ID限制集设置ulimit。应用pam_limits时的每个进程。“每个用户”的ulimit是“ ulimit -u”“单个用户可用的最大进程数”
无用户名

0

将原始lsof调用的结果与假定的限制进行比较的常见错误。

对于全局限制(/ proc / sys / fs / file-max),您应该查看/ proc / sys / fs / file-nr->第一个值指示使用的是什么,最后一个值是限制

OpenFile限制适用于每个进程,但是可以在用户上定义,请参见命令“ ulimit -Hn”以了解用户限制,并请参见/etc/security/limits.conf以获得定义。通常与“应用程序用户”一起使用,例如:“ tomcat”:将tomcat用户的限制设置为65000,该限制将应用于它运行的Java进程。

如果要检查在进程上应用的限制,请获取其PID,然后:cat / proc / $ {PID} / limits如果要检查进程打开了多少文件,请获取其PID,然后:ls -1 / proc / {PID} / fd | wc -l(请注意ls是“减一”,而不是“减一el”)

如果您想了解lsof的详细信息,但仅了解那些计入限制的文件处理程序,请尝试使用以下文件:lsof -p $ {PID} | grep -P“ ^(\ w + \ s +){3} \ d + \ D +” lsof -p $ {PID} -d'^ cwd,^ err,^ ltx,^ mem,^ mmap,^ pd,^ rtd, ^ txt'-a

备注:“文件”是文件/管道/ tcp连接/等。

请注意,有时您可能需要是root用户或使用sudo才能获得命令的正确结果,而没有特权有时则没有错误,只是结果较少。

最后,如果您想知道某个进程可以访问文件系统上的哪些“文件”,请查看:lsof -p {PID} | grep / | awk'{print $ 9}'| 排序 优衣库

玩得开心 !

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.