홈으로 돌아가기

df du 차이: Linux에서 삭제된 파일 찾기

Linux에서 df와 du 불일치가 발생하는 이유는 열린 프로세스 디스크립터에 의해 유지되는 삭제된 파일 때문입니다. 기사가 inode 메커니즘, lsof +L1을 통한 검색 및 재시작 없이 > /proc/PID/fd/FD로 공간 해제를 설명합니다. logrotate copytruncate 및 모니터링 권장사항.

df 거짓말? 아니요, lsof에서 삭제된 파일 검색
Advertisement 728x90

df와 du 결과가 다른 이유: 리눅스에서 숨겨진 기가바이트 찾기

df -h 명령어는 디스크 사용량이 95%라고 표시하는 반면, du -sh /*는 단지 20%만 합산합니다. 나머지 75%는 du에는 보이지 않지만 디스크 블록을 차지하고 있습니다. 그 이유는 삭제된 파일을 가리키는 프로세스의 열린 파일 디스크립터 때문입니다. df는 파일 시스템 슈퍼블록을 직접 읽고, du는 디렉토리 트리를 순회하며 그 안에 항목이 없는 파일은 무시합니다.

inode는 데이터 블록 목록을 포함한 파일 메타데이터를 저장합니다. rm은 디렉토리 항목(하드 링크)만 제거하며, inode 링크 수는 감소하지만 프로세스가 디스크립터를 보유하고 있다면 블록은 계속 할당된 상태로 남습니다.

다이어그램:

Google AdInline article slot
rm 실행 전:
디렉토리        inode          블록
/var/log/  --> app.log  -->  [block1][block2]
               ^
               nginx 디스크립터 (pid 1234, fd 7)

rm 실행 후:
디렉토리        inode          블록
/var/log/  --> (삭제됨) -->  [block1][block2]
               ^
               nginx 디스크립터

du는 /var/log/의 파일을 볼 수 없지만, df는 점유된 블록을 기록합니다.

문제의 전형적인 사례

로그 로테이션: logrotate가 오래된 파일에 rm을 수행하지만, nginx나 java가 시작 시점의 디스크립터를 보유하고 있습니다. 프로세스는 삭제된 파일에 기록하고, df는 증가된 사용량을 등록하지만 du는 그렇지 않습니다.

다른 시나리오:

Google AdInline article slot
  • 열린 로그를 가진 장기 실행 데몬.
  • 디스크립터 닫힘보다 rm이 먼저 실행되는 정리 스크립트 버그.
  • 내부 프로세스가 호스트 파일을 보유하는 Docker 컨테이너.

문제는 누적됩니다: 디스크가 가득 찰 때까지 기가바이트가 눈에 띄지 않게 사라집니다.

삭제된 파일을 가진 프로세스 찾기

NLINK < 1(파일 시스템에서 삭제되었지만 열려 있음)인 파일에 lsof +L1 사용:

COMMAND  PID  USER  FD  TYPE  DEVICE  SIZE/OFF  NLINK  NODE  NAME
nginx   1234  www   7w  REG   8,1  2147483648  0  12345  /var/log/app.log (deleted)
java    5678  app   3w  REG   8,1   536870912  0  67890  /var/log/service.log (deleted)

주요 필드:

Google AdInline article slot
  • COMMAND/PID: 프로세스와 ID.
  • FD: 디스크립터 (7w — 쓰기, 번호 7).
  • SIZE/OFF: 크기 — 손실된 GB의 원천.
  • NLINK=0: 삭제 확인.
  • NAME (deleted): rm 실행 전 경로.

크기 필터: lsof +L1 | awk '$7 > 104857600 {print}' (100MB 이상 파일).

재시작 없이 공간 확보

프로세스 PID 1234, FD 7의 경우:

$ > /proc/1234/fd/7

/proc는 메모리의 procfs입니다. 이 명령어는 디스크립터를 통해 파일을 제로화하고, 커널은 즉시 블록을 해제합니다. df가 업데이트되며, 프로세스는 fd 7에 계속 기록합니다.

확인: lsof +L1 | grep 1234 — SIZE/OFF=0 또는 비어 있음.

스크립트 자동화:

#!/bin/bash
lsof +L1 | awk '$7 > 104857600 && $9 ~ /deleted/ {print $2, $8}' | while read pid fd; do
  echo "Zeroing $pid/$fd"
  > /proc/$pid/fd/$fd
  echo "Freed"
done

logrotate에서 문제 방지

로테이션에서 rm을 피하세요. /etc/logrotate.d/app에서:

/var/log/app.log {
    daily
    rotate 7
    compress
    copytruncate
}

copytruncate는 로그를 복사한 후 원본을 잘라냅니다(> 메커니즘). 디스크립터는 변경되지 않습니다.

단점: 복사 시 미세 지연 — 일부 줄 손실 가능성.

무손실 대안:

  • logrotate: mv old → new file.
  • kill -HUP <pid> (로그 재개를 위한 SIGHUP).

nginx: nginx -s reopen. systemd: systemctl reload nginx.

모니터링 및 경고

확인 스크립트:

lsof +L1 -F s | awk '/^s/ && substr($0,2)+0 > 104857600 {count++} END {print count+0}'

100MB 이상 삭제된 파일 수 출력.

Prometheus 통합:

  • node_filefd_allocated — 열린 fd 증가.
  • df/disk_used 대 du 합계 비교.

5분마다 cron: 불일치 >10% 시 경고.

핵심 요점

  • df는 슈퍼블록의 할당된 블록을 보여주고, du는 디렉토리에서 보이는 파일을 보여줍니다.
  • lsof +L1는 NLINK=0으로 (삭제된) 파일을 가진 프로세스를 찾습니다.
  • 공간 확보: > /proc/PID/fd/FD — 재시작 없이 제로화.
  • logrotate copytruncate는 HUP 없이 문제를 방지합니다.
  • 모니터링: lsof 또는 node_exporter 메트릭을 사용한 스크립트.

— Editorial Team

Advertisement 728x90

다음 읽기