Java

Too many open files

_침묵_ 2007. 5. 9. 21:42

출처 :http://kr.bea.com/support/customer_support/SupportPattern/08_15_Too_Many_Open_Files_Pattern.html

 

Too many open files

문제 설명
다음의 두 스택 트레이스 사항은 동일한 문제를 나타내며Too many open files라는 동일한 메시지를 표시합니다.

예외 1

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)


예외 2

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 동작에 영향을 주는 경우 발생합니다.
두 경우 모두 서버 차단(blocking) 문제를 유발합니다. 아래에서 설명하는 방법으로 문제를 파악하여 해결할 수 있습니다.


문제 해결
다음 항목을 모두 수행해야 하는 것은 아닙니다. 어떤 경우에는 다음 중 일부만 수행하여도 해결할 수 있습니다.

항목 바로가기:

문제 발생 원인

이러한 예외가 발생한 것은 운영 체제(OS)에 리소스 문제가 발생했고 OS 및 JVM 프로세스의 스템이 파일 디스크립터가 부족한 상황에서 실행되고 있음을 의미합니다(파일 디스크립터란?참조).

이 문제는 서버에 연결하는 동시 접속자가 많은 경우에 주로 발생합니다. Java는 사용자의 응용 프로그램을 실행하는 데 필요한 클래스를 읽기 위해 많은 파일을 엽니다. 매우 큰 응용 프로그램은 많은 파일 디스크립터를 사용할 수 있습니다. 이로 인해 새 파일 디스크립터가 부족해질 수 있습니다. 또한 새로운 각 소켓에도 디스크립터가 필요합니다. 클라이언트와 서버는 TCP 소켓을 통해 통신합니다. 브라우저의 http 요청으로 서버에 연결될 때 TCP 소켓을 사용합니다.

우선 파일 디스크립터를 모니터링하고 이러한 진단을 통해 열려 있는 파일의 상태 및 기타 발생 가능한 문제를 파악하는 것이 중요합니다.  이 문제 해결 섹션에서 각 운영 체제별 문제 해결 방법을 적용하려면 파일 디스크립터의 개수를 늘려야 할 수도 있습니다(파일 디스크립터 및 설정참조).

페이지 맨 위

파일 디스크립터 모니터링

해결 가이드

다음은 일반적인 가이드 및 고려 사항입니다.

  • 파일 디스크립터의 총 개수가 너무 적거나 또는 일부 파일 디스크립터가 잘못 해제되고 있는지 확인합니다.
서로 다른 기간에 파일 디스크립터의 총 개수를 확인하여 파일 디스크립터 개수의 증감 여부를 파악할 수 있습니다.

이와 함께 연결이 닫히기 전TIME_WAIT상태 커넥션의 유지 시간을 줄일 수 있습니다(파일 디스크립터 해제 및 시기). 사용량이 많은 서버에서 디폴트 값인 240을 사용하면 커넥션 시도가 지연될 수 있으며, 이로 인해 커넥션의 최대 개수가 제한됩니다.

  • 이 개수가 계속 증가하는 경우 일부 디스크립터의 처리 시간이 너무 긴지(예: 파일이 제대로 닫히지 않는 경우 -파일 디스크립터 해제 및 시기) 또는 너무 많은 파일을 만들고 있는지(예: 드라이버 라이브러리에서 새로운 각 JDBC 연결에 대해 파일을 계속 로드하는 경우) 확인합니다.
  • jar 파일을 이용하면 사용하는 파일 디스크립터의 개수가 줄어듭니다.  클래스가 개별적으로 로드된 경우 각각 하나의 디스크립터가 사용되는데 반해 jar는 하나의 디스크립터만 사용됩니다.

OS에 따라 다음 가이드를 통해 한 프로세스에서 모든 디스크립터를 어떻게 사용하고 있는지 모니터링하고 진단할 수 있습니다.

페이지 맨 위

열린 파일 확인

Unix 플랫폼

Solaris, Tru64, HP-UX, Linux 및 AIX에서 제공되는lsof(LiStOpenFiles) Unix 관리 도구로 형식, 크기, i-node 등과 같은 열린 파일 및 네트워크 파일 디스크립터에 대한 정보를 표시할 수 있습니다.

