ulimit 入門 - プロセスのリソース上限を理解する
ulimit とは?
結論:
ulimitは shell とそこから起動するプロセスが使えるリソース量(開けるファイル数・プロセス数・メモリ等)の上限を確認・変更するコマンド。
ulimit は bash 等の shell に組み込まれたコマンドで、カーネルの getrlimit(2) / setrlimit(2) を呼び出してリソース上限(resource limit)を操作する。上限は「1 プロセスあたり」に適用され、fork した子プロセスへ継承される。
代表的な用途は次の 3 つ。
- 「Too many open files」のような上限到達エラーの原因切り分け
- DB / Web サーバ等の同時接続数に見合う上限の引き上げ
- 暴走スクリプトによる資源枯渇を防ぐ上限の引き下げ
前提(対象環境)
- bash を前提(
ulimitは shell ビルトイン。zsh等でも利用可だがオプションが一部異なる) - 永続化の節は systemd ベースのディストリ(Ubuntu / RHEL 系)を想定
ソフトリミットとハードリミットの違いは?
結論: ソフトは実際に効く上限、ハードはソフトの天井。非特権ユーザーはソフトをハードまで上げられるが、ハードを引き上げるには root 権限が必要。
各リソースには 2 つの値がある。
| 種別 | 意味 | 非特権ユーザーの変更可否 |
|---|---|---|
| ソフト(soft) | 実際に強制される現在の上限 | ハード以下なら自由に増減できる |
| ハード(hard) | ソフトが超えられない天井 | 下げる方向のみ(上げは不可) |
ハードを一度下げると同一プロセス内では戻せない(戻すには root 権限 = CAP_SYS_RESOURCE が必要)。ulimit ではフラグで対象を切り替える。
$ ulimit -Sn # ソフトの open files 上限を表示 $ ulimit -Hn # ハードの open files 上限を表示
-S:ソフトリミットを対象-H:ハードリミットを対象- 省略時:表示はソフト、設定は両方を同時に変更する点に注意
現在の上限を確認するには?
結論:
ulimit -aで全リソースの現在のソフト上限を一覧表示できる。個別に見るときは-n(ファイル)等の単独フラグを使う。
$ ulimit -a
real-time non-blocking time (microseconds, -R) unlimited core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signals (-i) 15363 max locked memory (kbytes, -l) 8192 max memory size (kbytes, -m) unlimited open files (-n) 1024 pipe size (512 bytes, -p) 8 stack size (kbytes, -s) 8192 max user processes (-u) 15363 virtual memory (kbytes, -v) unlimited
-a はソフト値を表示する。ハード値をまとめて見たいときは ulimit -aH を使う。
$ ulimit -aH # 全リソースのハード上限
主なリソース種別の一覧
結論: 実務で触る頻度が高いのは
-n(open files)・-u(プロセス数)・-c(core)・-s(stack)の 4 つ。
| フラグ | リソース | 典型的な用途・症状 |
|---|---|---|
-n |
open files | 「Too many open files」。FD 数の上限 |
-u |
max user processes | 「fork: retry: Resource temporarily unavailable」 |
-c |
core file size | クラッシュ時の core dump 出力可否(0 で無効) |
-f |
file size | 1 ファイルあたりの最大サイズ |
-s |
stack size | 深い再帰での segfault 調査 |
-v |
virtual memory | プロセスの仮想メモリ総量の上限 |
-l |
max locked memory | mlock できるメモリ量(DB 等で関係) |
-u(max user processes)はそのユーザー全体のプロセス数に対する上限。一見「このシェルだけ」に見えて、同一 UID の全プロセスを合算してカウントする点に注意する。
上限を一時的に変更するには?
結論:
ulimit -Sn 4096のように実行すると、その shell と以降に起動する子プロセスにだけ反映される。shell を閉じると元に戻る。
# ソフトの open files をハードの範囲内で 4096 に引き上げ $ ulimit -Sn 4096 # 確認 $ ulimit -Sn 4096
ハードを超える値を指定すると拒否される。
$ ulimit -Sn 999999 bash: ulimit: open files: cannot modify limit: Operation not permitted
この場合はハードの引き上げが必要で、非特権ユーザーでは不可。ハードごと上げるには root で次のように実行する(root は両方変更できる)。
# root のみ。ソフト/ハードを同時に 65536 へ $ sudo bash -c 'ulimit -n 65536; exec your-server'
ulimit の効果はそれを実行した shell とその子孫にしか及ばない。既に動いているデーモンの上限は変わらない。稼働中プロセスへの適用は prlimit を使う。
上限を永続化するには?
結論: ログインセッションには
/etc/security/limits.d/*.conf、systemd 管理のサービスには unit のLimitNOFILE=を使う。両者は適用経路が別物。
ログインシェル(pam_limits 経由)
/etc/security/limits.conf および /etc/security/limits.d/*.conf は、PAM の pam_limits モジュールがログイン時に適用する。SSH ログインや login 経由の shell が対象。
# /etc/security/limits.d/90-nofile.conf * soft nofile 8192 * hard nofile 65536 deploy soft nproc 4096
書式は <domain> <type> <item> <value>。domain はユーザー名・@グループ名・全体を表す *。設定後はいったんログアウトして再ログインしないと反映されない。
pam_limits は PAM セッションを経由しないプロセスには効かない。systemd が起動するデーモンには limits.conf は適用されないため、サービスの上限を上げたつもりが効かない事故が多い。
systemd サービス
systemd 管理のサービスは unit ファイルの [Service] セクションで指定する。
# /etc/systemd/system/myapp.service.d/override.conf [Service] LimitNOFILE=65536 LimitNPROC=4096
$ sudo systemctl daemon-reload $ sudo systemctl restart myapp
全サービス共通のデフォルトを変えるなら /etc/systemd/system.conf の DefaultLimitNOFILE= を編集する。systemctl show myapp -p LimitNOFILE で実効値を確認できる。
実行中プロセスの上限を調べるには?
結論:
/proc/<PID>/limitsを読むかprlimit --pid <PID>を使う。prlimitは再起動なしに稼働中プロセスの上限を変更もできる。
$ cat /proc/1234/limits
Limit Soft Limit Hard Limit Units Max open files 1024 524288 files Max processes 15363 15363 processes ...
prlimit なら 1 行で確認・変更できる。
# 確認 $ prlimit --pid 1234 --nofile # 稼働中プロセスのソフト/ハードを 8192 に変更(権限が必要な場合あり) $ sudo prlimit --pid 1234 --nofile=8192:8192 # コマンドを上限付きで起動 $ prlimit --nofile=4096:4096 ./myserver
Too many open files の対処
結論: まず
lsofで実際の FD 数を数え、上限と突き合わせる。アプリの FD リークか、上限不足かを切り分けてから対処する。
「Too many open files」は open files(-n)の上限到達を示す。手順は次の通り。
- 対象プロセスの PID を特定する
- 実効上限を確認する(
cat /proc/<PID>/limits) - 実際に開いている FD 数を数える
# プロセスが開いている FD 数をカウント $ lsof -p 1234 | wc -l
- FD 数が上限に張り付いていれば、原因を判断する。
- FD リーク(開きっぱなしで閉じていない)→ アプリ側の修正が本筋。上限引き上げは延命策
- 正当に多い(高同時接続)→ 永続化の手順で上限を引き上げる
上限をやみくもに unlimited 近くまで上げるのは避ける。FD リークを隠蔽し、メモリ枯渇やカーネルの file-max 到達といった別の障害に化けることがある。
まとめ
ulimitはプロセス単位のリソース上限を操作するコマンド。ソフト/ハードの二層構造を押さえる- 一時変更は
ulimit -Sn N、確認はulimit -a//proc/<PID>/limits/prlimit - 永続化はログインなら
limits.d/*.conf、systemd サービスなら unit のLimitNOFILE=。経路の取り違えに注意 - 「Too many open files」は上限引き上げの前に FD リークを疑う