이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.

  • File Descriptor와 열린 파일에서 붙잡아야 할 핵심 판단 기준은 무엇인가?
  • 열린 자원 수는 process 한계다라는 기준은 어떤 JVM/OS 신호로 확인되는가?
  • Java/Spring 코드에서 File Descriptor와 열린 파일 판단 기준은 어떤 장애 신호로 드러나는가?

개요

이 문서의 주제는 File Descriptor와 열린 파일이다. File descriptor의 의미, limit, socket과 파일 공유, 고갈 증상을 정리한다.

먼저 붙잡을 기준은 다음 문장이다. 열린 자원 수는 process 한계다. 이 문서는 이 기준을 Java/Spring 실행 흐름, JVM/OS 관찰 지표, 장애 판단 순서로 연결한다.

핵심 모델

  • 판단 기준: FD는 process가 OS 자원을 붙잡는 손잡이다.
  • File descriptor는 파일, socket, pipe, eventfd를 모두 가리킬 수 있다.
  • FD limit에 가까워지면 파일 오류와 네트워크 오류가 같이 나타날 수 있다.
  • Java 객체가 사라지는 것과 FD가 즉시 닫히는 것은 같은 말이 아니다.
  • FD 증가는 수량뿐 아니라 어떤 종류가 증가하는지 분류해야 한다.

문서별 핵심 구분

  • FD는 파일과 socket을 모두 포함하는 process 자원이다.
  • FD 고갈은 새 파일 열기 실패와 새 연결 실패로 함께 나타날 수 있다.
  • limit과 현재 열린 수를 항상 같이 본다.

원리

File descriptor는 process가 kernel object를 참조하는 번호다. 일반 파일뿐 아니라 TCP socket, pipe, eventfd, epoll instance도 FD를 사용한다.

FD 한계는 process 단위로 적용된다. Java 코드에서 파일 stream을 닫지 않아도, HTTP client connection이 회수되지 않아도, accept된 socket이 쌓여도 결국 같은 open files limit을 압박한다.

FD 고갈은 Too many open files로만 나타나지 않는다. 새 로그 파일을 못 열거나, 새 DB/socket 연결이 실패하거나, accept가 실패해 네트워크 장애처럼 보일 수 있다.

File Descriptor와 열린 파일 관점에서 중요한 점은 “현재 열린 수”와 “limit”을 항상 같이 보는 것이다. lsof 목록만 많다고 장애는 아니며, 어떤 종류의 FD가 늘고 있는지와 limit까지의 여유가 판단 기준이다.

Java/Spring 연결

  • 파일 upload/download, log file, HTTP client socket, DB connection은 모두 FD를 사용한다.
  • try-with-resources는 stream close와 FD 반환을 명시적으로 보장한다.
  • Too many open files는 파일 코드가 아니라 outbound socket leak에서도 발생한다.
  • systemd LimitNOFILE, container ulimit, /proc/<pid>/limits를 실제 process 기준으로 확인한다.
  • FD 수와 Tomcat/Hikari/HTTP client pool 상한을 함께 계산해야 한다.

코드와 설정 예시

try (InputStream in = Files.newInputStream(path)) {
    return in.readAllBytes();
}

예시는 stream을 열면 process의 FD를 하나 사용하고, try-with-resources가 끝날 때 반환된다는 점을 보기 위한 것이다. readAllBytes()는 파일 크기만큼 heap도 사용하므로 FD와 memory를 함께 고려해야 한다.

관찰 명령

ulimit -n
ls /proc/<pid>/fd | wc -l
lsof -p <pid> | head
cat /proc/<pid>/limits

File Descriptor와 열린 파일 관찰 명령은 결론이 아니라 가설 확인 도구다. 운영 중에는 반복 간격, 대상 PID, 수집 시각을 함께 남기고 출력이 큰 명령은 범위를 제한한다.

지표 해석

신호먼저 의심할 것다음 확인
open files가 limit에 근접FD leak 또는 connection 폭주lsof, /proc/<pid>/fd
iowait 증가와 latency 상승disk 병목, flush 지연iostat, vmstat
로그량 급증 후 API 지연동기 로그 또는 log collector 지연log rate, appender queue
tmp 사용량 증가upload/export/temp cleanup 실패tmp directory, lsof deleted

