「Device or Resource Busy」という苛立ち
誰もが一度は経験することです。ドライブをアンマウントしようとしたり、巨大なログを削除しようとしたり、Nginxを再起動しようとしたときに、「Device or resource busy」や「Address already in use」というエラーに遭遇します。Linuxは、ハードドライブからネットワークソケットまで、あらゆるものを「ファイル」として扱うことで有名です。しかし、何かがロックされているとき、OSは必ずしもどのプロセスが犯人であるかを教えてくれません。そこで登場するのが lsof (List Open Files) です。
12個のマイクロサービスが稼働する本番環境の Ubuntu 22.04 サーバーで、私は lsof を使って繰り返し発生していたデプロイのハングアップを解決しました。これにより、推測による20分間のトラブルシューティングが、30秒の正確な作業へと短縮されました。盲目的にプロセスをキルする代わりに、どの Python スクリプトがソケットを掴んだままにしているかを正確に把握できたのです。これは、システム管理者にとって「誰が何をしているか」を知るための究極のツールです。
クイックスタート:5分で学ぶ lsof の基本
今すぐ問題を解決する必要がある場合、これら5つのコマンドが使用頻度の90%を占めるでしょう。他のユーザーが所有するプロセスを表示するには、sudo を使用することを忘れないでください。
1. 特定のポートを使用しているプロセスを見つける
これは、Webサーバーの起動に失敗したときの救世主となります。ポート80が占有されている場合、このコマンドを実行して「不法占拠者」を見つけます。
sudo lsof -i :80
2. 特定のユーザーが開いているファイルをリストアップする
「www-data」ユーザーが現在触れているすべてのファイルを確認するには:
sudo lsof -u www-data
3. 特定のプロセスの動作を確認する
プロセスID (PID) が 1234 であることがわかっていて、そのアクティビティを確認したい場合:
sudo lsof -p 1234
4. 特定のディレクトリを確認する
/mnt/data をアンマウントしようとしていますか?このコマンドは、誰が退出を妨げているかを表示します:
sudo lsof +D /mnt/data
lsof の出力を読み解く
引数なしで lsof を実行すると、情報の壁が押し寄せます。干し草の山から針を見つけるには、各カラムの意味を知る必要があります:
- COMMAND: アプリケーションまたはスクリプトの名前。
- PID: プロセスのユニークなID。
- USER: プロセスの所有者。
- FD: ファイル記述子。
cwd(カレントディレクトリ) やtxt(実行されている実際のコード) に注目してください。 - TYPE:
REGは通常のファイル、DIRはフォルダ、IPv4/IPv6はネットワーク接続です。 - NAME: ファイルへのパス、または関連するIPアドレス。
私が初めて高負荷なデータベースサーバーでこれを確認したとき、何千もの mem エントリが表示されました。パニックにならないでください。これらはメモリにマップされた共有ライブラリにすぎません。単一のアプリがこれらを数十個表示するのは正常な動作です。
高度なトラブルシューティング:ネットワークとディスク容量
基本を学んだら、フォレンジック分析や「ゴースト」ファイルのクリーンアップなど、より複雑なタスクに lsof を活用できます。
ネットワーク接続のフィルタリング
プロトコルでフィルタリングして、特定の種類のトラフィックを見つけることができます。これは、不正な接続の特定や、スタックした同期ジョブのデバッグに役立ちます。
# TCP接続のみをリストアップ
sudo lsof -i tcp
# 特定のリモートサーバーへの接続を検索
sudo lsof -i @192.168.1.50
「ゴースト」ディスク容量の回復
rm で50GBのログファイルを削除したのに、df -h では依然としてディスクがいっぱいだと表示されたことはありませんか?これは、プロセスがまだそのファイルを開いたままにしているために起こります。ファイルは「削除」されていますが、プロセスが解放するまでスペースは解放されません。
これらの隠れた容量占有者を次のコマンドで見つけます:
sudo lsof +L1
+L1 フラグは、リンクカウントがゼロのファイルを見つけます。PIDが見つかったら、そのサービスを再起動して、ようやくディスク容量を取り戻すことができます。
-a を使ったフィルタの組み合わせ
デフォルトでは、lsof は「OR」論理を使用します。ユーザー「john」によって開かれ、かつ特定のポート22を使用しているファイルを見つけたい場合は、-a (AND) フラグを使用する必要があります:
sudo lsof -a -u john -i :22
モダンな管理者のための実践的Tips
1. 結果を高速化する
デフォルトでは、lsof はIPアドレスをホスト名に変換しようとします。これは低速です。混雑したネットワークでは、コマンドが数秒間ハングすることがあります。DNSをスキップするには -n を、ポート名の変換をスキップするには -P を使用します:
sudo lsof -nP -i :443
2. スクリプティングと自動化
CI/CDパイプライン中にポートをブロックしているものを強制終了する必要がある場合は、-t (簡潔) フラグを使用します。これはPIDのみを返すため、他のコマンドへのパイプに最適です。
# ポート3000を使用しているプロセスを強制終了する
sudo kill -9 $(lsof -t -i :3000)
これは慎重に使用してください。強引な手法ですが、スタックしたデプロイを解消する唯一の方法である場合もあります。
3. リアルタイム・モニタリング
-r フラグを使用すると、ファイルやポートをリアルタイムで監視できます。これは、ログファイルの増加を監視したり、特定の接続が確立されるのを待ったりするのに最適です。
# ポート80の新規接続を2秒ごとにチェックする
sudo lsof -i :80 -r 2
まとめ
lsof を学ぶことで、Linuxの管理方法が変わります。再起動して解決を祈る代わりに、競合を引き起こしている正確なプロセスを特定できるようになります。100GBのゴーストログを追い詰める場合でも、開発ポートが乗っ取られた理由を見つける場合でも、lsof は必要な明快さを提供してくれます。これらのコマンドを手元に置いておけば、二度と「Resource busy」エラーに怯えることはないでしょう。

