S3 삭제 감사 로그 유실 — append 동시성과 FIFO SQS

클라우드·인프라2분조회

S3 버킷에 쌓인 파일을 오래되면 자동으로 지우도록 라이프사이클 규칙을 걸어뒀습니다. 그런데 “무엇이 언제 지워졌는지” 는 어딘가 남겨둬야 나중에 확인할 수 있습니다. 그래서 파일이 삭제될 때마다 그 기록을 구글 스프레드시트에 한 줄씩 남기는 감사(audit) 파이프라인을 만들었습니다.

구조는 AWS 서비스 몇 개를 이어 붙인 형태입니다.

  • S3 라이프사이클 이 오래된 파일을 삭제하면,
  • EventBridge(AWS 이벤트 버스)가 그 삭제 이벤트를 잡아,
  • SQS(메시지 큐)에 넣고,
  • Lambda(이벤트로 실행되는 함수)가 그 메시지를 받아 스프레드시트에 한 줄을 덧붙입니다(append).

어느 날 보니 32개가 삭제됐는데 시트엔 25줄만 있었습니다. 7개가 사라진 겁니다.

모든 단계 지표는 32로 정상

각 단계를 다 확인했는데 어디도 이상이 없었습니다.

단계
EventBridge 매칭 32
SQS sent / received / deleted 32
Lambda invocation 32
Lambda error 0
시트 최종 25

메시지도 안 잃고, Lambda 도 다 돌았고, 에러도 0 인데 시트만 모자랍니다.

원인 — 컨테이너 재사용 + append의 동시성 한계

스트림별 Lambda 로그를 뜯어보니, 한 실행 안에서 Appended row두 번 찍힌 게 있었습니다. Lambda 컨테이너 재사용으로 거의 동시에 두 append 호출이 나갔습니다.

그리고 Google Sheets 의 append 에는 문서화된 한계가 있습니다. 동시에 들어온 append 들이 같은 셀 범위를 잡아 서로 덮어씁니다. “다음 빈 줄” 을 각자 계산하는데, 동시에 계산하면 같은 줄을 가리켜 하나가 다른 하나를 밀어냅니다. 그래서 호출은 다 성공했는데 결과 줄만 모자랍니다. 에러가 없으니 지표론 안 잡힙니다.

해결 — FIFO SQS로 직렬화

동시성이 문제니 처리를 직렬화하면 됩니다. Standard SQS 를 FIFO 로 바꾸고, 모든 메시지에 같은 MessageGroupId 를 줬습니다.

  • MessageGroupId 를 하나로 고정 → 그 그룹은 한 번에 하나씩만 처리
  • Lambda 배치 크기 1 → 한 번에 한 건

EventBridge 도 SQS FIFO 타겟을 지원해서(SqsParameters 의 MessageGroupId), 파이프라인 구조를 크게 안 바꾸고 직렬화만 걸 수 있었습니다. 이후로 32개가 빠짐없이 기록됐습니다.

지표는 정상인데 결과가 모자랄 때 — 동시 덮어쓰기

“모든 단계 지표가 정상인데 최종 결과만 모자란다” 면 동시에 들어와 서로 덮어쓴 것 를 의심합니다. 호출이 다 성공해도, 그 호출들이 같은 자원(여기선 시트의 다음 빈 줄)을 동시에 잡으면 결과가 유실됩니다. 에러가 안 나니 지표로는 안 보입니다. 순서가 중요한 append 성 작업은 FIFO 큐 + 단일 MessageGroupId 로 직렬화하는 게 확실합니다. 병렬로 빨리 처리하는 것보다, 겹치지 않게 하는 게 목적일 때가 있습니다.

  1. 불러오는 중