DEV LOG 002 / DATA ENGINEERING

Oracle에서 DocumentDB로
옮기고, 계속 맞추기.

초기 마이그레이션부터 1분 주기 증분 동기화까지.
YAML 매핑과 워터마크로 정리한 Python ETL 개발 노트.

OracleAWS DocumentDBPythonYAML MappingIncremental Sync
이번 글의 질문

대량 데이터를 옮긴 다음,
변경분을 어떻게 이어받고
실패한 지점에서 다시 시작할까?

정규혁 · Development Notes마이그레이션 ETL기준 문서 · 2026.07.27
01 / PROJECT OVERVIEW

한 번 옮긴 뒤에도, 데이터는 계속 바뀐다

Oracle의 데이터를 DocumentDB로 옮기는 일은 첫 적재만으로 끝나지 않는다. 원본에 새 데이터가 생기거나 기존 값이 바뀌면, 대상 문서에도 그 변화가 이어져야 한다.

이 프로젝트는 초기 대량 마이그레이션주기적인 증분 동기화를 함께 제공한다. Oracle에서 행을 읽고, YAML에 정의한 규칙으로 문서 구조를 만든 뒤, DocumentDB에 저장한다. 새 테이블을 추가할 때도 공통 처리 코드를 복제하기보다 매핑 정의를 확장하는 구조다.

구분초기 마이그레이션증분 동기화
읽는 범위기존 데이터 전체수정 시각 기준의 변경 구간
실행 방식PK 해시로 분할해 병렬 적재스케줄러가 기본 60초 간격으로 실행
연결 지점시작 시 확보한 DB 기준 시각저장된 워터마크를 기준으로 다음 구간 조회
이 글의 범위

2026년 7월 27일 작성된 프로젝트 문서를 바탕으로 구조와 동작을 정리했다. 소스코드 실행 검증이나 운영 성능 측정 결과는 포함하지 않으며, 보완할 사항은 별도의 검토 항목으로 표시했다.

02 / ARCHITECTURE

실행 방법은 여러 개, 핵심 로직은 한 곳

CLI와 스케줄러는 실행 시점과 대상을 결정하고, 실제 ETL 처리는 services/sync.pyrun() 함수로 모은다. 향후 API를 붙이더라도 같은 처리 함수를 재사용하는 것이 문서의 핵심 설계 방향이다.

SHARED ETL CORE
수동·초기 실행CLI · run.py · migrate.py
주기 실행APScheduler · scheduler.py
services · 공통 동기화 / 마이그레이션 / 상태 관리
mappingYAML 로드 · 스키마 검증 · 문서 변환
dbOracle 배치 조회 · DocumentDB 쓰기
공통 설정 .env · 공통 로깅
계층 / 파일맡은 역할
config.pyPydantic Settings로 접속 정보·배치 크기·주기 검증
mapping/schema.py · loader.pyYAML 구조와 식별자 검증, 폴더별 작업 로드·캐시
mapping/transform.py컬럼명 변경, 타입 변환, 중첩 문서 구성
services/query.py · sync.py조회 조건 생성과 추출·변환·적재 실행
services/watermark.py대상 DB의 _sync_state에 동기화 지점 저장
services/migration.py · doctor.py초기 병렬 적재와 테이블·컬럼·인덱스 사전 점검
03 / INCREMENTAL SYNC

어디까지 반영했는지 기억하는 워터마크

워터마크는 마지막으로 성공한 동기화의 기준 시각이다. 매번 전체 테이블을 읽는 대신, 이전 기준점부터 이번 실행의 상한까지를 조회한다. 상한은 애플리케이션 시계 대신 Oracle의 SYSDATE로 확보한다.

증분 조회 조건 · 문서 기준
SELECT ... FROM T
WHERE UPDATED_AT > :wm_low
  AND UPDATED_AT <= :wm_high
ORDER BY UPDATED_AT

-- wm_low  = 저장된 워터마크 - overlap (기본 2초)
-- wm_high = 이번 조회 시작 시 Oracle SYSDATE
  1. 작업 정의와 이전 상태 읽기YAML을 로드하고 마지막 워터마크를 확인한다.
  2. 조회 구간 확정하기DB 시계로 상한을 고정하고, 하한은 설정한 시간만큼 되감는다.
  3. 배치 단위로 읽고 쓰기Oracle 행을 스트리밍으로 읽어 문서로 변환하고 bulk_write로 적재한다.
  4. 모두 성공한 뒤 기준점 이동하기모든 배치가 성공했을 때만 워터마크를 이번 상한으로 갱신한다.
실패하면 같은 구간을 다시 읽는다

중간 실패 시 워터마크를 유지하므로 다음 실행에서 같은 데이터를 다시 만날 수 있다. 따라서 안정적인 매칭 키를 가진 upsert가 재처리 설계의 전제가 된다.

