분석 · 관제심화 · 16분 읽기

로그 회전과 수집기: inode·offset·손실 경계

ALPACA 실습의 Snort 파일 수집 구조를 바탕으로 rename과 copytruncate의 차이, 열린 파일과 읽기 위치, 재전송·중복 처리를 설명합니다.

개념부터 찾아보기

정의·역할·동작 원리를 독립 페이지에서 확인하세요. 본문의 밑줄 용어에도 설명이 있습니다.

이 노트에서 설명할 수 있게 되는 것

  1. rename과 copytruncate에서 열린 파일이 어떻게 달라지는지 설명한다.
  2. offset 복구의 한계와 누락·중복 경계를 구분한다.
  3. 원본 파이프라인의 회전 시험 절차를 설계한다.

01개념과 구성 요소

  • 계속 자라는 로그를 보존 정책에 맞게 나누는 작업이며 writer와 reader의 파일 상태가 함께 바뀐다.
  • 경로··열린 파일 디스크립터·읽은 은 서로 다른 값이다.
  • 이름 변경·잘라내기·재시작 사이에서 미수집 꼬리, 중복, 복구 불가능한 손실이 생길 수 있다.

02rename 회전에서 수집 파일을 전환하는 순서

  1. writer와 reader가 기존 를 사용하며 reader는 처리한 을 추적한다.
  2. 기존 로그를 회전 이름으로 옮겨도 이미 열린 FD는 기존 를 계속 가리킬 수 있다.
  3. 새 경로의 파일을 만들고 writer가 지원하는 reopen 절차로 새 에 쓰도록 전환한다.
  4. reader가 기존 의 남은 기록을 끝까지 수집한다. 새 경로만 즉시 따라가면 꼬리 부분을 놓칠 수 있다.
  5. 새 의 을 별도로 추적하고 전달·저장 확인 문맥과 함께 복구 상태를 유지한다.

03수집 파이프라인과 회전 경계

  • 원본 ALPACA 프로젝트에서는 가 alert_fast.txt에 경보를 쓰고 수집기가 새 줄을 읽어 DataBuffer에 보낸 뒤 중앙 으로 전송했다. 로그 파일이 계속 커지므로 logrotate로 크기와 보관 기간을 관리했다.
  • 여기서 회전은 디스크 정리만이 아니라 쓰는 프로그램과 읽는 프로그램이 어느 파일을 보고 있는지를 바꾸는 사건이다.
  • 파일에서 경보 한 줄을 놓친 것과 네트워크 패킷을 캡처하지 못한 것은 서로 다른 손실이다. 경보 파일 회전 문제는 이미 만들어진 경보 기록을 수집하는 단계의 누락이다.
  • 경보 수, 수집기 전송 수, 중앙 적재 수를 나눠야 패킷 처리 성능 문제와 혼동하지 않는다.
  • 원본은 작은 규모의 MVP에서 를 선택하고 크기가 읽기 위치보다 작아지면 처음부터 다시 읽도록 보완했다. 이것은 알려진 손실 구간을 줄이는 선택이며 무손실 수집을 증명하는 방식은 아니다.

04경로·inode·파일 디스크립터·offset의 관계

  • 파일명은 디렉터리에서 파일 객체를 찾는 이름이다. 가 open으로 얻은 파일 디스크립터는 열린 파일을 참조하며, 읽기 위치인 은 어느 바이트까지 읽었는지를 나타낸다.
  • 같은 경로에 새 파일을 만들더라도 이미 열린 디스크립터가 자동으로 새 파일로 이동하지 않는다.
  • 의 파일 신원을 추적할 때는 만이 아니라 장치 번호와 함께 본다. 는 삭제 후 재사용될 수 있고 재시작 뒤 파일이 달라질 수 있으므로 영구적으로 유일한 이벤트 식별자로 삼지 않는다.
  • 수집기는 열린 대상의 fstat과 경로의 stat을 비교하여 이름 교체와 내용 축소를 구분할 수 있다.
  • 줄 기반 수집에서는 마지막 줄의 줄바꿈이 아직 기록되지 않았을 수 있다. 읽은 바이트를 즉시 완성 이벤트로 취급하면 나중에 이어진 내용과 분리된다.
  • 부분 줄 버퍼와 마지막으로 확정한 위치를 함께 관리한다.

