BlueByte
EMFILEFixed

Linux: Too many open files (EMFILE)

작성 Haneul Seo2026년 8월 22일 업데이트6 min

안녕하세요, BlueByte입니다. 부하가 걸릴 때 서비스가 EMFILE을 던지기 시작하면, 사실 한 오류 안에 질문이 둘 숨어 있습니다 — 한도가 낮은 건가, 아니면 뭔가 새는 건가. 오늘은 이 둘부터 가른 뒤 — 한도 올림은 하나만 고치고 다른 하나는 미루기만 하니까 — 프로세스가 실제로 도는 곳에 해결을 적용하는 순서로 가보겠습니다.

EMFILE이 알려주는 것

부하가 걸리면 서버나 스크립트가 실패하기 시작합니다:

Error: EMFILE: too many open files

프로세스가 허용된 파일 디스크립터 최대치를 넘겨 파일·소켓·연결을 열려고 했습니다. 소켓과 파이프도 모두 세므로, 바쁜 네트워크 서비스는 실제 파일이 바닥나기 한참 전에 걸립니다. 실패는 프로세스 단위이고, 해결은 그 프로세스가 실제로 도는 곳에 적용해야 합니다 — 사람들이 가장 자주 틀리는 지점입니다.

한도가 낮은가, 새는가 — 두 진짜 원인

각 프로세스에는 열린 디스크립터의 소프트 한도가 있습니다(기본 1024인 경우 많음). 도달하면 모든 새 open()·socket()·accept()가 EMFILE로 실패합니다. 근본 상황은 둘이고 대응이 다릅니다:

  • 한도가 정말 낮음 — 수천 동시 연결을 다루는 프록시·DB는 1024보다 훨씬 필요.
  • 프로세스가 디스크립터를 누수 — 닫지 않는 연결·파일을 계속 열어 수가 천장까지 늘기만 함.

이 둘을 가르는 게 전부입니다.

디스크립터 수를 지켜보며 둘을 가르기

어느 쪽인지 추측할 필요 없습니다 — 지켜보면 됩니다. 현재 한도와 프로세스가 지금 쥔 개수를 확인:

ulimit -n
ls /proc/$(pgrep -f myservice)/fd | wc -l

그 둘째 수를 몇 분간 일정한 트래픽에서 지켜보세요. 오르기만 하고 안 떨어지면 누수, 실제 부하에서 한도 근처에 머물면 한도가 낮은 것입니다. 셸이 아니라 실행 중 프로세스의 실효 한도를 보려면:

grep "open files" /proc/$(pgrep -f myservice)/limits

프로세스가 도는 곳에서 한도를 올리기

  1. 서비스면 도는 곳에서 한도를 올립니다. systemd 유닛은 셸 ulimit을 무시하므로 유닛에 설정:
# /etc/systemd/system/myservice.service
[Service]
LimitNOFILE=65536
sudo systemctl daemon-reload
sudo systemctl restart myservice
  1. 로그인 세션이면 /etc/security/limits.conf에 추가 후 새 세션을 엽니다:
*  soft  nofile  65536
*  hard  nofile  65536
  1. 누수를 찾았으면 열고 안 닫는 코드를 고치세요 — 한도 올림은 시간만 벌 뿐입니다.

실제 사례: 낮은 한도가 아니라 누수

Node 서비스가 트래픽 약 1시간 뒤 EMFILE을 던지기 시작합니다. ls /proc/<pid>/fd | wc -l이 1024에 고정돼 있고, 이전 실행에서 10분간 지켜봤을 때 꾸준히 오르기만 하고 안 떨어졌습니다. 낮은 한도가 아니라 누수 지문입니다 — 앱이 요청마다 HTTP 클라이언트를 열고 안 닫습니다. 클라이언트가 풀링된 연결을 재사용하도록 고치니 같은 부하에서 디스크립터 수가 약 200에 머뭅니다. 여유로 LimitNOFILE을 65536으로 올리긴 하지만, 실패를 실제로 멈춘 건 누수 수정입니다.

