파일 기반 배치형 CDC와 멱등 UPSERT
파일 단위 binlog를 직접 파싱하고, 정상 변환된 DML을 멱등 UPSERT로 적용하도록 바꿨습니다.
작업 요약
파일당 처리 속도 평균 2.5배 · 최대 5배
재시도를 멱등하게 만든 이유
레거시 동기화의 단위는 binlog 파일 전체였습니다. 파일 안의 이벤트 하나가 실패해도 파일 전체가 막히고, 적용된 범위는 stderr 텍스트를 세어 추정해야 했기 때문에 정확한 복구 위치를 찾기 어려웠습니다. 품질 개선 회의에서 CDC 구조 전환을 직접 제안한 이유입니다.
정상 변환된 INSERT·UPDATE에 한해 UPSERT로 적용했습니다. DELETE·DDL과 truncation skip은 이 보장에 포함하지 않았으며, 파일 전체를 데이터 손실 없이 재실행할 수 있다는 보장은 없습니다.
배경
레거시(v2/v3) Updater는 mysqlbinlog 유틸리티를 파이프로 실행해 binlog를 대상 DB에 그대로 적용하는 방식이었습니다. SQL을 제어할 수 없으니 중복 키 에러가 나면 수동 개입이 필요했고, DEFINER 절·Virtual Column처럼 고객사 환경에서 깨지는 구문도 거를 수 없었습니다. 일부 고객사는 MySQL replica 방식의 상시 TCP 연결을 허용하지 않아, 기존 HTTPS 파일 배포 경계를 유지한 채 변경분을 전달해야 하는 제약도 있었습니다.
Before
파일 단위 All-or-Nothing 리플레이 → 이벤트 하나의 실패가 파일 전체를 막음, 중복 적용 시 에러, 복구 위치 추적 불가After
배치 binlog 파일 → Go Updater 오프라인 파싱 → 정상 변환된 INSERT·UPDATE를 UPSERT로 적용해 재실행 시 중복 반영 방지한 일
- Go Updater의 오프라인 binlog 파싱 — ROW-format 배치 로그와 MySQL 8.4의 ZSTD-compressed
Transaction_payload를 풀어 고객사 환경에서 처리 - 정상 변환된 DML을 UPSERT로 적용 — INSERT·UPDATE를 매개변수화해, 같은 파일을 다시 실행해도 정상 변환된 범위에서는 중복 반영되지 않도록 변경
- HTTPS 파일 전달 경계 유지 — 고객사 on-premise 환경의 상시 TCP 복제 대신 Python/FastAPI 다운로드 서버가 AES-256-GCM으로 암호화한 배치 파일을 제공하고, Go Updater가 무결성을 검증한 뒤 복호화
- 도구 비교와 PoC로 제약 확인 — Debezium·Maxwell·Canal·custom parser를 비교하고 Maxwell FileSink에서 DML·DDL JSON 출력을 확인했지만, MySQL 8.4 ZSTD payload 미지원으로 운영 경로에서 제외
- 재실행 보장 범위를 명시 — 멱등 재실행 보장은 정상 변환된 DML로 한정하고, truncation error 110 skip은 후속 대상 정합성 확인이 필요한 대상으로 구분
아키텍처 (데이터 흐름)
파일 배포 경계를 바꾸지 않은 채 Go Updater의 오프라인 파싱과 DML 변환을 적용했습니다. 재실행 안전성은 정상 변환된 INSERT·UPDATE 범위이며, truncation skip은 별도 정합성 확인이 필요합니다.
결과
역할
파일 단위 동기화의 한계를 검토해 CDC 구조 전환을 제안하고 설계·구현과 배포 시나리오 리뷰를 마친 뒤, 고객사 배포는 기술지원팀에 이관했습니다. 도구 선정 단계에서 Maxwell은 FileSink PoC로 DML·DDL JSON 출력을 확인했지만, 공식 MySQL sink가 없고 MySQL 8.4의 ZSTD 압축 Transaction_payload를 처리하지 못해 제외했습니다. HTTPS 파일 전달 방식은 유지하면서, 기존 난독화를 AES-256-GCM 암호화와 수신 측 검증으로 바꿨습니다. 기술지원팀은 고객사 현장 배포와 일상 운영을 맡고, 저는 운영 중 접수된 이슈를 재현해 구현을 개선하고 기술 지원을 제공했습니다.
근거 자료
아래 기록에 근거해 정리했습니다. 내부 원문 경로를 표시하며, 비공개 원문 파일은 이 페이지에서 제공하지 않습니다.
ai/sources/career/interviews/2026-09-03-general-numbers-01.mdai/wiki/people/career-timeline.mdai/wiki/projects/bts.mdai/worklog/2026/2026-W29.mdai/sources/career/2026-09-21-portfolio-evidence-refresh.md