LinuxでToo many open filesエラーが出た時の対処法|ファイルディスクリプタ枯渇の調査からulimit・sysctl設定まで

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOME > Linux技術 リナックスマスター.JP(Linuxマスター.JP) > Linuxtips, Linuxトラブルシューティング > LinuxでToo many open filesエラーが出た時の対処法|ファイルディスクリプタ枯渇の調査からulimit・sysctl設定まで
「サーバーが落ちた。ログに『Too many open files』が大量に出ている。」
そんな連絡を深夜に受けた経験がある人は少なくないだろう。プロセスを再起動すれば一時的に回復するが、数時間後にはまた同じ状態になる——この繰り返しが現場を消耗させる。

「ファイルが多すぎる=ディスクが溢れた」と思い込んで df コマンドを打ち、問題がないとわかると今度は古いログファイルを削除し始める——私自身、SE時代に同じ間違いを犯して2時間以上無駄にした。原因はファイルディスクリプタ(FD)の枯渇だ。「上限を上げれば解決」と思われがちだが、FDリークが原因の場合は上限を上げても焼け石に水になる。まず現状を正確に把握してから手を打つのが正解だ。

この記事では、FD枯渇の仕組みから調査コマンド、上限値の恒久設定、FDリークの特定まで、一連の対処手順を実機の出力例とあわせて解説する。RHEL 9.4 / Ubuntu 24.04 LTS で動作確認済み。

この記事のポイント

・/proc/sys/fs/file-nr でシステム全体のFD使用数を即座に把握できる
・lsof でFDを大量消費しているプロセスをPID別に特定できる
・limits.confとLimitNOFILEの2箇所を設定しないと恒久化されない
・上限を「unlimited」に設定するのは危険——必ず具体的な数値を入れる
・FDが時間とともに増え続ける場合はアプリのFDリークを疑う


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

SE時代に「Too many open files」で2時間右往左往した話

2004年、私がSEとして担当していたWebサーバーで起きた出来事だ。

昼過ぎからアクセスが増えてきた頃、本番のApacheが断続的にエラーを返すようになった。ブラウザには「503 Service Unavailable」が表示され、上司から「早く直してくれ」と催促を受けながら焦って対応していた。

pingはサーバーに通る。SSHでログインもできる。ps コマンドでApacheのプロセスが動いていることも確認できる。なのにリクエストに応答しない。何が起きているのかまったくわからなかった。

先輩から「エラーログを見ろ」と言われて /var/log/httpd/error_log を開いたところ、次のようなメッセージが延々と並んでいた。

[Wed Apr 07 13:42:17 2004] [emerg] (24)Too many open files: Error getting accept lock. Exiting! [Wed Apr 07 13:42:18 2004] [emerg] (24)Too many open files: Error getting accept lock. Exiting! [Wed Apr 07 13:42:19 2004] [emerg] (24)Too many open files: Error getting accept lock. Exiting!

「(24)って何だ?ファイルが多すぎる?ディスクが溢れたのか?」と思い、df コマンドを打ったが容量は問題なし。次に古そうなログファイルを削除し始めたが、まったく改善しなかった。

そのとき先輩に言われた一言が、「それはディスクの問題じゃない。ulimit を確認しろ」だった。

この一言で初めてファイルディスクリプタという概念を知った。原因が明確になった瞬間、2時間の右往左往が恥ずかしくなったのを今でも覚えている。それ以来、「Too many open files」が出たときは必ずulimitを最初に確認することを習慣にしている。

ファイルディスクリプタとは何か(なぜエラーが起きるのか)

Linuxではファイルを開くたびに、カーネルがプロセスに「ファイルディスクリプタ(FD)」という整数番号を割り当てる。ファイルだけでなく、ソケット・パイプ・デバイスなど、プロセスが「開いているもの」はすべてFDで管理される。

・stdin(標準入力): FD 0
・stdout(標準出力): FD 1
・stderr(標準エラー出力): FD 2
・以降は open() や accept() のたびに 3、4、5…と割り当てられる

重要なのは、Linuxにおける「ファイル」の概念が非常に広いことだ。通常のテキストファイルだけでなく、以下のリソースもすべてFDを消費する。

・通常ファイル: テキストファイル、ログファイル、バイナリファイルなど
・ソケット: TCP/UDPによるネットワーク接続(HTTPリクエスト1件で1つ消費)
・パイプ: プロセス間でデータをやり取りするためのパイプ
・デバイスファイル: /dev/ 配下にあるデバイスへのアクセス