특정 프로세스의 경우 구문은 다음과 같습니다.

lsof -p <pid of process>

예제 1

다음 명령은 Solaris 2.7에서 WLS 8.1SP1을 시작한 직후 실행되었습니다.  서버에서 실행 중인 Java 프로세스(pid 390)에 의해 84개의 파일 디스크립터가 할당되었음을 보여줍니다.  이 숫자는 파일 디스크립터의 디폴트 hard limit보다 훨씬 작습니다.

$ lsof -p 390 | wc -l
84


예외 발생 후 이 명령을 실행하면 이 java 프로세스에 의해 열린 파일의 최대 개수에 도달했음을 확인할 수 있습니다.  즉, 프로세스에서 파일 디스크립터가 부족합니다.

그런 다음$ lsof -p <pid>를 실행하고 출력 방향을 파일로 지정하면 열린 각 파일을 확인할 수 있습니다.  닫혀있어야 할 파일이 목록에 표시되는 경우 해당 파일이 예상대로 닫히지 않은 이유를 조사할 수 있습니다.

lsof출력 부분:


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 .h는 가능한 모든 구문 및 옵션을 표시합니다. 이 프로그램의 최신 버전은http://ftp.cerias.purdue.edu/pub/tools/unix/sysutils/lsof/에서 구할 수 있습니다.

파일 디스크립터는 각 소켓 연결에도 사용되며lsof는 소켓(TCP 또는 UDP)의 유형 및 주소와 포트를 표시할 수 있습니다.

예제 2


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)