검토 포인트: 2초 되감기는 경계 부근의 커밋 지연을 완화하는 설정이다. 의도적인 중복 조회가 발생하며, 이 범위를 넘는 지연까지 누락 없이 처리한다고 단정할 수는 없다. 수정 시각의 갱신 규칙과 실제 트랜잭션 지연을 확인해야 한다.

04 / YAML MAPPING

테이블별 차이는 YAML에 모으기

테이블, 기본키, 수정 시각 컬럼, 대상 컬렉션과 필드 변환 규칙을 YAML에 정의한다. 지원되는 매핑 범위 안에서는 테이블별 Python 코드를 늘리지 않고 설정으로 변경을 관리할 수 있다.

customer.yaml · 문서의 매핑 구조를 정리한 예시
job_name: customer
source:
  table: SCOTT.CUSTOMER
  primary_key: [CUST_ID]
  updated_column: UPDATED_AT
target:
  collection: customers
  write_mode: replace
fields:
  CUST_ID: { to: _id, type: string }
  CUST_NM: { to: name, type: string }
  BALANCE: { to: balance, type: decimal }
  ZIP_CD: { to: address.zipCode, type: string }

CUST_ID는 문서의 _id로, CUST_NMname으로 바뀐다. address.zipCode처럼 점 표기를 사용하면 중첩 문서로 구성한다. 금액은 Decimal128으로 변환하는 규칙을 제공한다.

매핑 기능사용 방식
타입 변환string / int / float / bool, decimal, date / datetime, json, raw
소스 모드단순 table 또는 조인·집계 등을 담는 sql
그룹 구분폴더명으로 작업을 구분해 main-data.customer 같은 이름 사용
자동 매핑fields를 생략하면 SELECT *와 원본 컬럼명을 사용
로드 제외이름이 _로 시작하는 파일·폴더는 공용 조각 또는 초안으로 제외

예시의 테이블과 고객 필드는 구조 설명용이다. 실제 스키마에 맞춰 매핑 결과를 preview로 확인한 뒤 적재한다.

05 / WRITE & RETRY

replace와 merge, 무엇을 보존할 것인가

쓰기 방식은 대상 문서의 필드를 누가 관리하는지에 따라 선택한다. 원본 테이블이 문서 전체의 기준이라면 replace, 다른 처리 과정이 채운 필드를 함께 유지해야 한다면 merge를 검토한다.

쓰기 방식문서의 동작확인할 점
replaceReplaceOne + upsert로 문서 전체 교체대상에만 존재하는 필드도 교체 범위에 포함
mergeUpdateOne의 $set + upsert로 지정 필드 반영매핑에서 빠진 기존 필드는 남을 수 있음
PK 없는 작업InsertOne으로 삽입동일 구간 재실행 시 중복 삽입 가능

여러 문서는 bulk_write(..., ordered=False)로 묶어 쓴다. 문서에서는 부분 오류를 BulkWriteError로 수집하고 성공·실패 건수를 결과에 남기도록 설명한다. 일부 쓰기가 성공해도 전체 배치가 성공하지 않았다면 워터마크는 전진하지 않는다는 원칙이 중요하다.

재실행이 안전하려면

같은 원본 행이 항상 같은 키로 매칭되어야 한다. PK를 _id로 매핑하는 방식을 우선 검토하고, 키가 없는 집계·리포트 작업은 별도의 중복 방지 또는 재적재 정책을 정해야 한다.

06 / INITIAL MIGRATION

대량 적재에서 증분 처리로 이어가기

초기 적재는 시작 시점의 DB 시각을 먼저 확보하고, 기본키 해시로 데이터를 나누어 워커별로 읽는다. 문서의 분할 조건은 MOD(ORA_HASH(pk), N) = i다. 각 워커가 서로 다른 행 집합을 맡으며 OFFSET 방식의 페이지 순회를 사용하지 않는다.

  1. 시작 기준 시각 확보초기 적재가 진행되는 동안의 변경을 후속 증분 조회로 이어받을 기준점을 만든다.
  2. 샤드별 병렬 적재PK 해시로 나눈 데이터를 공통 변환·쓰기 흐름으로 저장한다.
  3. 적재 후 인덱스 구성문서는 인덱스 유지 비용을 줄이기 위해 적재 후 생성을 설명한다. 필수 키·제약조건의 적용 시점은 실제 구성에서 확인한다.
  4. 전체 성공 후 증분 동기화 시작실패한 샤드가 있으면 새 워터마크를 설정하지 않는다. 성공한 경우 시작 기준 시각부터 변경분을 이어서 반영한다.

