본문 바로가기

computer science

File Descriptor란?

"하나의 서버 컴퓨터가 요청을 몇 개나 맺을 수 있을까요?"

답변을 하지 못했다. 아마 성능이 매우 좋은 cpu, ram, disk를 쓰면 요청을 많이 맺을 수 있지 않을까 생각했다. 물론 하드웨어적인 요소들이 서버가 맺을 수 있는 요청의 수에 영향을 주겠지만, Unix-like OS 관점에서 볼 때 모든 요청이 파일로 관리되기 때문에 '파일을 얼마나 생성해낼 수 있는가?'가 하나의 지표로 활용될 수 있을 것이다.

여기서 요청이라 하면 sockets, network I/O, disk I/O 등 다양한 인터페이스를 가리킨다. 소켓을 열거나 네트워크 연결을 수립할 때, 파일을 열거나 디스크 장치에 접근할 때도 file descriptor가 생성된다.

현재 사용하고 있는 노트북이 macOS이므로 file descriptor를 다음과 같이 확인해볼 수 있다. 

lsof

 

매우 많은 목록이 보인다. 리스트가 몇 개나 되는지 확인하기 위해 다음과 같은 command를 사용해본다.

lsof | wc -l

 

라인 수를 카운트하여 결과로 출력해준다. 현재 내 노트북에서는 8806개의 file descriptor가 있는 것으로 보인다. root 권한이 필요한 목록까지 보기 위해 다음과 같이 확인해본다.

sudo lsof | wc -l

 

12,405개가 출력된다. 그런데 엄밀히 따지면 해당 command 명령이 시스템이 갖고 있는 정확한 file descriptor 수를 나타내는 것은 아니라고 한다.

lsof 명령은 내 시스템을 포함해 현재 실행중인 프로세스나 application, 네트워크를 통해 연결된 다른 기기의 파일이나 소켓도 함께 보여준다. Google Chrome을 실행시키고 있는 지금 chrome application을 통해 연결된 파일들에 대한 file descriptor 목록도 함께 볼 수 있다.

좀 더 정확하게 8080 포트의 tomcat 서버를 실행시키고 해당 프로세스의 file descriptor를 확인하기 위해서 다음의 명령어를 사용했다. 8080 포트의 PID를 확인하고, 해당 PID를 사용하는 프로세스의 file descriptor를 얻는다. 100개의 file descriptor를 사용하고 있고 다음과 같이 나온다.

lsof -i :8080
lsof -p {PID}
COMMAND  PID       USER   FD     TYPE             DEVICE  SIZE/OFF                NODE NAME
java    7551        sun  cwd      DIR               1,18       416             8682488 /Users/sun/labs/java/playground
java    7551        sun  txt      REG               1,18     69888             8555606 /opt/homebrew/Cellar/openjdk@17/17.0.6/libexec/openjdk.jdk/Contents/Home/bin/java
.
.
.

playground 앱을 실행시켰고, openjdk17을 사용했다. 

- command: 이 프로세스와 관련된 커맨드 이름

- pid: 프로세스의 ID

- user: 해당 프로세스를 소유한 유저의 이름

- fd: file descriptor number

- type: 파일 또는 장치의 타입

- device: device number and partition number

- size/off: file descriptor의 size와 offset

- node: inode number

- name: 이름

 

굉장히 여러 종류의 타입이 나온다. 추려보면 다음과 같다.

- DIR: directory

- REG: regular file

- PIPE: inter-process communication mechanism

- IPv6: IPv6 socket

- unix: unix domain socket

- CHR: character device

- KQUEUE: kernel event queue

- systm: system file

 

file descriptor가 관리되고 있는 경로는 linux 에서 '/proc/{PID}/fd/' 경로에서 확인할 수 있고, macOS에서는 '/dev/fd/' 에서 symbolic link를 확인할 수 있다.

 

왜 file descriptor에 대해서 알아보았냐 하면, 하나의 시스템에서 각 프로세스가 열 수 있는 file descriptor의 수가 제한이 있기 때문이다. 즉, 프로세스가 열 수 있는 파일 디스크립터의 최대 갯수이다. 이 설정을 'RLIMIT_NOFILE'이라 부른다. 이 설정을 다음과 같이 확인할 수 있다. 256이 출력된다. 설정을 바꾸지 않는다면 하나의 프로세스가 최대 256개의 파일 디스크립터를 열 수 있다.

ulimit -n

 

linux에서 'RLIMIT_NOFILE' 설정은 다음과 같이 변경할 수 있다. 대신 다음과 같은 커맨드로 변경한 값은 현재 shell 세션에서만 유지된다. 영구적인 변경은 '/etc/security/limits.conf' 파일 설정을 통해 할 수 있다.

ulimit -n <number>

 

맥북에서는 설정이 조금 다른데, '/Library/LaunchDaemons' 경로의 limit.maxfiles.plist 파일을 사용하거나 'launchctl' 명령어를 사용해 리소스 제한을 설정할 수 있다.

launchctl limit maxfiles <number> <number>

맥북에서 전체 시스템의 open file descriptor 수를 확인하고 싶다면 다음과 같이 하면 된다. 필자의 맥북에서는 122,880개가 설정되어 있다.

sysctl kern.maxfiles

 

file descriptor 수가 실행 프로세스의 요청 처리에 영향을 미칠 수 있음을 알아보았다. 이에 대한 설정을 확인할 수 있는 ulimit(user limit) 커맨드도 알아보았다. 다음 글에서는 이를 이용해 운영 환경에서 어떤 영향이 있을지 알아보도록 한다.

다음 글 : File Descriptor 제한 테스트(feat. ulimit, JMeter, VisualVM)

 

 

 

* ulimit

ulimit은 file descriptor 수만 확인하는 커맨드는 아니다. 여러 자원들에 대한 설정도 함께 확인할 수 있는데, macOS 기준으로 다음과 같은 설정도 함께 확인할 수 있다. 'ulimit -a' 커맨드는 soft 설정을, 'ulimit -aH' 커맨드는 hard 설정을 볼 수 있다. soft 설정은 프로세스가 실행될 때 기본으로 적용되는 값이고, hard 설정은 soft 설정을 할 수 있는 최대값이다.