5.3 시점 복구와 버그 재현
잘못된 데이터 변경을 발견하면 사고 직전 상태와 현재 운영 상태를 대조할 환경이 먼저 필요합니다. 과거 데이터를 확인하는 작업, 필요한 행을 복구하는 작업, 같은 오류를 재현하는 작업은 완료 조건이 다릅니다. 이 장에서는 조사용 환경을 먼저 준비하는 구성을 제안합니다. 이후 절차는 부분 복구 검증과 코드 결합 재현으로 나눕니다.
복구할 데이터 범위를 정하기 전에는 운영 전체를 과거로 전환하는 절차를 자동으로 실행하지 않습니다. 사고 이후의 정상 변경을 어떻게 보존할지 함께 판단합니다. 다음의 제품 동작과 Replit 공개 사례를 제외한 조사 순서와 patch 검토는 운영 설계 제안입니다. 보존과 만료 정책도 운영 설계 제안에 포함합니다. 고객의 실제 부분 복구 사고 처리 사례는 이번 조사에서 사례 미확인으로 남깁니다.
적용 계층과 제품
과거 상태를 준비하는 경로
일반 PostgreSQL의 PITR은 base backup과 WAL 재생으로 목표 시점의 상태를 준비합니다. 복구 목적이 같아도 제품마다 과거 branch를 만드는 방식은 다릅니다. 복구 대상의 cluster와 timeline, 선택한 시점, 실제 복구 완료 상태를 함께 식별합니다. 서로 다른 계보에서 LSN의 숫자가 같다는 이유만으로 데이터 상태가 같다고 판정하지 않습니다.
Neon은 저장된 page 이력을 활용해 과거 시점의 branch를 준비하는 경로를 제공합니다. 조사 시점의 데이터와 현재 운영 데이터를 분리해 확인하는 용도로 검토합니다. 저장 이력과 조상 관계의 상세는 Timeline과 Branch 내부에 연결합니다. 이 장에서는 page 재구성 과정의 반복 설명을 생략합니다. 조사에 사용할 기준점과 코드 버전의 연결을 다룹니다.
Tiger의 fork도 모드를 구별합니다. 현행 문서는 CoW 경로와 backup restore 및 WAL replay 경로를 구분합니다. 최신 상태, 최근 snapshot, 보존 범위 안의 지정 시점을 선택하는 방식도 설명합니다. 지정 시점 fork를 선택했다는 이유만으로 모든 서비스의 준비 시간이나 청구 방식이 같다고 가정하지 않습니다. 실제 적용 경로를 복구 계획에 명시합니다.
Neon의 restore, reset, snapshot 명령은 복구와 초기화 실습에 정리되어 있습니다. 여기서는 명령 실행 자체보다 목적을 구분합니다. 사고 직전 자료를 읽는 환경과 수정안을 실행할 환경에 서로 다른 식별자를 부여합니다. 실험 중 변경한 데이터를 원래 조사 자료로 제시하지 않도록 관리하는 방식을 제안합니다.
코드와 데이터 시점의 결합
2025-05-21에 공개된 Replit App History 설명은 과거 checkpoint의 preview 준비 방식을 다룹니다. 해당 시점의 Neon DB branch와 대응하는 코드 버전을 결합합니다. 실명 파트너의 구현을 설명한 공급사 자료이므로 신뢰도는 보통입니다. 이 자료는 과거 도입 사례로 사용합니다. 고객별 branch 생성량이나 2026년 전체 내부 구성의 근거로 확대하지 않습니다. Replit App History
자체 버그 재현 환경에도 코드와 데이터 기준점을 함께 기록하는 방식을 제안합니다. 여기에 PostgreSQL 버전, extension, 설정, 실행 입력을 추가합니다. 예를 들어 사고 직전 코드와 사고 직전 데이터를 결합한 실행을 먼저 기록합니다. 수정한 코드만 바꾼 실행은 별도 실험으로 둡니다. 재현 여부를 비교할 때 어떤 조건을 변경했는지 보고서에서 확인하도록 구성합니다.
운영 DB에 주는 부하
이력 보존과 복구 준비
복구 준비 비용은 보존, 읽기, 실행으로 나누어 관리합니다. 일반 PostgreSQL 경로에서는 backup과 WAL archive의 보존 및 복구 읽기를 기록합니다. WAL 재생 시간도 기록합니다. 서비스의 history window를 사용하는 경로에서는 선택 가능한 과거 범위와 이력 비용을 확인합니다. Neon의 비용 모델도 compute와 복구 이력의 비용을 구분합니다. 따라서 조사 compute를 정지했다는 이유만으로 보존 비용을 종료 처리하지 않습니다.
History window는 얼마나 과거의 상태를 선택하는지에 관한 범위입니다. RPO는 장애 시 허용할 데이터 손실을 시간으로 나타낸 목표입니다. 따라서 두 값을 동일하게 적지 않습니다. 조사 정책에는 사고 발생부터 발견까지 걸린 시간을 검토하도록 제안합니다. 담당자 확인까지의 시간과 기준점을 보존하기까지의 시간도 검토합니다. 필요한 시점이 아직 선택 가능한지는 실제 복구 요청으로 시험합니다.
이력 기간을 늘린 뒤에는 복구 준비의 각 단계에 걸리는 시간도 측정하는 방식을 제안합니다. Backup과 필요한 WAL을 읽는 단계, 복구된 DB에 접속하는 단계, 대상 데이터를 확인하는 단계를 구분합니다. 요청한 시점과 실제 확인한 시점도 구분합니다. 복구 대상이 보존 범위를 벗어났다면 근처의 다른 시점을 같은 결과로 대신 표시하지 않습니다.
조사와 운영 반영의 부하
조사 쿼리는 복구 환경의 compute와 저장소에서 실행하도록 설계합니다. 운영 상태와 비교할 때는 대상 키와 비교 범위를 먼저 정하고, 운영 조회량을 측정합니다. 복구 환경을 별도로 만들어도 현재 운영 데이터와의 대조 비용을 계산에 포함합니다. 여러 조사자가 동시에 접속하는 경우에는 세션 수와 큰 조회의 동시 실행 수를 제한하는 정책을 제안합니다.
부분 복구 patch를 운영에 적용하는 단계는 별도의 변경 작업으로 관리합니다. 후보 데이터 추출과 검증 시간, 현재 상태 재대조 시간, 실제 적용 시간을 구분합니다. 적용 행 수와 예상 변경 범위를 미리 기록합니다. 허용 범위를 벗어나면 작업을 중단하도록 설계합니다. 이때 사용하는 자원 예산은 조사용 clone의 예산과 분리합니다.
흔한 실패
잘못된 기준점과 혼재한 변경
사고 시각을 애플리케이션 로그 한 줄만으로 확정하는 상황을 실패 가설로 둡니다. 시간대와 기록 기준을 명시하는 절차를 제안합니다. 목표 데이터의 존재 여부를 확인해 선택한 시점을 검증합니다. 복구 식별자에는 cluster 또는 서비스의 원본 ID와 timeline 또는 branch 계보를 함께 남깁니다. 시각과 LSN 중 하나만 적어 다른 환경과 혼동하는 경우도 시험합니다.
현재 없는 행은 과거에 존재했다는 사실 외에도 복구 후보로 삼을 근거를 확인합니다. 업무 담당자와 사고로 삭제된 대상, 정상적으로 삭제된 대상, 사고 이후 수정된 대상을 분류하는 절차를 제안합니다. 구별할 증거가 부족하면 자동 patch 대상에서 제외하고 미확인으로 기록합니다. 정상 변경의 보존 여부는 행 수 증가만으로 판정하지 않습니다.
복구 후보가 현재 운영 데이터와 같은 키를 가진 경우에는 최신 상태를 우선 대조하도록 설계합니다. 과거 값을 무조건 덮어쓰거나 모든 충돌을 무시하는 규칙을 기본값으로 두지 않습니다. 키별 적용 조건과 보류 이유를 기록합니다. 검토자가 후보 데이터와 현재 데이터의 차이를 확인하도록 합니다. 관련 테이블의 업무 관계까지 어느 범위로 검증했는지도 보고서에 남깁니다.
재현 환경의 변질
재현 중인 환경을 최신 부모로 자동 초기화하면 사고 당시 조건을 잃는 상황을 시험합니다. 재현용 환경에는 자동 갱신을 제한하는 정책을 제안합니다. 데이터를 바꾸는 실험마다 시작 상태와 변경 내용을 남깁니다. 복구 자료를 보존하는 환경에 수정 코드가 바로 쓰지 않도록 접근 대상을 구분합니다. 별도 이름을 사용해도 같은 endpoint를 연결했는지 다시 확인합니다.
코드 commit만 일치하면 동일한 실행 조건이라고 판단하는 경우도 점검합니다. 설정과 입력, 외부 의존성을 재현 기록에 포함하고, 확보하지 못한 항목은 명시합니다. 외부 호출을 대체했다면 그 대체 조건도 적습니다. 오류가 재현되지 않았다는 결과만으로 원인이 없다고 단정하지 않습니다. 시험에서 복원한 조건의 범위를 먼저 검토하도록 제안합니다.
운영 정책 제안
부분 복구 검증 절차
- 사고 번호와 의심 시간 범위를 등록합니다. 운영 쓰기를 계속할지 제한할지는 서비스 책임자가 결정합니다. 허용한 동시 변경 범위를 조사 기록에 남깁니다. 필요한 과거 시점의 보존 여부를 확인하고 조사용 환경을 준비합니다.
- 대상 행이 존재하는지 확인합니다. 원본 계보, 선택 시각, 복구 완료 시각을 기록합니다. 사고 직전 자료라는 판단 근거를 보존합니다. 조회 결과의 행 수와 확인한 키 범위를 함께 남깁니다.
- 복구 후보를 추출하고 현재 상태와 대조합니다. 사고로 인한 손실과 정상 변경을 구분합니다. 불명확한 행은 적용 보류 목록에 둡니다. 이 단계의 산출물은 검토할 후보 데이터와 차이 목록입니다.
- 후보 patch를 별도의 검증 환경에서 실행합니다. 관련 데이터의 관계와 업무 조회 결과를 확인합니다. 예상 영향 행 수, 실행 조건, 중단 조건, 원복 자료를 기록합니다. DBA와 업무 담당자가 각자의 검증 항목을 확인합니다.
- 운영 반영 직전에 현재 값을 다시 대조합니다. 이전 검토 이후 바뀐 대상은 적용을 보류하고 재검토합니다. 승인된 범위만 반영한 뒤 실제 변경 행 수와 업무 결과를 확인합니다. 부분 적용이나 실패가 발생하면 그 상태에서 후속 절차를 결정합니다.
- 후보 추출, 승인, 적용, 검증 기록을 묶어 보존합니다. 조사용 환경과 patch 검증 환경의 삭제 기한을 각각 정합니다. 남겨야 할 증적을 별도로 저장했는지 확인한 뒤 정리합니다.
이 절차는 운영 적용 전에 현재 값이 다시 바뀌는 상황까지 시험하는 제안입니다. 검토 완료와 실제 쓰기 사이의 동시 변경을 어떻게 제한하거나 감지할지 정합니다. 이 방식은 서비스의 트랜잭션 설계에 맞춥니다. Clone 생성만으로 그 조건이 충족되었다고 판단하지 않습니다. 부분 복구의 적용 대상을 특정하지 못한 상태에서는 작업을 조사 단계로 유지합니다.
명명과 TTL
복구 환경에는 restore-사고번호-시점을 제안합니다. 재현 환경에는 repro-버그번호-코드버전을 제안합니다. 이름의 시점은 UTC 등 팀이 정한 표기 규칙을 따르고 시간대를 명시합니다. 표시명과 별도로 원본 ID, 실제 분기 ID, 코드 commit, 생성 목적을 저장합니다. 환경을 만들 때마다 만료 시각과 소유자를 요구합니다. 이름에 고객 식별 정보를 넣지 않는 정책을 제안합니다.
TTL은 사고 조사와 원인 검증의 종료 조건에 맞춰 정합니다. 이력 window, 조사 branch, 보고서의 보존 기간을 별도 항목으로 관리합니다. 조사 연장에는 사유와 새 종료일을 요구합니다. 기간을 바꿀 때 필요한 복구 시점의 보존 여부도 재확인합니다. 장기간 유지할 자료를 쓰기 가능한 조사 환경에만 의존해 보존하지 않도록 증적 보존 절차를 마련합니다.
도식
다음 흐름은 하나의 검증된 과거 기준점에서 두 작업으로 나누는 절차 제안입니다. 부분 복구는 현재 운영 상태와의 대조를 거칩니다. 버그 재현은 대응하는 코드와 설정을 결합합니다. 조사 완료 후에는 두 환경의 수명을 따로 관리합니다.
조사 보고서에는 선택한 기준점을 확인한 쿼리와 결과를 남깁니다. 부분 복구 보고서는 승인된 후보와 실제 반영 대상을 연결합니다. 재현 보고서는 코드와 데이터의 조합별 결과를 연결합니다. 운영 데이터의 변경 기록과 원인 분석의 실험 기록을 구별해 보존합니다.