05rename 방식: 이전 파일을 끝까지 읽고 새 파일로 전환

  • 일반적인 회전은 현재 파일을 다른 이름으로 바꾸고 원래 경로에 새 파일을 생성한다. 기존 writer의 디스크립터는 이름이 바뀐 옛 파일을 계속 가리킨다.
  • 프로그램이 지원하는 reopen 또는 적절한 신호를 통해 새 파일을 열게 해야 하며, 프로그램마다 지원 방식이 다르므로 신호 이름을 공통 답으로 외우지 않는다.
  • 수집기도 경로가 바뀌자마자 옛 파일을 닫으면 그 사이에 writer가 쓴 끝부분을 놓칠 수 있다. 옛 파일의 남은 데이터를 읽고 writer 전환을 고려한 뒤 새 의 파일을 0부터 읽는다.
  • 여러 번 빠르게 회전하거나 재시작하면 상태 저장과 파일 탐색 정책이 필요하다.
설명용 시점경로 app.logwriter·reader가 알아야 할 일
회전 전 101둘 다 101의 현재 사용
이름 변경·새 파일 생성 102열린 FD는 여전히 101일 수 있음
writer reopen 102새 기록은 102로, 101의 끝부분을 마저 수집
완료 102새 파일의 별도 추적

06copytruncate 방식과 피할 수 없는 경쟁 구간

  • 는 현재 내용을 보관 파일로 복사한 뒤 원래 파일 길이를 0으로 줄인다. 열린 디스크립터와 를 유지할 수 있어 reopen을 지원하지 않는 writer에도 적용하기 쉽다.
  • 그러나 복사와 truncate는 하나의 원자적 동작이 아니다. 두 동작 사이에 추가된 기록이 보관 사본에 없고 원본에서도 지워질 수 있다.
  • 수집기가 fsize < 을 발견해 seek(0)을 하면 축소 후 새로운 기록을 다시 읽을 수 있다. 하지만 검사 사이에 파일이 0으로 줄었다가 기존 이상으로 빠르게 자라면 크기 비교만으로 축소를 놓친다.
  • 중간에 지워진 데이터를 seek로 복원할 수도 없다.
  • 설명용으로 복사가 바이트 1,000까지 끝난 뒤 writer가 100바이트를 더 기록하고 truncate가 실행되었다고 하자. 보관 사본에는 첫 1,000바이트만 있고 원본은 비므로 마지막 100바이트는 다른 곳에 보존하지 않았다면 사라진다. 이 손실을 “수집기에서 크기만 검사하면 해결”이라고 적지 않는다.
  1. 현재 로그의 내용을 회전 사본으로 복사한다. Writer는 같은 원본 파일에 계속 쓸 수 있다.
  2. 기존 파일을 truncate하여 같은 의 크기를 줄인다.
  3. 수집기는 크기가 보다 작아졌는지 등으로 변화를 감지하고 읽기 상태를 조정한다.
  4. 복사와 truncate 사이의 기록은 사본에 없으면서 원본에서 사라질 수 있다. 사후 복구만으로 이 구간을 되살릴 수는 없다.

07logrotate 옵션의 의미

  • daily는 실행될 때 일 단위 조건을 평가한다. logrotate 가 상시 실행되어 정확히 자정마다 모든 파일을 자르는 것은 아니며 실제 timer 또는 실행 시각이 영향을 준다.
  • rotate 14는 보관 회전본 수이고, 크기 조건과 수동 실행 등 운용 방식이 달라지면 반드시 정확한 14일 보존을 뜻하지 않는다.
  • compress는 오래된 회전 파일 압축이고 delaycompress는 가장 최근 회전본의 압축을 다음 주기로 미룬다. writer 또는 reader가 직전 파일을 아직 사용하는 경우 도움이 되지만 의 복사·삭제 경쟁을 해결하지 않는다.
  • missingok와 notifempty는 각각 없는 파일과 빈 파일의 처리 정책이다.
  • 와 를 함께 지정하면 는 효과가 없다. 원래 파일을 지우고 다시 만드는 방식이 아니기 때문이다.
  • 다음 설정은 를 선택한 학습 예다. Writer가 reopen을 지원하면 방식과 비교해야 하며 는 무손실을 보장하지 않는다.
logrotate
/var/log/snort/alert_fast.txt {
 daily
 rotate 14
 missingok
 notifempty
 compress
 delaycompress
 dateext
 copytruncate
}

수업 MVP의 선택을 재구성했다. writer가 reopen을 지원한다면 방식과 수집기의 전환 처리를 먼저 비교한다.

08재시작 복구와 전달 확인: 읽음과 적재됨의 차이

  • 수집기가 읽은 즉시 을 영속 저장한 뒤 전송 전에 죽으면 재시작 때 이미 읽은 것으로 판단하여 미전송 기록을 건너뛸 수 있다. 반대로 전송 후 확인 응답을 받기 전에 죽으면 재전송하여 중복이 생길 수 있다.
  • 단순한 파일 하나로 손실과 중복을 모두 없애지는 못한다.
  • at-least-once 전송은 확인되지 않은 기록을 다시 보내 손실 가능성을 줄이고 수신 측에서 중복을 처리하는 접근이다. 이벤트 ID에는 소스 식별자, 파일 세대, 위치 등 재시작 후에도 일관된 기준이 필요하며 내용 해시만 쓰면 실제로 반복 발생한 동일 내용 사건을 잘못 합칠 수 있다.
  • 중앙 서버가 응답할 시점도 정해야 한다. 메모리에 받았을 때와 영속 저장이 끝났을 때는 보장 범위가 다르다.
  • DataBuffer가 메모리만 사용하면 장애 때 소실될 수 있으므로 디스크 큐와 보관량·역압력·버림 정책을 설계한다.
원리 심화

09파일 읽기 위치와 전달 완료 위치의 분리

  • 읽기 은 파일에서 가져온 위치이고 전달 checkpoint는 복구 시 다시 시작할 기준이다. 어느 완료 조건에 갱신하는지가 손실·중복을 결정한다.
  • 다음 을 영속화한 뒤 출력 저장 전에 종료되면 재시작 시 아직 저장하지 않은 레코드를 건너뛸 수 있다.
  • 출력이 성공한 뒤 checkpoint 갱신 전에 종료되면 같은 레코드를 다시 읽을 수 있다. 수신 측 중복 제거가 필요한 이유다.
  • 경로가 같아도 회전으로 가 달라질 수 있다. 파일 식별자와 세대·을 함께 추적해야 같은 위치의 다른 파일을 구분한다.
  • 파일 크기가 줄었다가 빠르게 다시 자라면 주기적 크기 검사만으로 축소 순간을 놓칠 수 있다. 의 손실 창을 완전히 없애지는 못한다.
예제로 추적

10가상 레코드 101의 종료 시점 비교

  1. checkpoint가 레코드 100 뒤를 가리키고 다음 레코드는 101이라고 가정한다. 숫자는 설명용 레코드 순서다.
  2. 101을 읽자마자 checkpoint를 101 뒤로 갱신하고 출력 전에 종료되면, 재시작은 102부터 읽어 101을 놓칠 수 있다.
  3. 101을 출력 저장한 뒤 checkpoint 갱신 전에 종료되면, 재시작에서 101을 다시 보낼 수 있다.
  4. 수신기가 안정적인 이벤트 ID로 같은 101을 알아보면 중복 저장을 줄일 수 있다. 파일 경로만 같은 두 이벤트를 합쳐서는 안 된다.
  5. 이때 회전까지 일어나면 이전 파일의 남은 부분과 새 파일의 시작을 각각 추적한다. 한 경로의 하나로 두 세대를 표현하지 않는다.
