Published on

리눅스 디스크 100%인데 삭제해도 용량이 안 줄 때(lsof)

Authors

서버에서 df -h는 100%를 가리키는데, 분명히 대용량 로그/덤프 파일을 rm로 삭제했음에도 사용량이 줄지 않는 상황은 운영에서 자주 만납니다. 이때 많은 경우 “파일은 삭제됐지만 프로세스가 아직 그 파일을 열고 있어서(파일 디스크립터 유지) 디스크 블록이 해제되지 않는” 전형적인 리눅스 동작을 밟고 있습니다.

이 글에서는 왜 이런 현상이 생기는지, lsof로 정확히 어떤 프로세스가 공간을 잡고 있는지 찾는 방법, 그리고 서비스 영향도를 최소화하면서 공간을 회수하는 방법을 단계별로 정리합니다.

> 관련 글: 같은 주제의 확장 버전은 리눅스 디스크 100% - 삭제해도 용량 안 줄 때에서도 확인할 수 있습니다.

증상: rm 했는데 df가 안 줄어드는 이유

리눅스/유닉스 파일 시스템에서 파일 삭제는 “디렉터리 엔트리 제거(링크 카운트 감소)”입니다. 하지만 어떤 프로세스가 해당 파일을 열어둔 상태라면(inode에 대한 참조가 남아 있음) 실제 데이터 블록은 즉시 해제되지 않습니다.

즉,

  • ls에서는 파일이 사라짐
  • 그런데 프로세스는 여전히 그 파일에 쓰거나 읽고 있음
  • 파일은 (deleted) 상태로 열린 채 유지
  • df는 블록이 여전히 사용 중이라 100%가 유지

이때 du로 디렉터리를 훑어도 안 잡히는 경우가 많습니다. du는 “디렉터리 트리에서 접근 가능한 파일”만 합산하기 때문에, 이미 이름이 사라진 (deleted) 파일은 보이지 않습니다.

1단계: dfdu가 왜 다르게 보이는지 빠르게 확인

먼저 파일 시스템 단위 사용량과 디렉터리 합계를 비교해 차이를 확인합니다.

# 파일시스템 사용량
sudo df -hT

# 특정 마운트(/) 아래에서 큰 디렉터리 찾기
sudo du -xhd1 / | sort -h
  • df는 높게 나오는데 du로는 큰 파일이 안 보이면, 숨은 사용량(대표적으로 deleted-but-open 파일, 또는 다른 마운트/오버레이, reserved blocks 등)을 의심합니다.

2단계(핵심): lsof로 (deleted) 열린 파일 찾기

삭제된 파일을 잡고 있는 프로세스를 찾는 가장 확실한 도구가 lsof입니다.

옵션 A: (deleted)만 필터링

sudo lsof +L1
  • +L1은 링크 수가 1 미만(즉 0)인 파일, 흔히 “삭제되었지만 열린 파일”을 보여줍니다.

출력 예시는 대략 이런 형태입니다.

COMMAND   PID USER   FD   TYPE DEVICE  SIZE/OFF    NODE NAME
java     1324 app   123w  REG  253,0  2147483648 123456 /var/log/app/app.log (deleted)
nginx     901 root   10w  REG  253,0   536870912 123999 /var/log/nginx/access.log.1 (deleted)

여기서 봐야 할 포인트:

  • PID: 어떤 프로세스가 잡고 있는지
  • FD: 123w처럼 쓰기(w)로 열려 있으면 계속 용량이 늘 수 있음
  • SIZE/OFF: 현재 점유 중인 크기(대략적인 회수 가능 용량)
  • NAME 끝의 (deleted)

옵션 B: 특정 마운트/경로에 한정해서 찾기

디스크가 꽉 찬 파티션이 /var라면 해당 경로에 한정하면 훨씬 빠릅니다.

sudo lsof +L1 /var

옵션 C: grep으로 빠르게 보기

sudo lsof | grep '(deleted)'

다만 이 방식은 불필요한 출력이 많을 수 있어 +L1을 권장합니다.

3단계: 어떤 프로세스를 어떻게 조치할지 결정

lsof +L1 결과에서 “용량을 크게 잡고 있는” 프로세스를 기준으로 조치합니다. 조치 방법은 크게 3가지입니다.

방법 1) 가장 안전: 서비스 재시작(프로세스가 FD를 닫게 하기)

대부분의 경우 프로세스를 재시작하면 열린 파일 디스크립터가 닫히며 즉시 공간이 회수됩니다.

# systemd 서비스라면
sudo systemctl restart nginx
sudo systemctl restart your-app.service

# 상태 확인
sudo systemctl status nginx --no-pager

재시작이 반복적으로 실패하는 상황이라면(디스크 100%로 인해 로그/임시파일 쓰기 실패 등) 먼저 원인을 빠르게 진단해야 합니다. 이 경우는 systemd 서비스 재시작 루프 10분 진단 가이드가 도움이 됩니다.

방법 2) 다운타임 없이: 해당 FD를 직접 truncate(주의 필요)

서비스를 내릴 수 없고, “삭제된 파일을 계속 쓰고 있는” 상황이라면 해당 파일 디스크립터를 직접 0으로 줄여 공간을 회수할 수 있습니다.

