- Published on
Linux journalctl 로그 폭주로 디스크 100% 찰 때
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서버가 멀쩡히 돌다가 갑자기 디스크 사용률이 100%가 되고, 애플리케이션이 파일을 못 쓰면서 장애가 나는 케이스가 있습니다. 그중 흔한 원인이 systemd-journald 저널 로그 폭주입니다. 특히 에러 루프가 난 서비스가 초당 수천 줄을 뿜거나, 커널/드라이버 로그가 폭발하면 /var/log/journal 아래의 저널 파일이 순식간에 커집니다.
이 글에서는 (1) 지금 당장 디스크를 살리는 응급처치, (2) 어떤 서비스가 로그를 폭주시켰는지 추적, (3) 다시는 같은 일이 안 나게 journald 보존 정책을 튜닝하는 흐름으로 정리합니다.
장애 상황에서 로그 폭주는 종종 메모리/프로세스 문제와 같이 옵저버빌리티 신호로 동반됩니다. OOM으로 재시작 루프가 돌며 로그가 폭발하는 패턴도 많으니, 필요하면 리눅스 OOM Killer로 프로세스 죽음 진단·방지도 함께 보세요.
1) 증상 확인: 정말 journald가 디스크를 먹고 있나
먼저 디스크가 어느 마운트에서 찼는지 확인합니다.
df -h
대부분 루트(/)나 /var가 꽉 차며, 저널은 보통 아래 위치 중 하나에 있습니다.
- 영구 저장(기본):
/var/log/journal - 휘발 저장:
/run/log/journal
저널 자체 크기는 journalctl로 빠르게 확인 가능합니다.
sudo journalctl --disk-usage
또는 디렉터리 단위로 상위 사용량을 확인합니다.
sudo du -sh /var/log/* | sort -h
sudo du -sh /var/log/journal/* 2>/dev/null | sort -h | tail
여기서 system.journal 또는 해시처럼 생긴 디렉터리(머신 ID) 아래 파일이 크면 journald가 범인일 확률이 큽니다.
2) 응급처치: 디스크 공간을 즉시 확보하는 방법
장애 대응에서는 “원인 규명”보다 “서비스 복구”가 먼저인 경우가 많습니다. 아래 순서대로 진행하면 안전합니다.
2-1) journald에 보존 축소(즉시 적용)
가장 먼저, 저널을 일정 기간/크기만 남기고 잘라냅니다.
- 기간 기준 삭제:
sudo journalctl --vacuum-time=2d
- 크기 기준 삭제:
sudo journalctl --vacuum-size=500M
- 파일 개수 기준 삭제:
sudo journalctl --vacuum-files=10
이 명령은 저널 파일을 “정상적인 방식으로” 정리하므로, 급한 상황에서 우선 선택하기 좋습니다.
2-2) 로그 폭주가 현재 진행 중이면, 원인 서비스부터 멈추기
계속 쓰고 있으면 vacuum이 따라잡지 못합니다. 의심 서비스가 있다면 일단 중지하고 공간을 확보하세요.
sudo systemctl stop your-service
sudo systemctl status your-service --no-pager
원인 서비스가 아직 불명확하면, 다음 섹션의 “폭주 유닛 찾기”를 먼저 수행한 뒤 멈추는 게 좋습니다.
2-3) 최후의 수단: 저널 디렉터리 정리(주의)
정말 급해서 vacuum이 안 먹히거나, 저널 파일이 깨져서 정리가 안 되는 경우가 있습니다. 이때는 journald를 멈추고 파일을 정리합니다.
sudo systemctl stop systemd-journald
sudo rm -f /var/log/journal/*/*.journal /var/log/journal/*/*.journal~ 2>/dev/null
sudo systemctl start systemd-journald
주의 사항:
- 운영 중인 장애 분석에 필요한 로그까지 삭제될 수 있습니다.
- 가능하면 먼저
journalctl --disk-usage와journalctl -S로 필요한 구간을 다른 곳으로 덤프해두세요.
예: 최근 1시간을 파일로 저장
sudo journalctl -S "1 hour ago" -o short-iso > /tmp/journal-last-1h.log
3) 원인 추적: 어떤 유닛/프로세스가 로그를 폭주시켰나
디스크를 비웠다면, 다음 장애를 막기 위해 “누가 로그를 쏟았는지”를 찾아야 합니다.
3-1) 최근 로그에서 특정 유닛이 반복되는지 확인
가장 단순한 방법은 최근 구간을 보고 같은 메시지가 반복되는지 확인하는 것입니다.
sudo journalctl -S "30 min ago" -o short-iso | tail -n 200
특정 유닛 로그만 보려면:
sudo journalctl -u your-service -S "2 hours ago" -o short-iso
부팅 단위로도 확인 가능합니다.
sudo journalctl -b -0 -S "1 hour ago" -o short-iso
3-2) “가장 많이 말한 유닛”을 통계로 찾기
저널에서 유닛 필드를 뽑아 카운트하면 폭주 유닛이 바로 드러나는 경우가 많습니다.
sudo journalctl -S "1 hour ago" -o json | \
jq -r '._SYSTEMD_UNIT // "(no-unit)"' | \
sort | uniq -c | sort -nr | head
jq가 없으면 설치하거나, 임시로 짧은 구간을 grep/awk로 처리할 수도 있지만 JSON 파싱이 가장 정확합니다.
3-3) 커널 로그 폭주 여부 확인
드라이버/네트워크/파일시스템 오류가 반복되면 커널 로그가 폭발합니다.
sudo journalctl -k -S "1 hour ago" -o short-iso | tail -n 200
여기서 같은 에러가 반복된다면, journald 튜닝만으로는 근본 해결이 안 됩니다. 장치/커널 파라미터/드라이버/네트워크 문제를 같이 봐야 합니다.
3-4) 재시작 루프(크래시 루프) 확인
서비스가 죽고 systemd가 계속 재시작하면, 시작/종료 로그가 폭발합니다.
sudo systemctl status your-service --no-pager
sudo systemctl show your-service -p NRestarts
재시작 루프의 원인이 메모리 부족(OOM)인 경우도 흔합니다. 이 경우 journald만 줄여도 재발하므로, OOM 원인을 함께 잡아야 합니다.
4) 재발 방지: journald 보존 정책을 “의도적으로” 제한하기
응급처치로 --vacuum-*를 해도, 설정이 그대로면 또 찹니다. journald 설정 파일에서 상한을 걸어야 합니다.
설정 파일은 보통 다음 중 하나입니다.
/etc/systemd/journald.conf/etc/systemd/journald.conf.d/*.conf
권장 방식은 드롭인 파일을 추가하는 것입니다.
sudo mkdir -p /etc/systemd/journald.conf.d
sudo tee /etc/systemd/journald.conf.d/99-limit-journal.conf > /dev/null <<'EOF'
[Journal]
SystemMaxUse=1G
SystemKeepFree=2G
RuntimeMaxUse=200M
MaxRetentionSec=7day
Compress=yes
EOF
설정 의미(핵심만):
SystemMaxUse:/var/log/journal전체 상한SystemKeepFree: 파일시스템에 이만큼 여유를 남기도록 유도(디스크 100% 방지에 유용)RuntimeMaxUse:/run/log/journal상한MaxRetentionSec: 시간 기준 보존Compress: 압축 저장(대개 켜는 편이 이득)
적용:
sudo systemctl restart systemd-journald
sudo journalctl --disk-usage
4-1) 영구 저장이 꼭 필요 없으면 Storage를 volatile로
장애 분석 정책상 저널을 장기 보관할 필요가 없고, 별도 로그 수집(예: Fluent Bit, Vector, CloudWatch, ELK 등)을 쓴다면 휘발로 돌리는 것도 방법입니다.
sudo tee /etc/systemd/journald.conf.d/10-storage.conf > /dev/null <<'EOF'
[Journal]
Storage=volatile
EOF
sudo systemctl restart systemd-journald
이러면 재부팅 시 저널이 사라지므로, 운영 정책과 맞는지 반드시 확인해야 합니다.
4-2) rate limit(속도 제한) 이해하기
journald에는 기본적으로 rate limit이 있습니다. 다만 “디스크가 차는 문제”는 rate limit만으로 완전히 막기 어렵습니다.
- 로그가 다양한 유닛에서 분산되면 제한이 잘 안 느껴질 수 있음
- rate limit으로 드롭된 로그가 생기면, 장애 원인 분석이 더 어려워질 수 있음
그래서 실무에서는 (1) 상한 설정(SystemMaxUse/KeepFree) 을 기본으로 하고, (2) 폭주 서비스 자체를 수정하는 접근이 가장 안정적입니다.
5) 폭주 로그를 만드는 애플리케이션/서비스 측 개선 포인트
디스크를 살리고 journald 상한을 걸었어도, 근본 원인이 남아 있으면 다음 장애로 이어집니다.
5-1) 동일 에러 무한 반복(타이트 루프) 제거
대표 패턴:
- 외부 의존성 실패(예: DB 다운, API 타임아웃) 시 즉시 재시도
- 예외 스택트레이스를 매번 출력
- 설정 오류로 매 요청마다 경고 로그 출력
해결:
- 지수 백오프와 지터 적용
- 동일 메시지 샘플링/집계
- “요청 단위 에러 로그”와 “상태 변화 로그”를 분리
예를 들어 네트워크 오류 재시도 패턴은 로그 폭주로 직결됩니다. Node.js 환경에서 연결 리셋/타임아웃이 반복될 때의 원인 접근은 Node.js fetch ECONNRESET·ETIMEDOUT 해결법도 참고할 만합니다.
5-2) systemd 서비스 설정에서 재시작 정책 점검
Restart=always가 무조건 나쁜 건 아니지만, 크래시 루프에서는 로그 폭주+자원 고갈을 같이 부릅니다.
점검 포인트:
Restart=on-failure로 충분한가RestartSec=5s등 재시작 간격을 늘릴 수 있는가StartLimitIntervalSec와StartLimitBurst로 재시작 폭주를 차단할 수 있는가
드롭인 예시:
sudo systemctl edit your-service
아래 내용 추가:
[Service]
Restart=on-failure
RestartSec=5s
[Unit]
StartLimitIntervalSec=300
StartLimitBurst=5
적용:
sudo systemctl daemon-reload
sudo systemctl restart your-service
6) 운영 체크리스트: 다음엔 “장애 전”에 감지하기
journalctl --disk-usage를 주기적으로 수집(노드 단위 메트릭)/var또는/파일시스템 사용률 알람(예: 80%, 90%)- 특정 유닛의 로그량 급증 탐지(로그 파이프라인에서 카운트)
- 크래시 루프 탐지:
NRestarts증가 알람
디스크가 꽉 차면 DB, 컨테이너 런타임, 패키지 업데이트 등 연쇄적으로 문제가 커집니다. 특히 컨테이너 노드에서는 이미지 레이어/로그/저널이 동시에 자라며 더 빨리 장애가 납니다.
7) 정리: 가장 안전한 해결 순서
df -h로 꽉 찬 마운트 확인journalctl --disk-usage로 저널 크기 확인- 폭주가 진행 중이면 원인 유닛을 찾아
systemctl stop journalctl --vacuum-size또는--vacuum-time으로 공간 확보/etc/systemd/journald.conf.d/*.conf로SystemMaxUse,SystemKeepFree,MaxRetentionSec설정- 폭주를 만든 애플리케이션/서비스의 재시도/로그 정책 및 systemd 재시작 정책 개선
이 순서대로 하면 “당장 디스크를 살리면서”도 “재발 방지”까지 같이 가져갈 수 있습니다.