du と df の違い - ディスク容量を正しく測る

du と df の違い - ディスク容量を正しく測る

この記事で解決できること

  • dudf役割の違い が説明できる
  • df は満タンなのに du で計算しても合わない」現象の 原因 が分かる
  • 「削除したのに容量が戻らない」事件を 自力で解決 できる
  • ディスクが足りなくなった時の 調査の型 が身につく

対象読者:Linux 入門者、dudf を「なんとなく」で使っている方

導入:リナのディスクパンク事件

リナ: ライニー先輩、大変です! サーバーのディスクが急に満タンになって、du で大きいファイルを探したんですけど、合計しても全然容量が足りないんです。なんで?
ライニー先輩: お、典型的な「dudf のズレ」だね。これ、ちゃんと理解してない人めっちゃ多いよ。
リナ: えっ、dudf って似たコマンドじゃないんですか?
ライニー先輩: そう見えるよね。でも実は 見ているものが全然違う んだ。今日はその違いと、ズレが起きる理由を一緒に見ていこう。

結論を先に

  • df = ファイルシステム単位 の空き容量(マウントポイントごと)
  • du = ディレクトリ・ファイル単位 の使用量(指定パス以下を集計)
  • 一致しないのは 削除済み開きファイル / マウント境界 / root 予約ブロック が主因

df - ファイルシステム単位で空きを見る

ライニー先輩: まずは df。「disk free」の略で、ファイルシステム(パーティションやマウントポイント)単位で「全体・使用済み・空き」を表示するよ。
リナ: ファイルシステム単位...?
ライニー先輩: 簡単に言うと「マウントされてる場所」ごとだね。/(ルート)、/home、USB メモリの /mnt/usb みたいに、別々にカウントされる。

実際に試してみよう

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        50G   42G  5.5G  89% /
tmpfs           1.9G     0  1.9G   0% /dev/shm
/dev/sda2       100G   60G   40G  61% /home