한도가 셸이 아니라 프로세스에 적용됐는지 확인

사람들이 건너뛰는 단계이니 직접 확인하세요:

cat /proc/$(pgrep -f myservice)/limits | grep "open files"

"Max open files" 열에 설정 값이 보여야 합니다. 그다음 실패하던 부하를 돌려 더는 실패하지 않고 디스크립터 수가 안정적인지 확인하세요.

다시 겪지 않으려면

네트워크 서비스는 유닛 파일에 LimitNOFILE을 의도적으로 두고 실제 동시성 + 여유에 맞추며, 디스크립터 수에 메트릭·알림을 걸어 느린 누수가 서비스를 죽이기 훨씬 전에 보이게 하세요.

ENFILE과의 구분

EMFILE은 프로세스 단위, ENFILE("file table overflow")은 시스템 전체 소진 — 훨씬 드물고 커널 전역 fs.file-max sysctl로 고칩니다. 셸에서 ulimit 작업 중 나는 "Too many open files"는 같은 한도지만 대화식으로 도달한 것입니다. EMFILE을 만나면 무언가 올리기 전에 수를 지켜보세요 — 그래프가 어느 문제인지 알려줍니다.

관련 질문

ulimit -n 65536을 했는데도 서비스가 여전히 실패합니다.

systemd 서비스는 셸의 ulimit을 상속하지 않습니다. 유닛 파일에 LimitNOFILE을 설정하고 systemd를 reload하세요.

어떤 값으로 설정해야 하나요?

실제 동시성에 여유를 더해 맞추세요. 65536은 바쁜 네트워크 서비스에 흔하고 안전한 상한입니다. 이유 없이 unlimited로 두지 마세요.

누수인지 그냥 낮은 한도인지 어떻게 아나요?

ls /proc/<pid>/fd | wc -l을 시간에 따라 보세요. 일정한 트래픽에서 정상 프로세스는 평평해지고, 누수는 안 떨어지고 오릅니다.

네트워크 소켓도 세나요?

네. 소켓·파이프·epoll 인스턴스가 모두 파일 디스크립터를 씁니다. 그래서 네트워크 서비스는 그만한 실제 파일을 열기 훨씬 전에 EMFILE에 걸립니다.

한 프로세스가 아니라 시스템 전체가 파일이 바닥났습니다.

그건 EMFILE이 아니라 ENFILE입니다. sysctl fs.file-max로 커널 전역 한도를 올리되, 먼저 폭주 프로세스 하나가 다 쓰는 건 아닌지 확인하세요.

참고 자료

Haneul Seo

Infrastructure engineer · 10+ years running Linux fleets

같은 카테고리 다른 글

Start request repeated too quicklyFixed

systemd: Start request repeated too quickly

systemd는 StartLimitIntervalSec(기본 10초) 안에 StartLimitBurst(기본 5회)보다 많이 시작된 유닛의 시작을 거부하며, Restart=도 이 제한에 포함됩니다. 기본 RestartSec 100ms로는 크래시하는 서비스가 1초도 안 되어 다섯 번을 소진합니다. 저널에서 진짜 크래시를 찾아 고치고, reset-failed를 실행한 뒤, RestartSec로 재시작에 여유를 주세요.

systemd
Too many authentication failuresFixed

SSH: Received disconnect ... Too many authentication failures

agent가 서버가 허용하는 것보다 많은 키를 내밀고 있습니다. sshd가 들여다보는 공개키 하나하나가 MaxAuthTries 시도를 한 번씩 소모하고 — 기본 6회, 하드닝된 호스트에서는 3회인 경우가 많습니다 — 정작 맞는 키는 차례가 오기 전에 연결이 끊깁니다. IdentitiesOnly=yes와 명시적 IdentityFile로 키 하나를 고정하면 시도 횟수가 1로 떨어집니다.