검토 포인트: 해시 분할 자체가 조회 성능이나 일관된 스냅샷을 보장하지는 않는다. 실제 실행 계획과 원본 DB 부하, 초기 적재 중 변경·삭제가 발생했을 때의 결과를 확인할 필요가 있다.

07 / OPERATIONS

실행 전 확인부터 운영 관찰까지

바로 전체 데이터를 옮기기보다 연결과 스키마를 점검하고, 소량의 변환 결과를 확인한 뒤 초기 적재와 스케줄러를 순서대로 실행한다.

CLI 실행 순서 · 첨부 문서 기준
py -m app.cli check
py -m app.cli jobs
py -m app.cli doctor customer
py -m app.cli preview customer -n 3

# 초기 전체 적재 → 주기적 증분 동기화
py migrate.py customer -w 4
py -m app.cli scheduler

# 상태 확인
py -m app.cli state customer

문서의 py 명령 표기를 유지했다. 실행 환경에 따라 가상환경의 Python 실행 파일로 바꾸고, 작업 이름은 jobs 출력에서 확인한다.

주요 설정문서 기본값설계 의도
batch_size2,000행한 번에 읽고 쓰는 배치 크기
oracle_arraysize5,000Oracle fetch 관련 설정
watermark_overlap_seconds2초조회 하한을 되감아 경계 지연 완화
scheduler_interval_seconds60초증분 처리 실행 간격

Oracle 연결은 풀로 재사용하며 결과를 배치 스트리밍으로 읽는다. DocumentDB 연결은 문서상 retryWrites=false와 TLS CA 설정을 사용한다. 접속 정보는 환경 설정으로 분리한다.

운영 결과에 남길 값

SyncResult에는 읽은 행 수, upsert·수정·매칭 건수, 배치 수, 실패 수, 조회 구간, 소요 시간과 오류 목록이 포함된다. 처리 시간뿐 아니라 워터마크가 계속 전진하는지와 실패 후 재처리가 정상 종료되는지를 함께 살펴볼 수 있다.

동일 프로세스 안에서는 작업별 threading.Lock으로 중복 실행을 막고, 스케줄러에는 max_instances=1, coalesce=True를 적용하는 구성이다. 여러 프로세스나 서버에서 실행할 경우에는 이 잠금 범위와 별도로 조정 방식을 검토해야 한다.

08 / REVIEW NOTES

운영 전에 더 확인할 네 가지

다음은 문서의 설계를 바탕으로 정리한 추가 검토 항목이다.

  1. 삭제는 별도의 반영 규칙이 필요하다물리 삭제된 행은 수정 시각 조회로 읽을 수 없다. 소프트 삭제를 쓰더라도 DEL_YN = 'N'으로 필터링하면 삭제 상태로 바뀐 행이 제외되어 대상 문서가 남을 수 있다. 삭제 상태 전달 또는 대상 정리 절차를 함께 설계한다.
  2. 변경 조회 인덱스와 실행 계획을 확인한다문서는 UPDATED_AT 인덱스를 필수 점검 항목으로 둔다. 상수 조건과 사용자 정의 SQL이 더해졌을 때도 실제 조회 비용이 적절한지 확인한다.
  3. 중복 재처리와 늦은 커밋을 함께 시험한다배치 중간 실패, 같은 키의 재등장, overlap을 넘는 지연 상황에서 대상 데이터와 워터마크를 대조한다.
  4. 성능은 실제 데이터로 측정한다워커 수와 배치 크기를 바꿔 소요 시간·메모리·원본 DB 부하를 비교한다. 문서의 소량 실행 예시는 운영 처리량을 나타내는 벤치마크가 아니다.

다음 확장: API에서도 같은 로직 호출하기

문서는 FastAPI에서 공통 sync.run()을 호출하는 방안을 향후 확장으로 제안한다. 동기 드라이버를 고려한 실행 방식과 스케줄러 수명주기 연동이 포함되며, 구현 완료된 기능으로 소개하지는 않는다.

DEVELOPMENT NOTE

옮기는 로직과, 다시 시작하는 기준을 함께 설계하기.

이 ETL의 중심은 YAML 매핑, 공통 처리 함수, 그리고 성공한 쓰기를 기준으로 움직이는 워터마크다. 변경 조회와 재처리의 경계를 명확히 해야 초기 이관 이후에도 데이터 흐름을 이어갈 수 있다.

참고 문서

「SBSI 신규 ETL jobs — Oracle → AWS DocumentDB ETL 프로젝트 구조 및 개발 로직 문서」, made by kyuhuck, 2026.07.27.

프로젝트 문서의 구조·매핑·실행 절차를 재구성했으며, 운영상 보완 의견은 ‘검토 포인트’와 이 절에서 구분했다.

KH
정규혁데이터를 연결하고, 개발 과정을 기록합니다.