검증·예외

11회전 직후 누락·중복을 좁히는 자료

  • 뒤에도 가 이전 파일 디스크립터에 쓰는지 확인한다. 새 경로 파일이 존재해도 실제 쓰기 대상은 다를 수 있다.
  • 열린 파일의 식별자·현재 ·마지막 전달 ID를 비교한다. 파일 크기만으로 어느 레코드까지 저장됐는지는 알 수 없다.
  • ACK가 큐 수신인지 내구성 있는 적재 완료인지 확인한다. 완료 의미가 다르면 복구 보장도 달라진다.
  • 회전·강제 종료·출력 지연·재시작을 함께 넣은 가상 표본으로 개수와 ID를 대조한다. 정상 회전 한 번만으로 장애 복구를 증명하지 않는다.

12검증 시나리오와 대체 수집 경로

  • 격리된 실습에서 순번이 있는 시험 로그를 연속 생성하고 회전 전후 원본·보관본·수집 결과의 순번을 비교한다. 정상 회전뿐 아니라 회전 도중 writer 계속 쓰기, 수집기 재시작, 긴 부분 줄, 연속 회전, 중앙 서버 중단을 시험해야 어디에서 누락·중복되는지 알 수 있다.
  • Unix 소켓이나 ·RELP 전송으로 파일 회전 의존성을 줄일 수 있지만 소켓 버퍼 초과, 재연결, 큐 영속성과 수신 확인 문제는 남는다. 메시지 브로커는 확인 응답·보존·재처리를 제공할 수 있으나 운용 복잡성과 저장 비용도 늘어난다.
  • “파일 대신 네트워크면 무손실”이라는 결론 대신 각 경계의 실패 동작을 비교한다.
  • 보관 만료는 수집 완료 확인보다 빨리 일어나지 않아야 한다. 회전 파일을 압축하거나 지우는 정책과 지연된 수집기의 복구 가능 시간을 함께 정하고, 경보 수집 지연과 마지막 성공 위치를 운영 지표로 남긴다.
LEARN THROUGH PRACTICE

날짜별 파일과 압축 결과에서 회전 중 수집 위치 추적하기

로그 파일명이 바뀌거나 내용이 잘리는 순간에 경로··읽기 이 어떻게 달라지는지 설명하고 누락·중복을 구분한다.