lsof 출력에서 PID와 FD 번호를 확인한 뒤 /proc/<pid>/fd/<fd>를 대상으로 truncate 합니다.

# 예: PID=1324, FD=123 (lsof에서 123w로 보였다고 가정)
sudo truncate -s 0 /proc/1324/fd/123

또는 셸 리다이렉션을 사용할 수도 있습니다.

sudo sh -c ': > /proc/1324/fd/123'

주의사항:

  • 이 방법은 “프로세스가 현재 쓰고 있는 스트림”을 강제로 비우는 것이므로, 애플리케이션/로그 로테이션 정책에 따라 예상치 못한 동작이 있을 수 있습니다.
  • 특히 데이터 파일(로그가 아닌 DB 파일 등)에 하면 장애로 이어질 수 있으니, 대상이 로그/임시파일인지 반드시 확인하세요.

방법 3) 로그 로테이션/재오픈 시그널로 해결(서버 소프트웨어별)

일부 데몬은 재시작 없이 로그 파일을 다시 열도록 시그널을 받을 수 있습니다.

예를 들어 nginx는 보통 USR1로 로그를 reopen 합니다(배포판/설정에 따라 다를 수 있으니 문서 확인 권장).

# nginx 마스터 PID를 찾아서
pid=$(cat /run/nginx.pid)
sudo kill -USR1 "$pid"

이 방식은 “삭제된 파일을 계속 쓰는” 문제를 완화하고, 새 로그 파일로 쓰기를 전환하게 합니다.

4단계: 공간이 실제로 회수됐는지 검증

조치 후 아래를 확인합니다.

sudo df -h
sudo lsof +L1 | head
  • df 사용량이 내려가야 정상입니다.
  • lsof +L1에서 대용량 (deleted) 항목이 사라졌는지도 확인합니다.

실전 팁: 용량 폭증의 흔한 원인 패턴

운영에서 자주 보이는 패턴을 몇 가지 정리합니다.

1) 애플리케이션 로그가 폭증 + logrotate 미동작

  • 로그 파일을 삭제(rm)해버리면, 프로세스는 기존 FD로 계속 쓰고 디스크는 안 줄어듭니다.
  • 정석은 logrotate로 rotate + (필요 시) 서비스에 reopen 시그널/재시작을 수행하는 것입니다.

점검:

sudo logrotate -d /etc/logrotate.conf
sudo logrotate -f /etc/logrotate.conf

2) 컨테이너/쿠버네티스 환경에서 노드 디스크가 가득 참

컨테이너 런타임 로그나 애플리케이션 로그가 노드 파일 시스템을 잠식할 수 있습니다. 특히 프로세스가 삭제된 로그 파일을 계속 잡고 있으면 노드에서 df만 100%로 유지됩니다.

  • 노드에서 lsof +L1로 원인 프로세스(컨테이너 프로세스/런타임)를 찾고
  • 필요 시 해당 파드/서비스 재시작으로 FD를 닫게 해야 합니다.

운영 중 파드가 계속 죽고 올라오며 로그가 남지 않는 상황도 섞일 수 있는데, 이때는 K8s CrashLoopBackOff - Readiness·Liveness 5분 진단 같은 체크리스트가 문제를 빠르게 좁히는 데 유용합니다.

3) DB/검색엔진의 대형 임시파일

정렬/머지/컴팩션 과정에서 임시파일이 커질 수 있습니다. 이 경우는 단순 truncate가 위험할 수 있으니, 프로세스 특성을 확인하고 “정상 절차(롤링 재시작, 설정 조정, 임시 디렉터리 분리)”로 접근해야 합니다.

운영 관점 체크리스트(재발 방지)

디스크 100%는 단발로 끝나지 않고 반복되는 경우가 많습니다. 아래를 함께 점검하면 재발 확률이 크게 줄어듭니다.

  1. 로그 정책
    • 로그 디렉터리별 보관 기간/최대 용량 설정
    • logrotatecopytruncate를 쓸지(재시작 어려운 프로세스) vs reopen 시그널을 쓸지 결정
  2. 모니터링
    • 파일 시스템 사용량(df) 경보
    • inode 사용량(df -i) 경보(파일이 너무 많아도 장애)
  3. 장애 시 대응
    • “rm로 지우기”보다 “원인 프로세스 확인(lsof) → 안전한 회수(재시작/FD truncate)” 절차를 런북화

결론

rm로 파일을 지웠는데도 df가 100%에서 내려오지 않는다면, 높은 확률로 “삭제되었지만 열린 파일(= (deleted) 상태)”이 디스크를 붙잡고 있습니다. 이 문제는 감으로 해결하기 어렵고, lsof +L1어떤 PID가 어떤 FD를 잡고 있는지를 확인하면 바로 풀립니다.

정리하면 실전 순서는 다음이 가장 안전합니다.

  1. df -h로 대상 파티션 확인 → 2) lsof +L1로 deleted 파일 확인 → 3) 가능하면 서비스 재시작으로 FD 닫기 → 4) 불가하면 /proc/<pid>/fd/<fd> truncate를 신중히 적용 → 5) df로 회수 확인

이 흐름만 익혀두면 “디스크 100%인데 용량이 안 줄어드는” 난감한 상황을 짧은 시간 안에 복구할 수 있습니다.