LabHub

스토리지와 마운트 · 디스크 사용량 추적 · 이론

df 와 du 는 왜 다른 답을 하나

LabHub 에서 이어서 보기

한 줄 요약

df파일시스템에게 묻고 du디렉터리를 걸어다니며 센다. 그래서 이름이 없는 파일은 df 에는 잡히고 du 에는 안 잡힌다.

왜 이게 필요했나

로그가 디스크를 다 먹어서 큰 파일을 rm 으로 지웠는데 df 의 여유 공간이 1바이트도 늘지 않는다. 다들 한 번씩 겪고 한 번씩 당황한다.

여기서 "rm 이 안 먹혔다" 고 결론 내리면 그날 밤이 길어진다. 실제로 일어난 일은 이렇다. rm 은 파일을 지우는 명령이 아니라 디렉터리에서 이름을 하나 떼어내는(unlink) 명령이다. 데이터 블록이 반환되려면 두 조건이 동시에 성립해야 한다.

1. 그 실체를 가리키는 이름이 하나도 남아 있지 않고
2. 그 실체를 열어 둔 프로세스도 하나도 없을 때

로그를 쓰던 애플리케이션이 아직 그 파일을 열고 있으면 두 번째 조건이 깨진다. 이름은 사라졌지만 데이터는 살아 있고, du 는 경로를 걸어다니며 세기 때문에 이름 없는 그 파일을 영원히 찾지 못한다. df 와 du 가 어긋나는 순간이 바로 이 상황의 신호다.

어떻게 동작하나

용량 문제를 좁히는 순서는 이렇다.

df -h                                    # 블록 사용량df -i                                    # inode 사용량 (이게 100% 일 수도 있다)du -x -h --max-depth=1 / | sort -h       # 어느 디렉터리가 큰가 (-x: 다른 fs 로 안 넘어감)lsof +L1                                 # 삭제됐지만 열려 있는 파일ls -l /proc/<PID>/fd | grep deletedfind / -xdev -size +500M -printf '%s %p\n' | sort -rn | head

각 도구가 답하는 질문이 다르다.

| 도구 | 질문 | 놓치는 것 |
| --- | --- | --- |
| df | 파일시스템에 얼마나 남았나 | 어디가 먹었는지 |
| df -i | inode 는 얼마나 남았나 | 블록 사용량 |
| du | 이 경로 아래가 얼마나 크나 | 이름 없는 파일, 다른 파일시스템 |
| lsof +L1 | 지워졌는데 열려 있는 파일이 있나 | 이미 닫힌 것 |

du 에는 함정이 두 개 더 있다.

삭제된 열린 파일 복구

프로세스가 아직 열고 있다면 /proc/PID/fd 아래에 그 파일로 가는 심링크가 살아 있다.

ls -l /proc/1234/fd | grep deletedcp /proc/1234/fd/7 /backup/recovered.log

여기서 순서가 가장 중요하다. 프로세스를 재기동하는 순간 마지막 참조가 사라지고 블록이 반환되어 복구 기회가 완전히 없어진다. 용량이 급한 상황에서도 첫 행동은 재기동이 아니라 복사여야 한다.

공간만 급하게 회수해야 한다면 > /proc/1234/fd/7 로 파일을 비울 수 있다. 로그 파일이라면 이 방법이 프로세스를 살린 채 공간을 돌려준다.

현장에서 만나는 모습

inode 고갈. 세션 파일이나 메일 큐가 작은 파일 수백만 개를 만들면 블록은 남아도 inode 가 먼저 떨어진다. df -i 를 안 보면 원인을 못 찾는다. 그리고 ext4 는 포맷 후 inode 를 늘릴 수 없으므로, 근본 해결은 재포맷이거나 그 워크로드를 다른 파일시스템(XFS 는 동적 할당)으로 옮기는 것이다.

du 가 오래 걸려 장애 대응이 늦어진다. 파일이 수백만 개면 du 는 몇 분씩 걸린다. 급할 때는 du --max-depth=1 로 위에서부터 좁혀 들어가는 편이 빠르다.

다음 실습에서 할 것

작은 파일을 대량 생성해 inode 소비를 관찰하고, 희소 파일의 두 가지 크기를 비교하고, 삭제됐지만 열려 있는 파일을 직접 만들어 df 와 du 의 불일치를 재현한다.