そんな連絡を深夜に受けた経験がある人は少なくないだろう。プロセスを再起動すれば一時的に回復するが、数時間後にはまた同じ状態になる——この繰り返しが現場を消耗させる。
原因はファイルディスクリプタ(FD)の枯渇だ。「上限を上げれば解決」と思われがちだが、FDリークが原因の場合は上限を上げても焼け石に水になる。まず現状を正確に把握してから手を打つのが正解だ。
この記事では、FD枯渇の仕組みから調査コマンド、上限値の恒久設定、FDリークの特定まで、一連の対処手順を実機の出力例とあわせて解説する。RHEL 9.4 / Ubuntu 24.04 LTS で動作確認済み。
この記事のポイント
・/proc/sys/fs/file-nr でシステム全体のFD使用数を即座に把握できる
・lsof でFDを大量消費しているプロセスをPID別に特定できる
・limits.confとLimitNOFILEの2箇所を設定しないと恒久化されない
・FDが時間とともに増え続ける場合はアプリのFDリークを疑う
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
ファイルディスクリプタとは何か(なぜエラーが起きるのか)
Linuxではファイルを開くたびに、カーネルがプロセスに「ファイルディスクリプタ(FD)」という整数番号を割り当てる。ファイルだけでなく、ソケット・パイプ・デバイスなど、プロセスが「開いているもの」はすべてFDで管理される。・stdin(標準入力): FD 0
・stdout(標準出力): FD 1
・stderr(標準エラー出力): FD 2
・以降は open() や accept() のたびに 3、4、5…と割り当てられる
カーネルはFDの上限を2段階で管理している。
・プロセス単位の上限: 1プロセスが同時に開けるFDの最大数(ulimit -n で確認できる値)
・システム全体の上限: 全プロセス合計のFD使用数の上限(/proc/sys/fs/file-max で確認できる値)
プロセスが上限に達すると、新しくファイルやソケットを開こうとしたときにカーネルがEMFILEエラーを返す。これがアプリ側で「Too many open files」として表示される原因だ。
まず現状を把握する(/proc/sys/fs/file-nr と journalctl)
エラーが出たら、「プロセス単位の上限超過か」「システム全体の上限超過か」を最初に切り分ける。1. journalctl でエラーの発生時刻とプロセスを確認する
どのプロセスがいつエラーを出したかを最初に把握する。# 直近1時間のToo many open files関連のログを確認 journalctl -xe --since "1 hour ago" | grep -i "too many open" # RHEL系は /var/log/messages でも確認できる grep -i "too many open" /var/log/messages
Aug 22 03:17:42 web01 nginx[4821]: 2026/08/22 03:17:42 [alert] 4821#4821: socket() failed (24: Too many open files) while accepting new connection on 0.0.0.0:443
2. /proc/sys/fs/file-nr でシステム全体のFD使用数を確認する
cat /proc/sys/fs/file-nr
34304 0 392328
・1列目(34304): 現在使用中のFD数(システム全体合計)
・2列目(0): 割り当て済みだが未使用のFD数(通常は0)
・3列目(392328): システム全体の最大FD数(fs.file-max の値)
1列目が3列目の値に近い場合はシステム全体の枯渇を疑う。1列目が少ないにもかかわらずエラーが出る場合は、特定プロセスのプロセス単位上限超過を疑う。
3. 特定プロセスのFD上限と現在値を確認する
# 現在のシェルのFD上限を確認 ulimit -n # 特定プロセス(PID=4821)の上限を確認 cat /proc/4821/limits | grep "Max open files" # 現在そのプロセスが使っているFD数を確認 ls /proc/4821/fd | wc -l
Limit Soft Limit Hard Limit Units Max open files 1024 4096 files
プロセス別のFD使用数を調べる(lsof と /proc/PID/fd)
1. FDを多く使っているプロセスをランキングで把握する
# PID別のFD使用数ランキング(上位10プロセス) lsof 2>/dev/null | awk '{print $2}' | sort | uniq -c | sort -rn | head -10
1823 4821 312 1234 241 5610 87 998
2. 特定プロセスのFD種別を確認する
FDが何に使われているか(ファイル・ソケット・パイプ)を種別ごとに集計すると、原因の当たりがつきやすい。# PID=4821のFDを種別ごとに集計 lsof -p 4821 2>/dev/null | awk '{print $5}' | sort | uniq -c | sort -rn
1547 IPv4 189 REG 56 PIPE 17 IPv6 14 CHR
・IPv4/IPv6 が多い → ソケット(TCP接続)のclose漏れを疑う
・PIPE が多い → パイプのclose漏れを疑う
上記の例ではIPv4ソケットが1547個を占めており、TCPコネクションが積もっていると判断できる。Linux ポート確認の全コマンドで解説しているように、`lsof -i` でソケットの接続先や状態(ESTABLISHED/CLOSE_WAIT)を確認すると調査がさらに進む。
上限を一時的に引き上げる(ulimit -n と systemd の LimitNOFILE)
まず一時的に上限を上げてサービスを安定させてから、恒久設定に移る。1. ulimit -n で現在のシェルの上限を変更する
# FD上限を65535に変更(現在のシェルとそこから起動したプロセスに適用) ulimit -n 65535 # 確認 ulimit -n
2. systemdサービスは LimitNOFILE で設定する
nginxやMySQLなど、systemdで管理されているサービスはPAMを経由しないため limits.conf を読まない。ユニットファイルで個別に設定する必要がある。# ユニットファイルをオーバーライドで編集する(nginx の例) systemctl edit nginx
[Service] LimitNOFILE=65535
systemctl daemon-reload systemctl restart nginx # 反映確認(新PIDを確認してから実行する) cat /proc/$(pidof -s nginx)/limits | grep "Max open files"
Max open files 65535 65535 files
上限を恒久的に変更する(limits.conf と sysctl fs.file-max)
1. /etc/security/limits.conf でプロセス上限を永続設定する
全ユーザーに適用する場合:# /etc/security/limits.conf に追記する * soft nofile 65535 * hard nofile 65535
nginx soft nofile 65535 nginx hard nofile 65535
重要: systemdで管理するサービス(nginx、MySQL等)はPAMを経由しないため、limits.conf の設定は効かない。systemdサービスは前節のLimitNOFILEで個別に設定する。
2. sysctl で fs.file-max(システム全体の上限)を変更する
# 現在値の確認 sysctl fs.file-max # 一時的な変更(再起動後に元に戻る) sysctl -w fs.file-max=1000000
# 設定ファイルを新規作成して永続化する echo "fs.file-max = 1000000" | tee /etc/sysctl.d/99-filemax.conf # 即時反映 sysctl -p /etc/sysctl.d/99-filemax.conf # 確認 sysctl fs.file-max
fs.file-max = 1000000
3. 設定の優先順と落とし穴
混乱しやすいポイントをまとめる:・SSHでログインしたシェルなど、PAM経由のプロセス: limits.conf が有効
・systemdで管理されるサービス: limits.conf は無効。LimitNOFILE をユニットファイルに設定する
・limits.conf を変更してもsysctl fs.file-max が低ければシステム全体で詰まる
・/etc/systemd/system.conf の DefaultLimitNOFILE でsystemdの全サービスのデフォルト値を一括変更することもできる
FDリークを疑うときの調査手順
上限を引き上げても数時間後にまたエラーが出る場合は、アプリがFDをclose()せずに積み重ねている「FDリーク」を疑う。再起動直後はFD数が減り、時間とともに単調増加するパターンが典型的だ。1. watch コマンドでFD数の増加を監視する
# PID=4821のFD数を5秒ごとに監視する watch -n 5 "ls /proc/4821/fd | wc -l"
2. FDの種別で原因を絞る
# 1分間隔でFD種別の集計を記録する(Ctrl+C で停止) while true; do echo "=== $(date) ===" lsof -p 4821 2>/dev/null | awk '{print $5}' | sort | uniq -c | sort -rn | head -5 sleep 60 done
3. 緊急回避としての定期再起動
FDリークの根本修正に時間がかかる場合は、cron で定期的にサービスを再起動して延命する。# crontab -e で追加(毎日深夜3時に再起動する例) 0 3 * * * /usr/bin/systemctl restart myapp
本記事のまとめ
「Too many open files」の対処は、「現状把握 → 上限変更 → リーク調査」の3段階で進める。まずプロセス単位の枯渇かシステム全体の枯渇かを切り分け、原因に合わせた設定変更を行う。| やりたいこと | コマンド |
|---|---|
| システム全体のFD使用数を確認する | cat /proc/sys/fs/file-nr |
| システム全体の最大FD数を確認する | sysctl fs.file-max |
| プロセスのFD上限を確認する | cat /proc/PID/limits | grep "Max open files" |
| PID別のFD使用数ランキングを出す | lsof 2>/dev/null | awk '{print $2}' | sort | uniq -c | sort -rn | head -10 |
| 特定プロセスのFD数を確認する | ls /proc/PID/fd | wc -l |
| FD上限を一時的に変更する(シェル) | ulimit -n 65535 |
| systemdサービスのFD上限を設定する | ユニットファイルに LimitNOFILE=65535 を追記 |
| FD上限を永続設定する(PAM経由プロセス) | /etc/security/limits.conf に * soft nofile 65535 を追記 |
| システム全体の上限を永続設定する | /etc/sysctl.d/99-filemax.conf に fs.file-max = 1000000 を追記 |
| FDリークの有無を監視する | watch -n 5 "ls /proc/PID/fd | wc -l" |
FDエラーを素早く解消できるのは、Linuxの仕組みを体系的に理解しているから
ulimitの変更方法は調べれば分かります。でも「なぜsystemdサービスはlimits.confを読まないのか」「FDリークとプロセス上限不足はどう見分けるのか」を現場で即答できますか?
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、『Linuxサーバー構築入門マニュアル(図解60P)』を完全無料でプレゼントしています。
「独学の時間がもったいない」「プロから直接、現場の技術を最短で学びたい」という本気の方には、2日で実務レベルのスキルが身につく【初心者向けハンズオンセミナー】も開催しています。
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 前のページへ:setcap・getcapコマンドでLinuxのケーパビリティを設定する方法|root不要で特権ポートとrawソケットを安全に実現する
- この記事の属するカテゴリ:Linuxtips・Linuxトラブルシューティングへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます