서비스를 띄우면 다음이 찍히고 기동이 실패하거나 감시 기능만 동작하지 않는다.
systemd[1]: Failed to allocate directory watch: Too many open files
journalctl, sshd, firewalld, 에이전트류, 파일 감시를 쓰는 개발 도구에서 흔히 본다.
메시지에 Too many open files 가 들어 있어 파일 디스크립터 한계로 오해하기 쉽다. 그래서 ulimit -n 과 LimitNOFILE 을 올리는데, 그래도 같은 메시지가 계속 나온다.
directory watch 는 inotify 로 만드는 감시자다. inotify 에는 파일 디스크립터와는 별개의 커널 한계가 있고, 그 한계를 넘으면 커널이 EMFILE 을 돌려준다. 같은 errno 를 쓰기 때문에 메시지만 보면 구분되지 않는다.
두 값이 있다.
| 파라미터 | 뜻 | 기본값 계열 |
|---|---|---|
fs.inotify.max_user_instances |
사용자 한 명이 만들 수 있는 inotify 인스턴스 수 | 128 |
fs.inotify.max_user_watches |
사용자 한 명이 걸 수 있는 감시 대상 수 | 8192 또는 그 이상 |
기동이 아예 안 되고 directory watch 를 못 만든다면 대개 max_user_instances 쪽이다. 감시는 되는데 일부 디렉터리가 빠진다면 max_user_watches 쪽이다.
현재 값을 본다.
cat /proc/sys/fs/inotify/max_user_instances
cat /proc/sys/fs/inotify/max_user_watches
누가 얼마나 쓰고 있는지 센다. 대부분 root 로 도는 서비스가 몰려 있다.
find /proc/*/fd -lname 'anon_inode:inotify' 2>/dev/null | cut -d/ -f3 | sort | uniq -c | sort -rn | head
프로세스 이름까지 함께 본다.
for pid in $(find /proc/*/fd -lname 'anon_inode:inotify' 2>/dev/null | cut -d/ -f3 | sort -u); do
printf '%s %s\n' "$pid" "$(cat /proc/$pid/comm 2>/dev/null)"
done | sort -k2 | uniq -c -f1 | sort -rn | head
즉시 적용한다.
sudo sysctl -w fs.inotify.max_user_instances=512
sudo sysctl -w fs.inotify.max_user_watches=524288
재부팅 후에도 남기려면 파일로 둔다.
sudo tee /etc/sysctl.d/90-inotify.conf > /dev/null <<'SYSCTL'
fs.inotify.max_user_instances = 512
fs.inotify.max_user_watches = 524288
SYSCTL
sudo sysctl --system
값을 적용한 뒤 실패했던 서비스를 다시 띄운다. 기동 실패였다면 바로 뜬다.
sudo systemctl restart sshd
무한정 올리는 값이 아니다. 감시자 하나마다 커널 메모리를 쓴다. 감시 대상 하나당 수십 바이트 수준이라 max_user_watches 를 524288 로 두어도 실사용 메모리는 크지 않지만, 근거 없이 수백만으로 올리지는 않는다.
실무 기준은 다음 정도다.
Cloudera Data Services 처럼 요구값을 명시하는 제품이 있다. 제품 요구값이 있으면 그것을 먼저 따른다.
Too many open files 가 inotify 와 무관하게 나오는 경우도 물론 있다. 다음이 같이 보이면 그쪽이다.
accept: Too many open files
socket: Too many open files
java.io.IOException: Too many open files
이때 볼 것은 다르다.
cat /proc/sys/fs/file-nr
ulimit -n
cat /proc/<PID>/limits | grep 'open files'
ls /proc/<PID>/fd | wc -l
프로세스별 한계와 조정은 ulimit 편집 과 프로세스 메모리와 열린 파일 에 정리돼 있다. systemd 로 뜨는 서비스는 limits.conf 가 적용되지 않으므로 유닛의 LimitNOFILE 을 쓴다.
sudo systemctl edit sshd
[Service]
LimitNOFILE=65535