読み方

  • Filesystem:デバイス名(/dev/sda1 など)
  • Size:全体容量
  • Used:使用済み
  • Avail:空き
  • Use%:使用率(90% を超えたら警戒
  • Mounted on:マウントポイント
リナ: -h ってなんですか?
ライニー先輩: --human-readable の略。50G とか 5.5G みたいに 人間が読みやすい単位 で表示してくれる。-h 付けない素の df は KB 表示なので、桁数えで疲れるよ。
リナ: たしかに 52428800 とか出てきても分かんないですよね...

よく使うオプション

$ df -h          # 人間が読みやすい単位(G, M, K)
$ df -T          # ファイルシステムの種類も表示(ext4, xfs など)
$ df -i          # 使用量ではなく inode 数を表示
$ df -h /var     # 特定パスが属するファイルシステムだけ

df -i を忘れない

ディスク容量に余裕があるのに「No space left」エラーが出る場合、inode の枯渇 が原因のことがある(大量の小さいファイルが原因)。 df -hdf -i両方確認する習慣 をつけよう。

du - ディレクトリ単位で使用量を測る

ライニー先輩: 次は du。「disk usage」の略で、指定したディレクトリ以下のファイルを 実際に走査して 使用量を計算するよ。
リナ: 走査するって、ファイルを 1 個ずつ見るってことですか?
ライニー先輩: そう。だから大きいディレクトリで du を実行すると 時間がかかる ことがある。df が一瞬で返ってくるのと対照的だね。

実際に試してみよう

$ du -sh /var/log
1.2G    /var/log

よく使うオプションの組み合わせ

  • -s(summary):合計だけ表示
  • -h(human-readable):人間が読める単位
  • --max-depth=N:N 階層まで表示

-sh はワンセットで覚えると便利。

階層別に大きいディレクトリを探す

$ du -h --max-depth=1 /var
4.0K    /var/games
1.2G    /var/log
512M    /var/cache
24M     /var/lib
1.7G    /var
リナ: これすごく便利ですね!
ライニー先輩: でしょ? さらに 大きい順にソート するとボス級ディレクトリが一目で見えるよ。

サイズ順に並べる

$ du -sh /var/* 2>/dev/null | sort -h
4.0K    /var/games
4.0K    /var/opt
24M     /var/lib
512M    /var/cache
1.2G    /var/log

ポイント

  • 2>/dev/null:権限不足で読めないディレクトリのエラーメッセージを捨てる
  • sort -hhuman-readable な単位を正しくソート1.2G512M より大きいと判定)

sort -n(数値ソート)だと 1.2G1.2 だけ見て小さい扱いになるので注意。

du と df の決定的な違い

リナ: なんとなく分かってきましたけど、結局何が違うんですか?
ライニー先輩: 一言で言うと 見方の階層が違う。図にすると分かりやすいよ。

比較表

項目 df du
単位 ファイルシステム ディレクトリ・ファイル
取得方法 スーパーブロックから取得 実際にファイルを走査
速度 一瞬 大きいパスでは遅い
削除済み開きファイル 含まれる 含まれない
別マウント 別物として集計 跨いで集計(-x で抑制可)
root 予約ブロック 影響あり 影響なし
リナ: なるほど...だから「df で 90% なのに du だと 60% しか使ってない」みたいなことが起こるんですね?
ライニー先輩: その通り! よくある原因 3 つを次から詳しく見ていこう。

ズレの主犯:削除済み開きファイル事件

ライニー先輩: dfdu がズレる 一番多い原因 がこれ。「削除したのに、まだ誰かが開いているファイル」だよ。
リナ: 削除したのに開いてる...? どういうことですか?
ライニー先輩: Linux は rm でファイルを消しても、そのファイルを開いているプロセスがいる間は実体が残る んだ。たとえば、起動中の Web サーバーがログファイルを開いたまま、誰かが rm /var/log/access.log したケース。
リナ: わ、ログファイルが消えたように見えて、実は容量を食い続けてるってことですか?
ライニー先輩: 正解。duファイル名で辿れないから検出できない。でも dfファイルシステム的にはまだ確保されてる から使用済みとしてカウントする。これがズレの正体。

削除済み開きファイルを見つける

$ sudo lsof | grep deleted
nginx     1234  root  5w  REG  8,1  524288000  ... /var/log/nginx/access.log (deleted)
mysqld    5678  mysql 7w  REG  8,1  104857600  ... /tmp/ibdata.tmp (deleted)

読み方

  • 列 1:プロセス名(nginx, mysqld
  • 列 2:PID(プロセス ID)
  • 列 7:サイズ(バイト単位)
  • 末尾の (deleted):削除済みなのに開かれている印

解放するには

# 該当プロセスを再起動 or リロード
$ sudo systemctl restart nginx
$ sudo systemctl reload mysql

# プロセスが特定できれば、再起動なしで切り離す方法もある(上級者向け)
# /proc/<PID>/fd/<N> を /dev/null にリダイレクトする手法など

再起動の前に必ず影響範囲を確認

本番サーバーで systemctl restart する前に、サービスダウンが許される時間帯か、依存サービスはあるかをチェック。詳しくは ディスクがいっぱい を参照。

ズレの第二犯:マウント境界

リナ: あと 2 つって何ですか?
ライニー先輩: 1 つはマウント境界。たとえば /home が別パーティションになってる時、du -sh / するとどうなると思う?
リナ: えーっと.../home も含めて全部足される?
ライニー先輩: そう、デフォルトでは マウントポイントを跨いで集計する。一方 df は別ファイルシステムなので別物としてカウント。だから du -sh / の数字が df/ の使用量より 大きく出る ことがある。
# マウント境界を跨がない(その FS だけ集計)
$ sudo du -sh -x /

-x--one-file-system

これを付けると du指定パスと同じファイルシステムだけ を集計する。df との比較がしやすくなる。

ズレの第三犯:root 予約ブロック

ライニー先輩: 最後は地味だけど大事。ext4 などのファイルシステムは root 用に 5% の領域を予約 しているんだ。
リナ: なんで予約するんですか?
ライニー先輩: 通常ユーザーが容量を食い尽くしても、root が緊急対応できるようにするため。dfAvail はこの予約分を 差し引いた値 だから、Size - UsedAvail が一致しないように見える。
# 予約ブロックの割合を確認
$ sudo tune2fs -l /dev/sda1 | grep -i reserved
Reserved block count:     655360
Reserved blocks uid:      0 (user root)
Reserved blocks gid:      0 (group root)

予約ブロックを減らすのは慎重に

tune2fs -m 1 /dev/sda1 で 1% に減らせるが、システム領域では予約は 残しておくのが基本。データ専用パーティションのみ削減を検討する。

実務で使う「調査の型」

リナ: 違いは分かりました! じゃあ実際に「ディスクが足りない」って言われた時、どう動けばいいですか?
ライニー先輩: いい質問。手順を型化しておくと事故らないよ。

ディスク調査の型(上から順に)

  1. 全体を俯瞰df -h(どのファイルシステムが満タンか)
  2. inode も確認df -i(小さいファイル大量問題)
  3. 大きいディレクトリを特定sudo du -h --max-depth=1 / 2>/dev/null | sort -h
  4. dfdu がズレてたらsudo lsof | grep deleted
  5. 古いログを削除/var/log 配下の .gz などを確認
  6. 解放されない時:該当サービスを systemctl restart

各ステップのコマンド集

# 1. 全体を俯瞰
df -h

# 2. inode 確認
df -i

# 3. 大きいディレクトリ特定(root から 1 階層ずつ深掘り)
sudo du -h --max-depth=1 / 2>/dev/null | sort -h
sudo du -h --max-depth=1 /var 2>/dev/null | sort -h
sudo du -h --max-depth=1 /var/log 2>/dev/null | sort -h

# 4. 削除済み開きファイル
sudo lsof | grep deleted | sort -k7 -n -r | head

# 5. 大きいファイル単位で探す
sudo find / -type f -size +100M 2>/dev/null

ミニ課題:自分の環境で試してみよう

ライニー先輩: 知識を定着させるために、自分の環境で次の課題をやってみよう。

課題 1:自分の / パーティションの使用率を確認する

課題 2:ホームディレクトリ直下で 最も大きいディレクトリ Top 3 を見つける

課題 3df -hsudo du -sh -x / の数字を比較し、差分が出る理由を 1 行で説明する

課題 1 のヒント
df -h /

Use% 列が / の使用率。90% を超えたら片付けを検討。

課題 2 のヒント
du -h --max-depth=1 ~ 2>/dev/null | sort -h | tail -3

tail -3 で大きい順 Top 3 を抽出。

課題 3 のヒント

差分が出る主な理由:

  • 削除済みだが開いているファイル(df のみカウント)
  • 別マウントポイントの存在(du -x で除外していない場合)
  • ext4 の root 予約ブロック(dfAvail に影響)

よくある落とし穴

やってはいけない 3 つのパターン

  1. du -sh /nohup なしで本番で実行 → SSH 切断で途中停止
  2. df の数字だけ見てファイルを消す → 削除済み開きファイルが原因の時は無意味
  3. rm -rf /tmp/* で全削除 → 起動中のアプリの作業ファイルを壊す

安全な型

  • sudo du -sh /*トップレベルから順に深掘り(一気にルート以下を走らない)
  • 消す前に ls -lhサイズと更新日時を確認
  • 大きいログは消すより truncate -s 0 ファイル名中身だけ空にする(プロセスが開いていてもセーフ)

次に読む