HP에서 WebLogic Server를 실행할 때에는 성능 모니터링 도구인glance를 사용하여 열린 파일의 총 개수를 파악할 수도 있습니다. (이 도구는http://www.hp.com/에서 구할 수 있습니다.)

lsof를 사용할 수 없는 경우/proc/<pid>/fd의 프로세스에 대해 모든 파일 디스크립터를 표시할 수도 있습니다.  각 파일 디스크립터는 이 디렉토리에 있습니다.

Windows 플랫폼

핸들
WinNT 또는 Windows 2000에서 명령줄 도구handle을 사용하여다음 예와 같이 열린 파일에 대한 핸들 정보를 표시할 수 있습니다.  특정 프로세스에 대해 사용할 수도 있습니다.
이 유틸리티는http://www.sysinternals.com/ntw2k/freeware/handle.shtml에서 구할 수 있습니다.


C:\tmp>ps -ef | grep java
usera 1656 1428 0 10:11:41 CONIN$ 0: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.2\WEBLOG~1\server\lib\weblogic.policy" weblogic.Server


C:\tmp>handle -p java

Handle v2.10
Copyright (C) 1997-2003 Mark Russinovich
Sysinternals - www.sysinternals.com

------------------------------------------------------------------------------
java.exe pid: 1656 ABCDEF\usera
18: File C:\Releases\WLS8.2\user_projects\domains\mydomain
170: File C:\Releases\WLS8.2\jdk141_05\jre\lib\rt.jar
178: File C:\Releases\WLS8.2\jdk141_05\jre\lib\sunrsasign.jar
180: File C:\Releases\WLS8.2\jdk141_05\jre\lib\jsse.jar
188: File C:\Releases\WLS8.2\jdk141_05\jre\lib\jce.jar
190: File C:\Releases\WLS8.2\jdk141_05\jre\lib\charsets.jar
328: File C:\Releases\WLS8.2\jdk141_05\jre\lib\ext\dnsns.jar
330: File C:\Releases\WLS8.2\jdk141_05\jre\lib\ext\ldapsec.jar
338: File C:\Releases\WLS8.2\jdk141_05\jre\lib\ext\localedata.jar
340: File C:\Releases\WLS8.2\jdk141_05\jre\lib\ext\sunjce_provider.jar
348: File C:\Releases\WLS8.2\jdk141_05\lib\tools.jar
350: File C:\Releases\WLS8.2\weblogic81\server\lib\weblogic.jar
358: File C:\Releases\WLS8.2\weblogic81\server\lib\jconn2.jar
360: File C:\Releases\WLS8.2\weblogic81\server\lib\ojdbc14.jar
368: File C:\Releases\WLS8.2\weblogic81\server\lib\xmlx.jar
370: File C:\Releases\WLS8.2\weblogic81\server\lib\webservices.jar
378: File C:\Releases\WLS8.2\weblogic81\server\lib\wlcipher.jar
3e0: File C:\Releases\WLS8.2\weblogic81\server\lib\ant\ant.jar
3e8: File C:\Releases\WLS8.2\weblogic81\server\lib\EccpressoJcae.jar
3f0: File C:\Releases\WLS8.2\weblogic81\server\lib\EccpressoCore.jar
3f8: File C:\Releases\WLS8.2\weblogic81\server\lib\EccpressoAsn1.jar
400: File C:\Releases\WLS8.2\weblogic81\server\lib\jConnect.jar
408: File C:\Releases\WLS8.2\weblogic81\server\lib\ant\optional.jar
410: File C:\Releases\WLS8.2\weblogic81\server\lib\ant\jakarta-oro-2.0.7.jar
갋.
C:\tmp>handle -p java | wc -l
65


WLS 8.1SP2 실행 시 Windows에서 65개의 파일 핸들을 사용했음을 알 수 있습니다.

Process Explorer
Windows에서 사용할 수 있는 또 다른 도구인Process Explorer는 파일 핸들을 모니터할 수 있는 고급 유틸리티입니다.  이 도구는 GUI 인터페이스로 구성되어 있으며 실행 중인 각 프로세스에 대해 자세한 정보를 표시합니다.  이 프로그램을 사용하여 특정 핸들을 검색할 수 있습니다.  이 도구는http://www.sysinternals.com/ntw2k/freeware/procexp.shtml에서 구할 수 있습니다.  다음은 예제 출력 화면입니다.


사용자 삽입 이미지


WLS 실행 시 java 프로세스에서 884개의 핸들을 사용했고 이 중 일부(65개) 핸들만 열린 파일을 참조하고 있음을 알 수 있습니다.

이러한 도구를 사용하면 닫혀야 할 파일이 계속 열려 있는지 여부를 파악할 수 있습니다.  이제 아래에서 파일을 닫는 방법과 그것의 파일 디스크립터를 해제하는 방법을 확인해야 합니다.

페이지 맨 위

파일 디스크립터 해제 및 시기
파일 디스크립터는 파일을 닫거나 프로세스가 종료되면 해제됩니다. close()시스템 호출이 오류 코드를 반환하지 않으면 파일 디스크립터를 할당하는 이후의open()호출에서 연관된 파일 디스크립터를 사용할 수 있습니다.  열린 파일 디스크립터과 연관된 모든 파일 디스크립터를 닫으면 열린 파일 디스크립터가 해제됩니다.

파일 디스크립터와 같은 비 Java 리소스를 해제하기 위해 가비지 컬렉션과 개체 finalization에 의존해서는 안됩니다.  따라서close()를 사용해야 하며 오류 발생 시 적절하게 핸들링 해야 합니다.

모든 데이터 전송을 완료하기 위해 소켓을 닫더라도TIME_WAIT으로 변환되었다가 최종 승인(ACK)에 의해 데이터 전송이 종료됩니다. 이 경우 파일 디스크립터의 해제를 지연시킵니다. 이TIME_WAIT시간은 Unix 시스템에서tcp_time_wait _interval이라는 커널 매개변수로 정의됩니다. Windows NT, Windows 2000 및 Windows XP의 경우 이 시간은 레지스트리의HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters라는 시스템 키의TcpTimedWaitDelay로 정의됩니다.

Unix 커널 매개변수에 대한 자세한 설명을 보려면 다음 페이지를 참조하십시오. http://www.unixadm.net/networking/tune.html

페이지 맨 위

알려진 WebLogic Server 문제

이러한 파일 디스크립터 부족 문제는 대개 개수를 늘리면 해결이 되지만, WebLogic 서버도 스스로 너무 많은 파일을 사용하지 않고 열린 파일을 정상적으로 닫아야 합니다.

BEA 고객 지원부로 보고된 모든 문제는 파일 디스크립터의 부족이나 디스크립터 테이블의 오버플로와 관련이 있습니다.  이 문제는 OS에서 java 프로세스에 새 파일 디스크립터를 할당할 수 없음을 통보할 때 항상 발생합니다.  이런 경우 fd의 개수를 늘려야 합니다.

페이지 맨 위

파일 디스크립터 및 설정

파일 디스크립터란?

파일 디스크립터는 프로세스가 열린 파일을 식별하기 위해 사용하는 부호 없는 정수(unsigned integer)로 표시된 핸들입니다.  파일 디스크립터는 파일이 열렸을 때의 모드, 위치 유형, 초기 유형 등과 같은 정보가 포함된 파일 개체와 연관됩니다.  이 정보를 파일의컨텍스트라고 합니다.

파일 디스크립터 생성 방법
프로세스에서 파일 디스크립터를 획득하는 가장 일반적인 방법은 시스템 API인open또는create를 사용하거나 부모 프로세스에서 상속 받는 것입니다.  상속 방법을 사용하면 자식 프로세스가 부모 프로세스에서 사용하는 파일에 동일하게 액세스할 수 있습니다.  파일 디스크립터는 대개 각 프로세스마다 고유합니다. fork함수로 자식 프로세스를 생성하면 해당 자식 프로세스는fork시에 열린 모든 부모 프로세스의 파일 디스크립터 사본을 갖게 됩니다. fcntl, dupdup2함수를 이용하여 프로세스를 복제할 때와 동일한 복사 과정을 수행할 수 있습니다.

두 번째 예외는 JVM 프로세스에서forkAndExec()함수를 실행하는 동안 부모 프로세스의 파일 디스크립터를 복제하기 위해 새 파일 디스크립터가 필요한데 JVM 프로세스에서 파일 디스크립터가 부족한 경우를 나타냅니다.  OS 커널은 각 프로세스별로 모든 파일 디스크립터가 인덱싱된 파일 디스크립터 테이블을u_block구조로 관리합니다.

각 플랫폼에서 파일 디스크립터의 개수 정의 방법
프로세스에 할당할 수 있는 최대 크기 및 파일 디스크립터의 제한은 리소스 제한에 의해 정의됩니다.  이 값은 WebLogic Server 설명서에 제시된 OS 특정 파일 디스크립터 값에 따라 설정되어야 합니다.

WLS 8.1:하드웨어, 운영 체제 및 네트워크 성능 조정
WLS 7.0:하드웨어, 운영 체제 및 네트워크 성능 조정
WLS 6.1:하드웨어, 운영 체제 및 네트워크 성능 조정

Unix 및 Linux에 모두 파일 디스크립터가 있습니다.  주요한 차이점은 hard limit의 설정, 디폴트값 및 파일 디스크립터의 구성 절차에 있습니다.

Solaris
/usr/bin/ulimit유틸리티를 사용하여 단일 프로세스에 할당하는 파일 디스크립터의 개수를 정의합니다.  최대값은rlim_fd_max로 정의되며 기본적으로 65,536으로 설정됩니다.  루트 사용자만이 이 커널 값을 수정할 수 있습니다.

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

Windows
파일 디스크립터는 Windows OS에서는 파일 핸들이라고 합니다.  Windows 2000 서버의 경우 열린 파일 핸들 제한은 16,384로 설정되어 있습니다.  이 값은 작업 관리자 성능 요약에서 확인할 수 있습니다.

HP-UX
nfile을 사용하여 열린 파일의 최대 개수를 정의할 수 있습니다.  이 값은 대개 다음 공식으로 결정됩니다.((NPROC*2)+1000)여기서NPROC는 대개((MAXUSERS*5)+64)입니다. MAXUSERS가 400인 경우 계산 결과는 5128입니다.  대개 이 값을 더 높게 설정합니다. maxfiles는 프로세스별 소프트 파일 제한이고maxfiles_lim은 프로세스별 하드 파일 제한입니다.

AIX
파일 디스크립터 제한은/etc/security/limits파일에 설정되어 있으며 기본값은 2000입니다.  이 제한은ulimit명령 또는 setrlimit 함수로 변경할 수 있습니다.  최대 크기는OPEN_MAX상수로 정의합니다.