이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.

  • 데이터 손실 사고에서 가장 먼저 멈춰야 할 것은 무엇인가?
  • 복구와 보정 중 어떤 방식을 선택할지 어떻게 판단하는가?
  • 사고 대응 기록에는 어떤 증거가 남아야 하는가?

개요

데이터 손실 사고는 잘못된 삭제, 잘못된 update, 실패한 migration, 배치 오류, 파일 삭제 정책, 외부 시스템 중복 처리로 발생한다.

이 사고는 일반 장애와 다르다.

서비스를 다시 시작한다고 데이터가 돌아오지 않으며, 성급한 복구가 더 많은 데이터를 덮어쓸 수 있다.

첫 목표는 빠른 복원이 아니라 추가 손상을 멈추고 손실 범위를 확정하는 것이다.

Spring 백엔드 개발자는 어떤 요청과 배치가 데이터를 바꾸는지, 어떤 데이터가 재생성 가능한지, 어떤 데이터가 외부 시스템과 연결되는지 설명해야 한다.

첫 10분 원칙

데이터 손실이 의심되면 즉시 판단해야 할 순서가 있다.

  1. 추가 쓰기를 멈출 수 있는가?
  2. 자동 배치나 재시도 작업이 손실을 키우고 있는가?
  3. 사고 기준 시각을 좁힐 수 있는가?
  4. 최신 백업과 복구 가능한 시각은 어디인가?
  5. 손실 데이터가 DB, Object Storage, 외부 시스템 중 어디에 있는가?

이 순서가 없으면 원인을 찾는 동안 손실 범위가 계속 커질 수 있다.

멈추는 대상은 서비스 전체가 아닐 수 있다.

특정 관리자 기능, 삭제 배치, 정산 작업, 파일 lifecycle, 이벤트 consumer만 멈추는 것이 더 안전할 때도 있다.

증거 보존

복구 전에는 현재 상태를 보존해야 한다.

select now() as checked_at;
 
select count(*) as orders_after_window
from orders
where updated_at >= timestamp '2026-07-01 09:00:00';
 
select id, status, updated_at
from orders
where updated_at >= timestamp '2026-07-01 09:00:00'
order by updated_at desc
limit 100;

DB 상태뿐 아니라 애플리케이션 로그, 관리자 작업 기록, 배치 실행 기록, Object Storage 감사 로그도 같은 시간대로 모아야 한다.

증거를 남기지 않고 복구를 시작하면 나중에 어떤 데이터가 손실되었고 어떤 데이터가 정상 생성되었는지 구분하기 어렵다.

손실 범위 확정

손실 범위는 테이블명 하나로 충분하지 않다.

다음 축으로 좁혀야 한다.

  • 시간 범위
  • 사용자 또는 tenant 범위
  • 기능 범위
  • 테이블과 object prefix
  • 외부 시스템에 전달된 이벤트 범위
  • 재생성 가능한 데이터와 원본 데이터 구분

예를 들어 주문 상태를 잘못 update한 사고라면 주문 row만 볼 수 없다.

결제 승인, 포인트 지급, 알림 발송, outbox event, 정산 배치 입력까지 함께 확인해야 한다.

Spring 서비스의 트랜잭션 경계와 이벤트 발행 방식이 여기서 중요해진다.

복구 방식 선택

데이터 손실 대응에는 크게 세 가지 선택지가 있다.

  • restore: 백업이나 PITR로 특정 시점 데이터를 되돌린다.
  • forward fix: 현재 상태에서 보정 SQL이나 보정 배치로 잘못된 데이터를 고친다.
  • replay: 원본 이벤트나 로그를 다시 처리해 데이터를 재구성한다.

선택 기준은 다음과 같다.

  • 손실 범위가 전체 DB에 가까우면 restore가 유리하다.
  • 사고 이후 정상 쓰기가 많으면 전체 restore는 정상 데이터를 잃게 만들 수 있다.
  • 잘못된 변경 범위가 좁고 규칙이 명확하면 forward fix가 안전할 수 있다.
  • 이벤트 로그가 완전하고 idempotent 처리가 가능하면 replay를 검토할 수 있다.
  • 외부 결제나 발송이 얽혀 있으면 DB만 되돌리는 방식은 위험하다.

복구 방식은 데이터 정확성, 사용자 영향, 중복 부작용, 소요 시간을 같이 비교해야 한다.

보정 배치 예시

보정은 반드시 dry-run과 검증 SQL을 먼저 가진다.

-- dry-run: 대상 확인
select id, status, updated_at
from orders
where status = 'CANCELLED'
  and cancel_reason = 'BATCH_ERROR'
  and updated_at between timestamp '2026-07-01 09:00:00'
                   and timestamp '2026-07-01 09:20:00';
 