File Descriptor와 열린 파일에서는 핵심 신호와 보조 지표를 같은 시간축에서 맞춘다. 먼저 변한 신호와 뒤따라 포화된 신호를 분리해야 원인과 결과를 구분할 수 있다.

장애 상황에서 보는 순서

  1. /proc/<pid>/limits와 현재 /proc/<pid>/fd 개수를 비교한다.
  2. lsof로 file, socket, pipe, deleted file을 분류한다.
  3. 증가한 FD 종류를 코드 경로와 연결한다.
  4. close 누락, connection pool leak, log rotation 문제를 확인한다.
  5. limit 상향 전 실제 누수인지 정상 peak인지 구분한다.

이 순서는 FD 고갈을 파일 문제 하나로 단정하지 않기 위한 루틴이다.

실전 팁

  • ls /proc/<pid>/fd | wc -l/proc/<pid>/limits를 함께 본다.
  • lsof 결과는 file, socket, pipe, deleted file로 나누어 본다.
  • FD 증가가 트래픽 증가와 비례하는지, 요청이 끝난 뒤에도 줄지 않는지 비교한다.
  • HTTP client, DB pool, file stream은 close/return/release 경로를 코드에서 확인한다.
  • limit 증가는 임시 완화일 수 있지만 leak을 해결하지는 못한다.

주니어 팁

  • File Descriptor와 열린 파일 주제는 용어 정의보다 장애 때 어떤 증거로 확인할지까지 연결해 익힌다.
  • 정상 상태에서 이 문서의 관찰 명령을 실행해 File Descriptor와 열린 파일 기준선을 남긴다.
  • 장애 시에는 File Descriptor와 열린 파일 신호가 평소 기준선에서 벗어난 시각과 방향을 먼저 본다.

시니어 팁

  • File Descriptor와 열린 파일 주제의 영향이 pool, queue, retry, timeout으로 번지는 경로를 설계 리뷰에 포함한다.
  • File Descriptor와 열린 파일 runbook에는 실행 명령, 정상 범위, 해석 기준, 금지할 대응을 같이 둔다.
  • File Descriptor와 열린 파일 판단이 container, LB, 다중 인스턴스 환경에서도 같은 의미인지 확인한다.

Guru급 팁

  • File Descriptor와 열린 파일 주제는 단일 snapshot보다 변화 방향이 중요하다. 같은 명령을 간격을 두고 실행해 상태가 증가, 유지, 회복 중 어디인지 본다.
  • 고급 도구는 File Descriptor와 열린 파일 가설을 좁힐 때만 사용하고 기본 지표와 모순되는지 먼저 확인한다.
  • File Descriptor와 열린 파일 조치 후에는 CPU, memory, socket, disk, pool 중 다음 포화 지점이 어디로 이동했는지 확인한다.

위험 신호!

  • Too many open files를 파일 업로드 문제로만 본다.
  • socket도 FD라는 사실을 놓쳐 네트워크 장애와 FD 고갈을 분리하지 못한다.
  • 현재 FD 수만 보고 open files limit을 확인하지 않는다.
  • lsof에서 deleted file이 많은데 disk 사용량만 본다.
  • 재시작으로 FD가 줄었다는 이유로 leak 경로를 찾지 않는다.

확인 질문

확인 질문

  • File Descriptor와 열린 파일 주제를 장애 중 확인할 때 Application 로그만으로 부족한 이유는 무엇인가?
    • 로그는 코드 경로를 보여 주지만 File Descriptor와 열린 파일의 JVM/OS 자원 상태, 대기 위치, 포화 방향은 별도 지표로 확인해야 하기 때문이다.
  • File Descriptor와 열린 파일 관련 설정이나 pool 크기를 바꾸기 전에 확인할 것은 무엇인가?
    • 먼저 변한 신호, 하위 자원 capacity, 변경이 완화인지 증폭인지 판단할 기준을 File Descriptor와 열린 파일 지표로 확인해야 한다.
  • File Descriptor와 열린 파일 재발을 막기 위해 장애 기록에 무엇을 남겨야 하는가?
    • 발생 시간, 영향 범위, 사용한 명령, File Descriptor와 열린 파일 핵심 지표, 원인 판단, 완화 조치, 근본 수정, 남은 리스크를 남긴다.

참고 문서