← 아티클 목록

ulimit vs systemd LimitNOFILE 차이 — Too many open files

2028-02-28#linux#systemd#운영

서비스 로그에 Too many open files가 찍혀서 ulimit -n 65536으로 올렸는데, 재시작해도 여전히 죽습니다. 원인은 단순합니다. 셸에서 본 ulimit과 systemd가 데몬에 적용하는 한도는 서로 다른 경로이기 때문입니다. 터미널에서 올린 값은 그 셸과 자식에만 적용되고, systemd가 띄운 서비스에는 전혀 영향이 없습니다.

진단 — 두 곳을 따로 본다

먼저 내 셸의 한도:

로컬 터미널
ulimit -n
# 1024

그리고 실제로 돌고 있는 프로세스의 한도를 확인합니다. 이게 진짜 적용된 값입니다.

로컬 터미널
cat /proc/$(pgrep -f myapp)/limits | grep "open files"
# Max open files   1024   1024   files

systemd 서비스라면 유닛에 설정된 값도 봅니다.

서버 터미널
systemctl show myapp.service -p LimitNOFILE
# LimitNOFILE=1024

셸의 ulimit -n을 65536으로 올려도 위 두 값이 1024 그대로면, 데몬에는 아무것도 반영되지 않은 것입니다.

개념 — 어디서 한도가 정해지나

경로적용 대상설정 위치
ulimit -n (셸)로그인 셸과 그 자식/etc/security/limits.conf (PAM 경유)
systemd LimitNOFILEsystemd가 띄운 서비스유닛 파일 [Service]

limits.conf는 PAM 로그인 세션에만 걸립니다. systemd가 부팅 시 직접 띄운 데몬은 PAM을 거치지 않으므로 limits.conf를 무시하고 유닛의 LimitNOFILE을 따릅니다. 여기서 어긋남이 생깁니다.

해결 — systemd 서비스에 직접 적용

drop-in으로 안전하게 덮어씁니다(원본 유닛은 건드리지 않음).

서버 터미널
sudo systemctl edit myapp.service
INI
[Service]
LimitNOFILE=65536

저장 후 데몬 재로드와 재시작이 둘 다 필요합니다.

서버 터미널
sudo systemctl daemon-reload
sudo systemctl restart myapp.service

체크리스트

로컬 터미널
cat /proc/$(pgrep -f myapp)/limits | grep "open files"  # 실제 적용값
systemctl show myapp.service -p LimitNOFILE             # 유닛 설정값
systemctl edit myapp.service                            # LimitNOFILE drop-in
systemctl daemon-reload && systemctl restart myapp      # 반영

기억할 한 가지: 데몬의 한도는 ulimit이 아니라 /proc/<pid>/limits로 검증한다. 셸에서 본 숫자는 데몬과 무관할 수 있습니다.


ulimit·limits.conf·systemd 유닛이 어떻게 맞물리는지 직접 만져보는 실습은 리눅스 트랙에서 회원가입 없이 무료로 익힐 수 있습니다.