OpenSSH
1722Fixed

Active Directory: 복제가 error 1722(The RPC server is unavailable)로 실패

RPC는 하위 계층이 연결에 실패했을 때 1722(0x6ba, RPC_S_SERVER_UNAVAILABLE)를 보고합니다. 따라서 진짜 원인은 RPC 자신이 아니라 DNS, 차단된 포트, 두 도메인 컨트롤러 중 한쪽의 호스트 설정입니다. repadmin이 어느 파트너가 실패하는지 알려주고, dcdiag /test:dns가 이름 해석을 배제하며, Test-NetConnection과 동적 포트 범위가 방화벽 문제를 가릅니다. 가장 흔한 실수는 TCP 135만 허용하고 49152–65535는 막아 둔 규칙입니다.

Windows Server Active Directory
Windows Server RDSFixed

Windows Server RDS: The remote session was disconnected because there are no Remote Desktop License Servers available to provide a license

120일 RD Licensing 유예 기간이 끝났는데 세션 호스트가 쓸 수 있는 라이선스 서버가 없어 세션을 거부하는 상황입니다. GetGracePeriodDays 의 DaysLeft 가 0 이고 SpecifiedLSList 가 비어 있으면 몇 초 만에 확인됩니다. 해결은 활성화된 라이선스 서버와, 호스트 버전을 감당할 만큼 새 CAL 입니다. 2019 CAL 은 2022 세션 호스트를 서비스하지 못합니다. 여기에 배포 또는 Licensing 정책 설정과 두 서버 사이의 RPC 포트 개방이 따라옵니다.

Windows Server RDS
0x80070035 / Event ID 31017Workaround

Windows 11: NAS 공유 폴더를 열 때 "조직의 보안 정책이 인증되지 않은 게스트 액세스를 차단" (0x80070035)

Windows 10 Enterprise/Education/Pro for Workstations, Windows 11 Pro, Windows Server 2019 이후의 SMB 클라이언트는 기본적으로 게스트 로그온을 거부하고, Windows 11 24H2 Enterprise/Pro/Education 은 게스트 세션이 할 수 없는 SMB 서명까지 요구합니다. 그래서 게스트 접근만 제공하는 NAS 공유는 'block unauthenticated guest access' 대화상자, Error code 0x80070035, 또는 System error 3227320323 으로 실패하고, SmbClient/Security 로그에 Event ID 31017 'Rejected an insecure guest logon' 이 남습니다. Microsoft 가 권하는 해결은 NAS 에 실제 계정을 만들고 펌웨어에서 서명을 지원하게 하는 것입니다. Set-SmbClientConfiguration -EnableInsecureGuestLogons $true(24H2 는 -RequireSecuritySignature $false 까지)는 비상구이며, 그 클라이언트의 서명과 암호화를 포기하는 대가가 있습니다.

Windows (SMB client)
E: Could not get lock /var/lib/dpkg/lock-frontendFixed

Ubuntu/Debian: E: Could not get lock /var/lib/dpkg/lock-frontend — 누가 쥐고 있고 어떻게 기다리는지

다른 패키지 관리자, 대개 부팅 때 persistent systemd 타이머로 발화한 Ubuntu 의 unattended-upgrades 가 여러분의 apt-get 이 도는 동안 dpkg 프런트엔드 락을 쥐고 있는 것입니다. Ubuntu 는 apt 바이너리에만 binary::apt::DPkg::Lock::Timeout "120" 을 실어 두어서 apt-get 은 즉시 포기하고 apt 는 기다립니다. 메시지의 PID 를 읽고, 실행이 끝나게 두거나 apt-get 에 -o DPkg::Lock::Timeout=<초> 를 주고, dpkg --configure -a 는 실제로 중단된 실행 뒤에만 쓰고, 락 파일은 절대 지우지 마세요. 보유자가 종료하면 커널이 푸는 fcntl 락입니다.

APT (Ubuntu/Debian)