时间:2005-06-01 作者:Laurent Goldsztejn 浏览次数: 2816 本文关键字:"排错", "Too many open files", "Unix" |
无论文件类型是 socket 还是 pipe ,文件描述符对于标志不同类型的打开文件的进程来说是唯一的。当操作系统运行出现文件标志描述符不足时,就会抛出打开文件过多的异常。然而,文件描述符溢出则是更为复杂的问题的征兆,表明与这些文件相关联的资源没有正确被维护。让我们来看看如何诊断导致诸如此类异常的问题:
java.net.SocketException: Too many open
files
at java.net.PlainSocketImpl.accept(
Compiled Code)
at java.net.ServerSocket.implAccept(
Compiled Code)
at java.net.ServerSocket.accept(
Compiled Code)
at weblogic.t3.srvr.ListenThread.run(
Compiled Code)
|
和诸如此类的异常:
java.io.IOException: Too many open files at java.lang.UNIXProcess.forkAndExec( Native Method) at java.lang.UNIXProcess.( UNIXProcess.java:54) at java.lang.UNIXProcess.forkAndExec( Native Method) at java.lang.UNIXProcess.( UNIXProcess.java:54) at java.lang.Runtime.execInternal( Native Method) at java.lang.Runtime.exec( Runtime.java:551) at java.lang.Runtime.exec( Runtime.java:477) at java.lang.Runtime.exec( Runtime.java:443) |
第一个异常在错误影响到底层的 TCP 协议时抛出,而第二个异常则在错误影响到 I/O 操作时抛出。这两个异常都是出现阻塞服务器的类似问题的征兆。该问题可通过下面的研究方法来解决。
第二个异常在 JVM 进程缺乏文件描述符时出现(尽管在执行 forkAndExec() 子例程时需要新的文件描述符来复制父进程的文件描述符)。对于每个进程,操作系统内核在 u_block 结构中维护文件描述符表,所有的文件描述符都在该表中建立索引。
让我们从复习文件描述符开始。 文件描述符 是由无符号整数表示的句柄,进程使用它来标识打开的文件。文件描述符与包括相关信息(如文件的打开模式、文件的位置类型、文件的初始类型等)的文件对象相关联,这些信息被称作文件的上下文。
进程获取文件描述符最常见的方法是通过本机子例程 open 或 create 获取或者通过从父进程继承。后一种方法允许子进程同样能够访问由父进程使用的文件。文件描述符对于每个进程一般是唯一的。当用 fork 子例程创建某个子进程时,该子进程会获得其父进程所有文件描述符的副本,这些文件描述符在执行 fork 时打开。在由 fcntl 、 dup 和 dup2 子例程复制或拷贝某个进程时,会发生同样的复制过程。
如果数量下降,我们应该增加文件描述符的最大数量,以防止问题重复出现。这种变化可以与减少连接在断开之前保持 TIME_WAIT 状态的时间长度结合在一起。在繁忙的服务器上, 240 秒的默认值可以延迟其他连接的尝试,因此也限制了连接的最大数量。如果数量持续上升,我们应该确定是否有一些描述符的处理时间过长(文件没有被正确关闭),以及是否创建了过多的文件(例如,驱动程序库不断为每个新的 JDBC 连接加载文件)。
加载 JAR 文件也可以减少使用的文件描述符的数量。每个 JAR 文件都使用一个描述符。即使要对每个单一类都使用同一描述符,也必须对每个单一类单独加载。
监视描述符
我们可以使用不同的技术,来监控和诊断一个进程是如何使用所有描述符的,不同的技术取决于不同的操作系统。
Unix 平台: 在诸多工具中, lsof (LiSt Open Files) Unix 管理工具显示有关打开文件和网络文件描述符的信息,包括它们的类型、大小和 i- 节点。对于特定的进程,其语法如下所示:
lsof -p示例 1 : 以下命令在 Solaris 2.7 启动 WebLogic Server 8.1SP1 后立即执行。它表明运行服务器的 Java 进程 (PID390) 分配了 84 个文件描述符,此数量远小于文件描述符缺省的硬极限。
-p 390 | wc -l 84这个数字远远低于文件描述符的默认硬极限。在异常出现之后可以执行此命令,以确保此 Java 进程达到了打开文件的最大数量。这将确认该进程缺乏文件描述符。然后我们可以运行:
-p并将输出结果重定向到某个文件以检查打开的每个文件。如果某个应当关闭的文件却出现在列表中,您可以探查此文件以前没有按照预期方式关闭的原因(参见 清单 1 )。 lsof –h 命令显示所有可能的语法和选项(参见 参考资料 中这个程序的最新版本)。
Unix 平台的输出
清单 1. lsof –h 命令显示所有可能的语法和选项。如果某个应当关闭的文件却出现在列表中,您可以探查此文件以前没有按照预期方式关闭的原因。
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME java 29733 usera cwd VDIR 176,22 4096 4300274 /home/usera/810/user_projects/mydomain java 29733 usera txt VREG 176,22 36396 6642305 /home/usera/810/jdk141_02/bin/java java 29733 usera txt VREG 176,22 1251192 10818087 /home/usera/810/user_projects/mydomain/myserver/ .wlnotdelete/extract/myserver_uddi_uddi/jarfiles/ _wl_cls_gen.jar java 29733 usera txt VREG 176,22 511935 10074851 /home/usera/810/user_projects/mydomain/myserver/ .wlnotdelete/extract/myserver_uddi_uddi/jarfiles/ WEB-INF/lib/jsse39153.jar java 29733 usera txt VREG 176,22 2305960 6000676 /home/usera/810/user_projects/mydomain/myserver/ .internal/uddi.war java 29733 usera txt VREG 176,22 1227013 1385413 /home/usera/810/weblogic81/common/eval/pointbase/lib/ pbserver44.jar java 29733 usera txt VREG 176,22 653661 69379 /home/usera/810/weblogic81/server/lib/ant/ optional.jar
文件描述符将用于每个套接字连接, lsof 还可以显示套接字的类型( TCP 或 UDP )以及监听地址和端口(位于名称列中)。
示例 2 : 在 HP 上,您还可以使用性能监视工具 Glance (参见 参考资料 )来分析在运行 WebLogic Server 时所打开文件的总数。
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME in.telnet 29705 root 2u inet 0x30002808fd8 0t76 TCP aaaaabbbb:telnet-> abcdef.bea.com:3886 ( ESTABLISHED)
如果您没有 lsof ,则还可以在 /proc//fd 中查看某个进程的所有文件描述符。每个文件描述符都驻留在此目录中。
示例 3 :这个例子显示了一个处于 CLOSE_WAIT 状态的套接字:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME java 545 weblogic 24u IPv4 0x30002a4cea8 0t0 TCP abcd:7001->xyz. com:12345 (CLOSE_WAIT)
如果套接字保持这种状态,它的相关文件描述符就会存在。如果很多套接字处于这种状态,那么进程可以在文件描述符之外运行。当 TCP 套接字的对等方(连接的另一边)发送一个 FIN 时,它就会进入这种状态。因为不能设置超时来关闭这些套接字,所以它们只能等待本地应用程序调用 close() 函数。
Windows 平台: 在 Microsoft Windows NT 或 Windows 2000 上,命令行工具 handle 报告有关引用所打开文件的句柄信息,如下所示:
C:/tmp>ps -ef | grep java usera 1656 1428 0 10:11:41 CONIN-e:46 c:/Releases/WLS8.2/ JDK141~1/bin/java -client -Xms32m -Xmx200m -XX:MaxPermSize=128m -Xverify:none -Dweblogic.Name= myserver -Dweblogic. ProductionModeEnabled= -Djava.security.policy= "c:/Releases/WLS8.2WEBLOG~1/ server/lib/weblogic.policy" weblogic.Server
– 从
Windows 平台的输出
清单 2. 您可以使用 Handle 命令来显示特定进程的输出。这个例子表明,在 Windows 上运行 WebLogic Server 8.1SP2 时使用了 65 个文件句柄。
Process Explorer 是另一个 Windows 工具,它是用来监视文件句柄的更高级的实用程序。它具有 GUI 界面并能显示有关正在运行的每个进程的更多信息。您可以使用此程序来搜索特殊句柄 ( 参见 参考资料 中给出的获得这个工具的地址 ) 。 图 1 显示了一个输出例子,它表明运行 WebLogic Server 的 Java 进程使用了 884 个句柄,但只有少数( 65 个)句柄引用打开的文件。
图 1. Process Explorer
在这里的输出中,运行 WebLogic Server 的 Java 进程使用了 884 个句柄,但只有少数( 65 个)句柄引用打开的文件。
通过使用上述任一工具,您可以确定应当关闭的文件是否仍处于打开状态。接着,您应当按照下面说明的方式,来检查如何关闭文件,以及如何释放它的文件描述符。让我们详细描述如何在不同平台上定义文件描述符。文件描述符极限以及可分配给进程的最大大小由资源限制来定义。这些值应当按照在 WebLogic Server 文档中建议的、特定于操作系统的文件描述符值来设置。
Unix 和 Linux 都有文件描述符。不过,二者的主要区别在于如何设置文件描述符的硬极限值、缺省值和配置过程。文件描述符的最大数量也叫做硬极限。软极限定义了一个进程可以打开多少个文件。软极限可以增加,但是不能超过硬极限。
在 Windows 2000 server 上,打开文件句柄的限制被设置为 16,384 。可以在任务管理器性能一览表中监控这个数字。
Solaris 平台: /usr/bin/ulimit 实用程序定义允许单个进程使用的文件描述符的数量。它的最大值在 rlim_fd_max 中定义,在缺省情况下,它设置为 1024 。只有根用户才能修改这些内核值。从 Solaris 8 开始,软极限的默认值是 64 或 256 。
Linux 平台: 管理用户可以在 etc/security/limits.conf 配置文件中设置它们的文件描述符极限,如下例所示:
soft nofile 1024 hard nofile 4096
系统级文件描述符极限还可以通过将以下三行添加到 /etc/rc.d/rc.local 启动脚本中来设置:
# Increase system-wide file descriptor limit. echo 4096 > /proc/sys/fs/file-max echo 16384 > /proc/sys/fs/ inode-max
HP-UX 平台: nfile 定义打开文件的最大数量。 maxfiles 是每个进程的软文件极限, maxfiles_lim 是每个进程的硬文件极限。 2800 对于 nfile 通常是个不错的值,即并发文件描述符的总数。
AIX 平台: 文件描述符极限在 /etc/security/limits 文件中设置,它的缺省值是 2000 。此极限可以通过 ulimit 命令或 setrlimit 子例程来更改。最大大小由 OPEN_MAX 常量来定义。
参考资料
原文出处
http://www.fawcette.com/weblogicpro/2005_01/magazine/columns/troubleshootingdiary/
作者简介 | |
Laurent Goldsztejn是BEA systems 的一位后台开发人员和关系工程师,主攻领域是故障排除和使用他们的任务关键型应用程序解决复杂的客户问题。 |