리눅스 장애 대응 · 파일디스크립터와 한도 · 실습
파일디스크립터와 한도 진단
목표
파일디스크립터의 한도가 몇 겹인지 확인하고, fd 누수를 추적하는 도구를 손으로 만듭니다.
왜 중요한가
Too many open files 를 보면 거의 모두가 ulimit -n 65536 을 실행합니다. 그런데 그 값은 내 셸의 값이고 이미 떠 있는 서비스에는 아무 영향이 없습니다. 확인해야 할 곳은 /proc/<PID>/limits 이고, 실제 사용량은 ls /proc/<PID>/fd | wc -l 입니다(lsof -p 는 cwd·실행파일·mmap 라이브러리까지 세는데 이것들은 한도에 포함되지 않습니다). 그리고 한도를 올리는 것이 답인 경우는 드뭅니다 - 대개 누수이고, 그때 한도 상향은 장애를 몇 시간 뒤로 미루는 일일 뿐입니다. 누수인지 부하인지는 fd 수의 증가 패턴으로 구분합니다.
단계
/root/fd 디렉터리에서 작업합니다.
1. /proc/1/limits 에서 열린 파일 한도를 읽어 /root/fd/limits.txt 에 다음 두 줄로 적으세요.
soft=<값>hard=<값>count=<개수>distinct=<개수>
2. /etc/hostname 을 50번 이상 동시에 열고 있는 프로세스를 백그라운드로 띄우고 PID 를 /root/fd/holder_pid.txt 에 적으세요. 이후 단계 내내 살아 있어야 합니다.
3. 그 프로세스의 fd 중 /etc/hostname 을 가리키는 것의 개수와, 그것들이 가리키는 서로 다른 대상의 개수를 /root/fd/distinct.txt 에 다음 두 줄로 적으세요.
4. 한도를 낮춘 환경에서 파일을 계속 열어 Too many open files 오류를 재현하고, 그 메시지를 /root/fd/emfile.txt 에 저장하세요.
5. 시스템 전체 fd 상한을 /root/fd/file_max.txt 에 숫자만 적으세요.
6. python3 -m http.server 8099 --bind 127.0.0.1 을 백그라운드로 띄우고 PID 를 /root/fd/http_pid.txt 에 적으세요.
7. /root/fd/fdtop.sh <N> 을 만드세요. 열린 fd 개수 상위 N개 프로세스를 <fd개수> <PID> 형식으로 내림차순 출력합니다. 정확히 N줄이어야 합니다.
8. /etc/hostname 의 inode 번호를 /root/fd/inode.txt 에 적으세요.
참고
python3 -c "fs=[open('/etc/hostname') for _ in range(60)]; import time; time.sleep(9999)" &로 fd 를 붙잡을 수 있습니다. 리스트에 담아 두지 않으면 즉시 닫힙니다.bash -c 'ulimit -n 32; python3 -c "..."' 2> /root/fd/emfile.txt처럼 서브셸에서 한도를 낮출 수 있습니다./proc/sys/fs/file-nr는할당된 수 / 미사용 할당분 / 최대값세 숫자입니다.- 흔한 실수 1: 7번에서
/proc/self나 이미 종료된 프로세스 때문에 오류가 납니다. 실패하는 항목은 건너뛰세요. - 흔한 실수 2: 4번에서 오류를 표준출력으로 받으려 하면 아무것도 안 담깁니다. 오류는 표준에러로 나옵니다.
단계 8개
- 진짜 한도 읽기
- fd 50개 붙잡기
- fd 개수와 대상 개수 세기
- EMFILE 재현하기
- 시스템 전체 상한 읽기
- 소켓도 fd 다
- fd 상위 프로세스 뽑기
- fd 에서 inode 까지 추적