カーネルはFDの上限を2段階で管理している。

・プロセス単位の上限: 1プロセスが同時に開けるFDの最大数(ulimit -n で確認できる値)
・システム全体の上限: 全プロセス合計のFD使用数の上限(/proc/sys/fs/file-max で確認できる値)

プロセスが上限に達すると、新しくファイルやソケットを開こうとしたときにカーネルがEMFILEエラーを返す。これがアプリ側で「Too many open files」として表示される原因だ。

注意しなければならないのは、「ファイル」という名称に惑わされないことだ。Webサーバーがクライアントとの接続を1本確立するたびに、ソケット用のFDを1つ消費する。各接続で1つ、エラーログの書き込みで1つ、設定ファイルの読み込みで複数、といった具合にどんどん積み上がっていく。Linuxのデフォルト上限は「1プロセスあたり1024個」に設定されていることが多く、ある程度のアクセスが来るサーバーではすぐに壁にぶつかる数字だ。

セミナーで「なぜデフォルトが低いの?」と質問を受けることがある。理由は歴史的なもので、Linuxが設計された時代のシステムリソースに合わせた値が今に至るまで残っている。現代のサーバー運用者が意識して見直すべき設定のひとつだ。

まず現状を把握する(/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 # Apache/httpd のエラーログを直接確認する場合 grep -i "too many open" /var/log/httpd/error_log grep -i "too many open" /var/log/apache2/error.log

実際の出力例(RHEL 9.4):

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

Apacheの場合は次のような出力が短時間に大量に並ぶ:

[Wed Mar 05 08:47:12 2003] [error] (24)Too many open files: accept client connection: (null) [Wed Mar 05 08:47:12 2003] [error] (24)Too many open files: accept client connection: (null) [Wed Mar 05 08:47:13 2003] [error] (24)Too many open files: couldn't create accept lock

プロセス名とPIDがわかる。次のステップでそのプロセスのFD使用状況を掘り下げる。

2. /proc/sys/fs/file-nr でシステム全体のFD使用数を確認する

cat /proc/sys/fs/file-nr

出力例:

34304 0 392328

3列の意味:

・1列目(34304): 現在使用中のFD数(システム全体合計)
・2列目(0): 割り当て済みだが未使用のFD数(通常は0)
・3列目(392328): システム全体の最大FD数(fs.file-max の値)

1列目が3列目の値に近い場合はシステム全体の枯渇を疑う。1列目が少ないにもかかわらずエラーが出る場合は、特定プロセスのプロセス単位上限超過を疑う。

3. 特定プロセスのFD上限と現在値を確認する

# ソフトリミット(現在のセッションに適用されている上限値)を確認する ulimit -Sn # ハードリミット(一般ユーザー権限で設定できる最大値)を確認する ulimit -Hn # 特定プロセス(PID=4821)の上限を確認する cat /proc/4821/limits | grep "Max open files" # 現在そのプロセスが使っているFD数を確認する ls /proc/4821/fd | wc -l

soft limitとhard limitの違いを整理しておく。

・soft limit: 現在実際に適用されている上限値。ユーザーはhard limitを超えない範囲で自分で変更できる
・hard limit: 管理者(root)のみが変更できる上限値。ユーザーはこれを超えた値をsoft limitに設定することはできない

出力例(/proc/4821/limits):

Limit Soft Limit Hard Limit Units Max open files 1024 4096 files

「Soft Limit(1024)」が現在の実効上限、「Hard Limit(4096)」が一般ユーザー権限で設定できる上限の最大値だ。ulimit -n で変更できるのはSoft Limitの範囲内に限られる。

プロセス別のFD使用数を調べる(lsof と /proc/PID/fd)

1. FDを多く使っているプロセスをランキングで把握する

# PID別のFD使用数ランキング(上位10プロセス) lsof 2>/dev/null | awk '{print $2}' | sort | uniq -c | sort -rn | head -10 # 特定ユーザー(例: nginx)が使っているFDの総数を確認する lsof -u nginx 2>/dev/null | wc -l

出力例:

1823 4821 312 1234 241 5610 87 998

1列目がFD数、2列目がPIDだ。PID 4821 が1823個のFDを持っており突出している。先ほどのjournalctlで確認したPIDと一致すれば、そのプロセスが原因と断定できる。

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

・REG(Regular file)が多い → ファイルのclose()忘れを疑う
・IPv4/IPv6 が多い → ソケット(TCP接続)のclose漏れを疑う
・PIPE が多い → パイプのclose漏れを疑う

上記の例ではIPv4ソケットが1547個を占めており、TCPコネクションが積もっていると判断できる。Linux ポート確認の全コマンドで解説しているように、`lsof -i` でソケットの接続先や状態(ESTABLISHED/CLOSE_WAIT)を確認すると調査がさらに進む。

上限を一時的に引き上げる(ulimit -n と systemd の LimitNOFILE)

まず一時的に上限を上げてサービスを安定させてから、恒久設定に移る。

1. ulimit -n で現在のシェルの上限を変更する

# すべてのリソース制限を一覧確認する(open files の行に注目) ulimit -a # FD上限を65535に変更する(現在のシェルとそこから起動したプロセスに適用) ulimit -n 65535 # 確認する ulimit -n

`ulimit -a` を実行すると全リソース制限を一覧できる。「open files (-n)」の行がFD上限だ。出力例:

core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signals (-i) 15264 max locked memory (kbytes, -l) 64 max memory size (kbytes, -m) unlimited open files (-n) 1024 pipe size (512 bytes, -p) 8 POSIX message queues (bytes, -q) 819200 real-time priority (-r) 0 stack size (kbytes, -s) 8192 cpu time (seconds, -t) unlimited max user processes (-u) 15264 virtual memory (kbytes, -v) unlimited file locks (-x) unlimited

ulimit -n での変更は現在のシェルにしか効かない。既に起動済みのサービスには適用されないため、サービスの再起動が必要になる。

2. systemdサービスは LimitNOFILE で設定する

nginxやMySQLなど、systemdで管理されているサービスはPAMを経由しないため limits.conf を読まない。ユニットファイルで個別に設定する必要がある。

# ユニットファイルをオーバーライドで編集する(nginx の例) # 「systemctl edit」を使うと自動でdrop-inファイルが作成される systemctl edit nginx

エディタが開いたら以下を追記して保存する:

[Service] LimitNOFILE=65535

「systemctl edit」を使うと /etc/systemd/system/nginx.service.d/override.conf というオーバーライドファイルが自動で作成される。元のunitファイル(/usr/lib/systemd/system/nginx.service)を直接編集してしまうと、パッケージアップデート時に上書きされて設定が消えることがある。現場での実務上の鉄則だ。

あるいは設定ディレクトリを直接作成して追加する方法でも同じ効果が得られる:

# drop-inディレクトリを作成して設定ファイルを追加する(nginx の例) mkdir -p /etc/systemd/system/nginx.service.d/ cat > /etc/systemd/system/nginx.service.d/limits.conf << 'EOF' [Service] LimitNOFILE=65535 EOF

設定を反映してサービスを再起動する:

systemctl daemon-reload systemctl restart nginx # 反映確認(新PIDを確認してから実行する) cat /proc/$(pidof -s nginx)/limits | grep "Max open files"

出力例:

Limit Soft Limit Hard Limit Units Max open files 65535 65535 files

Soft/Hard ともに65535になっていれば設定が反映されている。`systemctl show nginx | grep LimitNOFILE` でも確認できる:

LimitNOFILE=65535 LimitNOFILESoft=65535

上限を恒久的に変更する(limits.conf と sysctl fs.file-max)

1. /etc/security/limits.conf でプロセス上限を永続設定する

全ユーザーに適用する場合:

# /etc/security/limits.conf に追記する * soft nofile 65535 * hard nofile 65535

特定ユーザー(例: nginx)だけに設定する場合:

nginx soft nofile 65535 nginx hard nofile 65535

この設定はログアウト・ログイン後に適用される。既存のセッションには影響しないことに注意する。

重要: systemdで管理するサービス(nginx、MySQL等)はPAMを経由しないため、limits.conf の設定は効かない。systemdサービスは前節のLimitNOFILEで個別に設定する。「limits.confに設定したのに変わらない」という場合はほぼ間違いなくこのパターンだ。まずサービスの起動方法(systemd管理か否か)を確認してから設定を変えることが先決だ。

2. sysctl で fs.file-max(システム全体の上限)を変更する

# 現在値の確認 sysctl fs.file-max # 一時的な変更(再起動後に元に戻る) sysctl -w fs.file-max=1000000

永続化するには /etc/sysctl.d/ に設定ファイルを作成する:

# 設定ファイルを新規作成して永続化する 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の全サービスのデフォルト値を一括変更することもできる

4. 上限値はいくつに設定すべきか

セミナーで「どんな値を設定すればいいか?」とよく質問を受ける。現場で使っている目安を2点お伝えする。

「unlimited」は設定しない

hard limitをunlimitedにすると、プロセスがFDを際限なく開き続けられるようになる。FDリーク(バグによって正しくクローズされない状態)が起きているプログラムがあった場合、メモリを食いつぶしてシステムがクラッシュする原因になる。必ず具体的な数値を設定すること。

ピーク値の2~3倍を目安にする

`ls /proc/PID/fd | wc -l` で実測した最大使用量が1,000であれば、2,048~4,096程度が適切だ。Webサーバーであれば最大同時接続数×2程度のマージンを持たせた値が目安になる。65535(64K近辺)はよく使われる設定値で、ほとんどのWebサービスにとっては十分な余裕がある。変更後は必ず `/proc/[PID]/limits` で設定が反映されたことを確認してから作業完了とすること。

FDリークを疑うときの調査手順

上限を引き上げても数時間後にまたエラーが出る場合は、アプリがFDをclose()せずに積み重ねている「FDリーク」を疑う。再起動直後はFD数が減り、時間とともに単調増加するパターンが典型的だ。

1. watch コマンドでFD数の増加を監視する

# PID=4821のFD数を5秒ごとに監視する watch -n 5 "ls /proc/4821/fd | wc -l"

正常なプロセスはFD数が上下しながら一定範囲に収まる。リークがある場合は5秒ごとに単調増加し続け、上限に達するまで止まらない。

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

どの種別(REG/IPv4/PIPE)が増え続けているかを記録し、対応するコードの箇所を開発チームに共有する。

3. 緊急回避としての定期再起動

FDリークの根本修正に時間がかかる場合は、cron で定期的にサービスを再起動して延命する。

# crontab -e で追加(毎日深夜3時に再起動する例) 0 3 * * * /usr/bin/systemctl restart myapp

あくまでも一時対応だ。根本原因(アプリのFDリーク)の修正を優先すること。

本記事のまとめ

「Too many open files」の対処は、「現状把握 → 上限変更 → リーク調査」の3段階で進める。まずプロセス単位の枯渇かシステム全体の枯渇かを切り分け、原因に合わせた設定変更を行う。

3,100名以上の受講生と向き合ってきた中で、障害対応が得意なエンジニアほど「確認の型」を持っているという共通点がある。対処で特につまずきやすい3点を押さえておこう:

・「ファイル」という名前に惑わされない: ネットワーク接続(ソケット)もパイプもFDで管理される。Webサーバーのアクセス集中でFDが枯渇するのはそのためだ
・サービスの起動方法を確認してから設定を変える: systemd管理のサービスにはlimits.confが効かない。LimitNOFILEをユニットファイルに設定する
・「設定した」で終わりにしない: 変更後は必ず /proc/[PID]/limits で反映を確認する

やりたいこと コマンド
システム全体のFD使用数を確認する cat /proc/sys/fs/file-nr
システム全体の最大FD数を確認する sysctl fs.file-max
プロセスのFD上限を確認する cat /proc/PID/limits | grep "Max open files"
soft/hard limitを個別に確認する ulimit -Sn / ulimit -Hn
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上限を設定する systemctl edit サービス名 で 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"
次に読む記事:
・Linuxのポート確認コマンド|ss・lsofの使い方
・chkconfigとsystemctlの使い分け|サービスの自動起動設定

FDエラーを素早く解消できるのは、Linuxの仕組みを体系的に理解しているから

ulimitの変更方法は調べれば分かります。でも「なぜsystemdサービスはlimits.confを読まないのか」「FDリークとプロセス上限不足はどう見分けるのか」を現場で即答できますか?
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、『Linuxサーバー構築入門マニュアル(図解60P)』を完全無料でプレゼントしています。

※ 「独学の時間がもったいない」「プロから直接、現場の技術を最短で学びたい」という本気の方には、2日で実務レベルのスキルが身につく【初心者向けハンズオンセミナー】も開催しています。

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。