-- fix는 승인 후 작은 범위로 실행
update orders
set status = 'PAID',
    cancel_reason = null
where id in (:confirmed_order_ids);

보정 SQL은 항상 “왜 이 row가 대상인지”를 설명할 수 있어야 한다.

대상이 애매하면 SQL을 실행하기 전에 샘플을 뽑아 도메인 담당자와 확인한다.

운영 체크리스트

  • 손실 의심 시각과 발견 시각을 분리해 기록한다.
  • 쓰기 기능, 배치, consumer, lifecycle 중 멈출 대상을 결정한다.
  • 최신 백업과 PITR 가능 시점을 확인한다.
  • 손실 범위 SQL과 샘플 데이터를 보존한다.
  • 외부 시스템 부작용 여부를 확인한다.
  • restore, forward fix, replay 후보를 비교한다.
  • 복구 후 검증 SQL과 사용자 영향 공지를 준비한다.
  • 사고 후 같은 경로가 다시 실행되지 않도록 차단한다.

장애 신호

  • 특정 시간 이후 데이터 건수가 평소 패턴과 다르다.
  • 삭제 배치 실행 후 문의가 급증한다.
  • 관리자 작업 로그와 DB 변경 시각이 일치한다.
  • migration 이후 특정 컬럼 값이 대량으로 null이 된다.
  • Object Storage prefix의 object 수가 갑자기 줄었다.
  • outbox event가 중복 발행되거나 누락되었다.
  • 복구 후에도 같은 배치가 다시 데이터를 덮어쓴다.

이 신호들은 단순 오류율보다 손실 범위 확정에 더 직접적으로 도움이 된다.

안전한 완화 조치

  • 자동 배치와 consumer를 멈춰 추가 변경을 막는다.
  • 문제가 된 기능을 feature flag나 권한으로 차단한다.
  • 운영 DB 전체 restore 전에 별도 DB에서 손실 범위를 비교한다.
  • 보정 SQL은 dry-run, 승인, 작은 batch, 검증 순서로 실행한다.
  • Object Storage 사고는 해당 prefix의 삭제 정책부터 멈춘다.
  • 외부 시스템 중복 호출 위험이 있으면 재처리 전에 idempotency key를 확인한다.

완화 조치는 손실을 더 키우지 않는 방향이어야 한다.

하지 말아야 할 대응

  • 원인도 범위도 모른 채 최신 백업을 운영 DB에 덮어쓰지 않는다.
  • 사고 이후 정상 생성된 데이터를 무시하고 과거 시점으로 전체 복원하지 않는다.
  • 보정 SQL을 dry-run 없이 실행하지 않는다.
  • 외부 결제, 알림, 포인트 같은 부작용을 DB 상태만 보고 재실행하지 않는다.
  • 사고 기록을 남기기 전에 로그와 백업을 정리하지 않는다.

인프라 담당자와 공유할 자료

  • 발견 시각, 의심 시작 시각, 마지막 정상 시각
  • 영향을 받은 테이블, row 수, 사용자 범위
  • 관련 배포, 관리자 작업, 배치 실행 기록
  • 백업 기준 시각과 PITR 가능 범위
  • 손실 데이터와 정상 데이터 구분 기준
  • 선택한 복구 방식과 선택하지 않은 방식의 이유
  • 복구 후 검증 SQL과 사용자 영향 결과

공유 자료는 책임 추궁보다 정확한 복구 결정을 돕는 형태여야 한다.

확인 질문

확인 질문

  • 데이터 손실 사고에서 가장 먼저 멈춰야 할 것은 무엇인가?
    • 추가 손상을 만드는 쓰기 기능, 자동 배치, consumer, 삭제 정책이다.
  • 전체 restore가 항상 안전하지 않은 이유는 무엇인가?
    • 사고 이후 정상 생성된 데이터를 잃거나 외부 시스템 상태와 DB 상태가 어긋날 수 있기 때문이다.
  • 복구 방식 선택에 필요한 핵심 정보는 무엇인가?
    • 손실 범위, 기준 시각, 백업 가능 시점, 정상 쓰기 여부, 외부 부작용 여부다.

리뷰 체크포인트

  • 사고 기준 시각과 발견 시각이 분리되어 있는가?
  • 추가 손상을 멈추는 절차가 있는가?
  • 손실 범위를 확인하는 SQL과 로그가 준비되어 있는가?
  • restore, forward fix, replay 선택 기준이 문서화되어 있는가?
  • 복구 후 검증과 재발 차단 작업이 포함되어 있는가?