분산 크롤러 운영 중 발생한 logrotate state file lock 충돌 이슈 분석

김동욱·5일 전

Troubleshooting

목록 보기
15/15
post-thumbnail

문제 증상

장애의 시작은 단순했다.

크롤러 서버(1~5번) 중 4번 서버에서 logrotate 설정이 적용되어 있음에도 불구하고, 특정 커뮤니티의 JSON 파일이 19GB까지 비정상적으로 증가하며 디스크 사용량이 급격히 상승하는 문제가 발생했다.
반면 다른 서버의 동일 파일은 대부분 0.7GB ~ 1.8GB 수준이었다.

과거에도 동일한 이슈로 해당 파일을 rm으로 삭제한 적이 있었지만, 일주일 뒤 동일한 문제가 다시 발생했다.

여기서 바로 두 가지를 알 수 있었다.

  1. 파일을 지우는 것만으로는 재발 방지가 되지 않는다.
  2. 단순 파일 크기 문제가 아니라, 생성 구조나 운영 방식에 근본 원인이 있다.

처음 세운 가설

초기에는 아래 네 가지를 의심했다.

  • 특정 서버에만 크롤링이 몰린 것은 아닐까
  • 파일이 append-only 구조로 계속 누적되는 것은 아닐까
  • 파일을 소비하거나 정리하는 로직이 실패한 것은 아닐까
  • logrotate가 정상적으로 동작하지 않은 것은 아닐까

이 가설들을 하나씩 검증하면서 원인을 좁혀갔다.


코드 레벨에서 확인한 내용

가장 먼저 확인한 것은 해당 파일이 코드에서 어떻게 다뤄지는지였다.

  • 해당 JSON 파일은 mode="a" (append 모드)로 열린다.
  • 공통 메서드 write_to_file()file.write(data + "\n") 형태로 계속 append 한다.

즉 이 파일은 구조적으로 누적형 파일이었다.

또한 해당 파일을 소비하거나 정리하는 로직은 보이지 않았다.
이 단계에서 이미 “rotate나 정리 작업이 실패하면 파일은 계속 커질 수밖에 없다”는 점은 분명해졌다.

게다가 이 커뮤니티는 글로벌 대상(119개 국가)으로 수집되고 있었고, 실시간성이 중요해 짧은 주기로 반복 수집되고 있었다.
따라서 데이터 증가 속도 자체도 빠른 상황이었다.


서버별 상태 비교에서 얻은 단서

서버별 파일 상태를 비교해 보니 일정한 패턴이 보였다.

  • 어떤 서버는 current 파일이 큼
  • 어떤 서버는 rotate 파일(-YYYYMMDD, .gz)만 존재
  • 어떤 서버는 current 파일이 0B

즉 “특정 서버만 이상하다”가 아니라
rotate가 어떤 날은 되고, 어떤 날은 안 되는 상태였다.

이 관찰은 매우 중요했다.

  • 코드 문제였다면 모든 서버에서 비슷하게 커졌어야 한다.
  • 하지만 실제로는 서버마다 상태가 달랐다.

👉 따라서 문제는 애플리케이션 코드가 아니라 운영 계층의 실행 불안정성으로 방향이 이동했다.


logrotate 설정 확인

/etc/logrotate.d/ 설정은 모든 서버에서 동일했고, 내용은 다음과 같았다.

daily
rotate 10
compress
delaycompress
copytruncate

설정 자체는 특별히 문제가 없어 보였다.
즉 “특정 서버 설정 오류” 가설은 여기서 배제되었다.

이제 확인해야 할 것은 설정이 아니라 실제 실행 결과였다.


결정적 단서

systemctl status logrotate.service를 확인했을 때 다음 로그가 발견되었다.

error: state file /var/lib/logrotate/logrotate.status is already locked
logrotate does not support parallel execution on the same set of logfiles.

이 메시지는 매우 중요했다.

👉 자정에 실행되어야 할 메인 logrotate아예 실패하고 있었다.

그리고 실패 원인은 state file lock 충돌이었다.


누가 logrotate를 동시에 실행하고 있었나

이후 조사 방향은 “누가 동시에 logrotate를 실행하고 있는가”로 바뀌었다.

systemd 외에도 cron을 확인했고, /etc/cron에서 다음 설정을 발견했다.

0 */2 * * * root /usr/sbin/logrotate -f /etc/logrotate.d/send_json_to_s3

즉 2시간마다 cron에서 logrotate -f가 강제 실행되고 있었다.

문제는 이 작업이 메인 logrotate와 같은 시간대(자정)에 겹칠 수 있다는 점이었다.


문제의 최종 원인

핵심은 logrotatestate file이다.

기본적으로 logrotate는 아래 파일을 사용한다.

/var/lib/logrotate/logrotate.status

이 파일은 단순 이력 파일이 아니라:

  • 마지막 rotate 시점 기록
  • 동시 실행 방지 lock

두 가지 역할을 동시에 수행한다.

👉 중요한 점
rotate 대상 파일이 달라도, 같은 state file을 사용하면 동시에 실행할 수 없다.


실제 문제 상황

  • cron: logrotate -f 실행 (state file lock 획득)
  • systemd: daily logrotate 실행 시도
  • 결과: already locked → 실행 실패

즉 메인 rotate 작업이 통째로 스킵되는 구조였다.

이 상태가 반복되면:

  1. append-only 파일은 계속 커짐
  2. rotate가 수행되지 않음
  3. 결국 수십 GB까지 파일이 증가

또한 이후 rotate가 수행되는 시점에는:

  • copytruncate (복사 후 원본 truncate)
  • delaycompress (다음 주기에 압축)

과정이 겹치면서 디스크 I/O와 파일시스템 부담도 증가할 수 있다.


왜 서버마다 상태가 달랐는가

모든 서버가 동일한 설정을 사용했음에도 결과가 달랐던 이유는 다음과 같다.

  • cron 실행 타이밍과 충돌 여부
  • 서버별 수집량 차이
  • 중간에 수동으로 파일 삭제 여부
  • rotate 성공/실패 시점 차이

즉 동일한 문제라도 비대칭적으로 나타날 수 있는 구조였다.


해결 방법

이번 문제는 다음 두 가지 방법으로 해결할 수 있다.

1. 실행 시간 분리

cron과 systemd의 실행 시간이 겹치지 않도록 조정

2. state file 분리 (권장)

5 */2 * * * root /usr/sbin/logrotate -s /var/lib/logrotate/send_json_to_s3.status -f /etc/logrotate.d/send_json_to_s3
  • -s 옵션으로 별도 state file 사용
  • lock 충돌 완전 방지

이번 이슈에서 배운 점

이번 사례를 통해 확인한 것은 다음과 같다.

  • 파일이 비정상적으로 커졌다고 해서 곧바로 애플리케이션 로직만 의심하면 안 된다.
  • 동일한 도구라도 실행 주체(systemd, cron)가 여러 개라면 충돌 가능성을 반드시 고려해야 한다.
  • logrotate는 파일 단위가 아니라 state file 단위로 동시 실행을 제어한다.
  • 특히 동일한 도구라도 실행 경로(systemd, cron)가 둘 이상이면 예상하지 못한 충돌이 발생할 수 있다는 점을 확인했다.

또한 단순히 rm으로 파일을 삭제하는 것은 근본 해결이 아니며, 왜 rotate가 실패했는지를 반드시 확인해야 재발을 막을 수 있다.

profile
안녕하세요! 질문과 피드백은 언제든지 환영입니다:)

0개의 댓글