실습 구성과 전제

  • 시험용 로그 디렉터리와 고유 번호가 붙은 가상 이벤트를 사용한다. 서비스 운영 로그를 임의로 자르지 않는다.
  • 날짜별 웹 로그 화면과 alert_fast 수집 설계는 서로 다른 자료다. 파일 회전의 공통 원리를 비교하며 동일 실행의 전후 사진이라고 가정하지 않는다.
  1. 현재 파일명과 수집 상태를 따로 기록하기

    • 날짜가 파일명에 들어가면 하루가 바뀔 때 다른 경로가 생길 수 있다. 수집기가 한 경로만 계속 열고 있으면 새 파일을 발견하지 못할 수 있으므로 파일 발견 정책부터 확인한다.
    • 파일명을 기억하는 것만으로는 부족하다. 와 읽기 을 함께 기록해야 같은 이름으로 새 파일이 생긴 경우와 기존 파일이 자라난 경우를 구별할 수 있다.
    bash
    stat -c '%i %s %n' ./lab.log
    logrotate -d ./lab-logrotate.conf

    lab.log와 시험 설정을 준비한 뒤 메타데이터와 회전 계획만 확인하는 예. -d는 실제 회전을 수행하지 않는다.

    log server 설정 · 실습·개념 참고 화면 1원본 크기로 보기 ↗
    • web/access 아래에 20260617.log와 20260618.log가 별도 파일로 나열되어 있다. 날짜가 바뀐 파일을 하나의 고정 경로로 볼 수 없다.
    • web/error가 access와 분리된 디렉터리로 보인다. 정상 접근 로그와 오류 로그의 수집 대상·규칙도 각각 지정할 필요가 있다.
    확인 기준

    고유 이벤트 번호, , 크기, 의 기준값을 저장한 뒤 회전 시험을 시작한다.

  2. 회전 후 압축 파일과 새 파일의 경계를 찾기

    • 회전에서는 기존 파일을 열고 있던 수집기가 그 파일의 끝까지 읽고, 새 의 활성 파일로 넘어가야 한다. 작성 도 새 파일을 다시 열 수 있어야 한다.
    • 는 복사 후 같은 파일을 비우므로 가 유지될 수 있다. 복사와 비우기 사이에 추가된 데이터의 손실 가능성이 있고, 파일이 빠르게 다시 자라면 단순 크기 감소 검사만으로 회전을 놓칠 수도 있다.
    log server 설정 · 실습·개념 참고 화면 2원본 크기로 보기 ↗
    • 20260617.log-20260618.gz처럼 원래 날짜와 회전 접미 날짜가 함께 들어간 압축 파일명이 보인다.
    • 압축 파일이 존재한다는 것은 보관 결과가 있다는 뜻이다. 그 안에 모든 이벤트가 들어 있는지, 수집기가 읽었는지는 파일명만으로 알 수 없다.
    확인 기준

    회전 직전·직후 이벤트 번호가 활성 파일과 압축 파일 중 어디에 있는지 읽어서 확인한다. 와 를 함께 썼다고 새 가 생성되는 것은 아니다.

  3. 읽은 번호와 전송 완료 번호를 대조하기

    • 파일에서 읽은 이벤트 번호와 중앙 저장소가 확인한 번호를 분리한다. 수집기가 읽은 직후 종료되면 메모리 버퍼에만 있던 이벤트는 아직 저장 성공이 아니다.
    • 가상 이벤트 101·102·103을 기준으로 회전 전후와 수집기 재시작을 나누어 시험한다. 원본 파일의 세 번호, 송신 기록의 세 번호, 최종 저장소의 세 번호를 비교해야 손실과 중복을 셀 수 있다.
    bash
    gzip -cd -- ./20260617.log-20260618.gz

    실습 디렉터리의 압축 보관 내용을 표준 출력으로 읽는 예. 실제 파일명에 맞춰 사용하며 원본을 덮어쓰지 않는다.

    확인 기준

    번호가 빠지면 작성·회전·읽기·전송 중 최초로 사라진 구간을 찾는다. 같은 번호가 둘이면 재전송과 체크포인트 저장 순서를 검사한다.

실습에서 확인한 동작 원리

  • 압축 파일 생성은 보관의 증거이며, 수집 완전성의 증거는 이벤트 번호 대조다.
  • 파일 회전과 중앙 전송 확인을 별도로 설계해야 재시작 때 누락과 중복을 설명할 수 있다.

설정·출력 추가로 확인하기 2장

아래 화면을 펼쳐 위 실습의 설정값, 명령과 확인 기준을 비교해 보세요. 각 묶음은 별도 실습 기록입니다.

실습 화면 묶음 01 1장
log server 설정 · 실습·개념 참고 화면 3원본 크기로 보기 ↗
  • 「flask」 문맥에 삽입된 원본 실습·개념 참고 화면이다. 로그 회전과 수집기 학습 내용과 함께 당시 구성·설정·관찰 결과를 비교할 수 있다.
실습 화면 묶음 02 1장
network log · 명령·상태 출력 10원본 크기로 보기 ↗
  • 「logrotate : 자동 로그 관리 (용량…)」 문맥에 삽입된 원본 명령·상태 출력이다. 로그 회전과 수집기 학습 내용과 함께 당시 구성·설정·관찰 결과를 비교할 수 있다.
동작·명령 참고 문서
학습 확인

이해했는지 확인하기

  • 기록 프로그램이 파일 순환 뒤 어디에 쓰는지 확인한다.
  • 수집기가 축소·이름 변경·재시작을 어떻게 처리하는지 확인한다.
  • 시험 이벤트 번호로 누락과 중복을 각각 계산한다.

함께 확인할 공식 자료