Linuxサーバーの怪現象って、だいたいパターンが決まっているんですよね。

消したのに減らない。killしても死なない。SSHを切ったらジョブごと消えた。全部、プロセスとファイルの仕組みが説明してくれます。今回は、運用で必ず出会うものを8つ集めました。1つでも知らなかったら儲けものです。

① rmしたのに、ディスクが減りません

ディスク逼迫時の定番、巨大ログの削除。

$ rm huge.log        # 10GBを削除
$ df -h              # → 空き容量、変わらず!?

原因は、プロセスがそのファイルを開いたままだからです。rmが消すのは「名前」だけで、実体は開いている全プロセスが手放すまで残ります。

犯人は lsof +L1(削除済みなのに開かれているファイル一覧)で見つかります。

  • 消す前なら:ファイルを消すのではなく、中身を空にする(> huge.log)
  • もう消してしまったら:lsofで分かったプロセスID(PID)とfd番号を使い、: > /proc/<PID>/fd/<番号> で中身を空にする。またはそのプロセスを再起動する

「削除=名前を外すこと」——このモデルが頭に入ると、この謎は二度と謎じゃなくなります。

② ゾンビプロセスは、killできません

プロセス一覧に残り続ける <defunct>、ゾンビプロセスです。

kill -9 を打っても消えません。なぜなら、ゾンビはもう死んでいるからです。

ゾンビの正体は、終了済みだが、親プロセスが終了報告(終了コード)をまだ受け取っていない状態。報告書だけが机に残っている、と思ってください。

だから消す方法は、ゾンビ本人ではなく親に報告を受け取らせること。親が回収しないバグなら、親を再起動(または終了)すれば、ゾンビはOSの初代プロセス(PID 1)に引き取られて回収されます。撃つ相手は、親なんです。

③ forkは、メモリを全コピーしません

プロセスの複製(fork)は、親のメモリを丸ごとコピーする——建前上は。

実際は、コピーオンライト(CoW)という仕組みで、その瞬間は何もコピーしません。親子でメモリを共有し、どちらかが書き込んだページだけ、その時に初めて複製します。

だから数GBのメモリを使うプロセスでも、forkは一瞬で終わる。

「巨大プロセスからforkした瞬間にメモリが倍になるのでは」という心配が(基本的には)要らないのは、この遅延コピーのおかげなんです。

④ 「Too many open files」の正体は、番号札の枯渇です

Linuxでは、ファイルもソケットもパイプも、ぜんぶ「ファイルディスクリプタ(fd)」という番号札で扱われます。「すべてはファイル」という設計思想です。

そしてこの番号札には、プロセスごとの上限があります(既定は1024のことが多い)。

つまり「Too many open files」は、ファイルの開きすぎとは限りません。閉じ忘れたソケットや接続リークでも起きます。Webサーバーで頻出するのはむしろこちら。

ls /proc/<PID>/fd で、いま掴んでいる番号札が全部見えます。エラー名に騙されず、fdの中身を見るんです。

⑤ kill -9 でも死なないプロセスが、実在します

SIGKILLは最強の必殺技——のはずが、効かない相手がいます。

「D」状態(割り込み不能スリープ)のプロセスです。ディスクやNFSの応答を待つカーネル内の処理中で、その待ちが終わるまで、シグナルが届きません。

NFSサーバーが応答しなくなったとき、lsコマンドすらD状態で固まって殺せない——運用者なら一度は見る光景です。

D状態が大量発生していたら、犯人はプロセスではなくその下のI/O(ストレージやネットワークファイルシステム)。見る場所が一段下がるんです。

⑥ SSHを切ると、ジョブが死ぬ理由

長時間バッチをSSH越しに実行して、接続が切れたらバッチも死んだ——新人期の通過儀礼です。

理由は、端末が切れると、その端末のプロセスたちにSIGHUP(切断通知)が送られるから。既定の反応は「終了」です。対策は用途で選びます。

方法向いている用途
nohupSIGHUPを無視させる最小手段
tmux / screen端末ごと生かしておき、後で再接続したいとき
systemdなどのサービス登録恒久的に動かし続けるジョブ(本筋)

「&を付けたのに死んだ」のは、バックグラウンド化とSIGHUP対策が別の話だからなんです。

⑦ 環境変数は、「起動時のコピー」です

exportしたのに、動いているアプリに反映されない——仕様です。

環境変数は、プロセスが起動する瞬間に、親から子へコピーされるものです。起動後に親のシェルでexportしても、既に動いているプロセスには届きません。逆方向(子が変更して親に反映)は、そもそも不可能です。

「設定を変えたのに効かない」の一定数は、これ。反映には再起動が要る、が原則です。

環境変数は「共有される設定」ではなく「出生時に持たされた荷物」。このモデルで、挙動が全部読めます。

⑧ メモリが尽きると、OSがプロセスを「選んで」殺します

最後は、突然死の裏側です。

Linuxはメモリが本当に枯渇すると、OOM Killerという仕組みが、スコアの高いプロセスを選んで強制終了します。アプリのログには何も残らず、忽然と消える。

「アプリが落ちた形跡がないのに死んでいる」ときは、アプリのログではなくOS側のログ(dmesgやjournal)を見る。「Out of memory: Killed process ...」の1行が答えです。

誰が殺されやすいかはスコアで調整もできます。巻き添えで大事なプロセスが死なない設計まで含めて、メモリ管理なんです。

番外編:手元で確かめられる小ネタ

/proc は、カーネルの窓です
/proc/<PID>/ の下には、そのプロセスのfd、環境変数、メモリマップが「ファイルのふり」をして並んでいます。④⑦の話は、ここを覗けば全部実物が見えます。

killは「殺すコマンド」ではありません
killの正体はシグナル送信コマンドです。kill -USR1 で再読込、kill -STOP で一時停止——殺す以外の用途がたくさんあるんです。

プロセスの家系図を見る

ps -ef --forest

親子関係がツリーで出ます。②の「親は誰か」も、⑥の「どの端末の子か」も、この1枚で見えます。

RJCでも、Linuxと向き合っています

RJCが携わるシステムの本番は、Linuxサーバーの上で長時間動き続ける世界です。①や⑧のような「知っていれば5分、知らなければ半日」の知識は、そのまま障害対応力なんですよね。

こういう仕組みの話を、Techチームで共有しながら開発しています。

よくいただくご質問

Q. まずどれから押さえるべきですか?
A. ①かなと思います。ディスク逼迫は緊急対応になりがちなので、「> で切り詰める」を知っているだけで初動が変わるんですよね。

Q. コマンドを覚えるコツはありますか?
A. コマンドより先に「プロセス・fd・シグナル」の3つのモデルを絵にすることをおすすめします。コマンドは全部、その絵の操作なんです。

Q. 障害時にまず何を見ればいいですか?
A. ps(プロセスの状態)、lsof/fd(何を掴んでいるか)、dmesg(OSが何をしたか)の3点セットです。今日の①④⑤⑧が、ほぼこの3つで切り分けられます。

Q. 未経験からでも、分かるようになりますか?
A. なります。Linuxは仕組みが全部観察可能なので、「見て確かめる」を繰り返した人から順に強くなる世界なんです。

怪現象は、仕様の顔をして現れます

今日の8つに共通していたのは、これでした。

Linuxの「変な挙動」は、ほとんどが設計どおりの動きを、モデルを知らずに見ているだけです。名前と実体、親と子、シグナルと状態。

モデルを持っている人には、同じ画面が「謎」ではなく「手掛かり」に見えるんですよね。

みなさんがサーバーで出会った怪現象、よかったら教えてください。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?