- 데이터 복구와 규제 준수를 위해 archived_at 열 기반의 소프트 삭제가 자주 사용되지만, 시간이 지나면 복잡성과 비효율이 커짐
- 이 방식은 쿼리, 인덱스, 마이그레이션, 복원 로직을 복잡하게 만들고, 대부분의 보관 데이터가 다시 읽히지 않아 데이터베이스에 불필요한 부하를 초래함
- 대안으로 애플리케이션 이벤트 기반 보관, 트리거 기반 보관, WAL(Change Data Capture) 기반 보관이 제시됨
- 각 방식은 운영 복잡도, 인프라 요구, 복원 용이성에서 차이를 보이며, 특히 WAL 기반은 Kafka 등 외부 시스템과의 통합이 필요함
- 새로운 프로젝트라면 트리거 기반 접근법이 단순성과 유지보수성 측면에서 가장 균형 잡힌 선택임
소프트 삭제의 문제점
- 일반적으로 deleted 불리언이나 archived_at 타임스탬프 열을 사용해 데이터를 논리적으로 삭제함
- 고객이 데이터를 실수로 삭제했을 때 복구 가능
- 규제나 감사 목적상 보관이 필요한 경우도 있음
- 그러나 archived_at 열은 쿼리, 운영, 애플리케이션 코드 전반에 복잡성을 유발
- 대부분의 보관 데이터는 다시 읽히지 않음
- API 동작 문제나 자동화 도구(Terraform 등)로 인해 수백만 개의 불필요한 행이 누적될 수 있음
- 보관 데이터 정리 작업이 설정되지 않으면 데이터베이스 백업 및 복원 시 성능 저하 발생
- 쿼리와 인덱스에서 보관 데이터를 필터링해야 하며, 데이터 누출 위험 존재
- 마이그레이션 시 오래된 데이터 처리나 기본값 수정이 어려움
- 복원 로직이 복잡해지고, 외부 시스템 호출이 필요한 경우 버그 발생 가능
- 결과적으로 archived_at 방식은 단순해 보이지만 장기적으로 유지보수 비용이 높음
애플리케이션 레벨 보관
- 삭제 시 이벤트를 발행하고, 이를 SQS로 전송해 다른 서비스가 S3에 보관
- 장점
- 주요 데이터베이스와 애플리케이션 코드 단순화
- 외부 리소스 정리를 비동기 처리하여 성능과 안정성 향상
- JSON 형태로 직렬화해 애플리케이션 친화적 구조로 보관 가능
- 단점
- 애플리케이션 코드 버그로 인해 보관 데이터 손실 가능
- 메시지 큐 등 운영 인프라 복잡성 증가
- S3의 보관 데이터는 검색 및 복원 도구 필요
트리거 기반 보관
- 삭제 전 트리거가 행을 별도의 archive 테이블에 JSON 형태로 복사
- 예시 테이블: archive(id, table_name, record_id, data, archived_at, caused_by_table, caused_by_id)
- 외래 키 삭제(cascade) 시 삭제 원인 추적을 위해 세션 변수(archive.cause_table, archive.cause_id) 사용
- 어떤 상위 레코드가 하위 데이터를 삭제했는지 조회 가능
- 장점
-
라이브 테이블이 깨끗하게 유지, archived_at 열 불필요
- 보관 테이블 정리(WHERE archived_at < NOW() - INTERVAL '90 days')가 간단
- 쿼리와 인덱스 효율 유지, 마이그레이션 단순화
- 백업 크기 감소
- 보관 테이블은 별도 테이블스페이스나 시간 파티셔닝으로 관리 가능
WAL(Change Data Capture) 기반 보관
- PostgreSQL의 WAL 로그를 읽어 삭제 이벤트를 외부 시스템으로 스트리밍
- 대표 도구: Debezium (Kafka와 연동)
- 경로 예시: PostgreSQL → Debezium → Kafka → Consumer → Archive Storage
- 경량 대안
-
pgstream: WAL을 웹훅이나 메시지 큐로 직접 전송
-
wal2json: WAL을 JSON으로 출력
-
pg_recvlogical: PostgreSQL 내장 논리 복제 도구
- 운영 복잡성
- Kafka 기반은 모니터링·장애 대응·튜닝 필요
- 소비자(consumer)가 지연되면 WAL 파일 누적 → 디스크 공간 부족 위험
- PostgreSQL 13+의 max_slot_wal_keep_size 설정으로 제한 가능
- 복제 슬롯 지연 모니터링 및 알림 필수
- 장점
- 애플리케이션 코드 수정 없이 모든 변경 캡처 가능
-
다양한 목적지(S3, 데이터 웨어하우스, 검색 인덱스) 로 스트리밍 가능
- 기본 데이터베이스에 추가 부하 없음
- 단점
-
운영 복잡도와 인프라 비용 높음
- 소비자 지연 시 데이터 손실 또는 재동기화 필요
- 스키마 변경 시 소스-소비자 간 조율 필요
삭제를 처리하지 않는 복제본 아이디어
- DELETE 쿼리를 무시하는 PostgreSQL 복제본을 유지하는 아이디어 제시
- 삭제되지 않은 모든 데이터를 누적 보관 가능
- 보관 데이터 직접 쿼리 가능
- 잠재적 문제
- 삭제 정보 구분 불가 가능성
- 마이그레이션 적용 시 충돌 위험
-
저장 공간 및 운영 비용 증가
결론
- 새로운 프로젝트에서는 트리거 기반 보관 방식이 가장 실용적 선택
- 설정이 간단하고, 라이브 테이블을 깨끗하게 유지
- 별도 인프라 없이도 보관 데이터 조회 및 관리 용이
- 복잡한 인프라가 이미 존재하거나 다중 목적지 스트리밍이 필요한 경우에는 WAL 기반 접근이 적합