복잡한 샤딩 DB 환경에서 안정적으로 데이터 이관하기

궁금하면 500원·2025년 12월 1일

미생의 개발 이야기

목록 보기
62/73

과거 사내 그룹웨어의 전자세금계산서 서비스를 개편하면서 진행했던 대규모 파일 데이터 마이그레이션 경험을 기록으로 남겨보려 합니다.

이번 작업은 단순히 데이터를 옮기는 것을 넘어, 레거시 시스템의 비효율을 개선하고 장기적인 운영 기반을 다지는 과정이었습니다.

포스팅은 총 두 편으로 나누어 진행할 예정이며, 오늘은 그 첫 번째 순서로 작업 배경과 Spring Batch를 선택하게 된 기술적 근거를 공유합니다.


1. 왜 마이그레이션을 해야 했나?

과거 저는 대학병원 임상실험 전자세금계산서 서비스 개편 업무를 담당했습니다.
이 과정에서 가장 큰 걸림돌이 되었던 것은 레거시 시스템의 비효율적인 파일 저장 구조였습니다.

1) 기존 시스템의 한계

기존 시스템은 파일의 종류를 DB 컬럼 내 0~3이라는 정수 값으로 관리했습니다.
시스템은 이 숫자에 따라 파일 시스템의 고정된 하드코딩 경로에서 파일을 읽어오는 방식이었습니다.

당시에는 최선의 선택이었을지 모르지만, 서비스가 성장하고 개편이 필요한 현시점에서는 다음과 같은 심각한 문제들이 있었습니다.

  • 확장성 부족: 정해진 파일 외에 커스텀 파일 첨부가 불가능합니다.
  • 클라우드 전환의 어려움: 현재는 Pod 내부 스토리지에 의존하고 있습니다.
    추후 S3와 같은 외부 스토리지 도입 시, 경로가 하드코딩된 현재 방식은 마이그레이션 비용을 크게 증가시킵니다.
  • 유지보수의 어려움: 0~3이라는 숫자가 무엇을 의미하는지 도메인 지식이나 별도 문서 없이는 파악하기 어렵습니다.
    또한 파일 메타데이터 관리가 안 되어 유효성 검증이나 부가 기능 구현이 불가능했습니다.

2) 개선 목표

따라서 다음과 같은 목표를 가지고 구조 변경을 결정했습니다.

  • 유연성 확보: 파일 관리 테이블을 정규화하여 메타데이터를 관리하고, 커스텀 파일 업로드를 지원합니다.
  • 운영 효율성: 파일 시스템 저장 방식을 유연하게 변경하여 추후 스토리지 변경에 대비합니다.

이 과정에서 기존에 0~3 값으로 매핑되어 저장된 파일들을 새로운 구조에 맞게 데이터 마이그레이션하고, 실제 물리적 파일 위치도 옮기는 작업이 필요해졌습니다.


2. 왜 스크립트가 아닌 Spring Batch인가?

일회성 마이그레이션 작업의 경우, 간단한 Shell ScriptSQL 프로시저를 사용하는 것이 일반적입니다.
실제로 팀 내에서도 기존에는 스크립트 방식을 주로 사용해왔습니다.
하지만 저는 이번 작업에서 Spring Batch 도입을 제안했고, 최종적으로 승인을 받았습니다. 그 이유는 다음과 같습니다.

이유 1. 복잡한 DB 토폴로지와 대용량 데이터 처리

저희 서비스의 DB 구조는 상당히 복잡합니다.

  • Sub-DB: 여러 호스트에 스키마가 파티셔닝되어 병렬로 구성됨
  • ASP-DB: 공통 데이터를 관리하는 중앙 DB

세금계산서 서비스의 특성상 누적 데이터 양이 방대하며, 수많은 호스트와 파티션에 데이터가 분산되어 있습니다.
이를 스크립트로 처리할 경우 다음과 같은 문제가 발생할 위험이 컸습니다.

  • 실패 복구의 어려움: 작업 중 네트워크 이슈나 타임아웃으로 실패할 경우, '어디까지 처리되었는지' 파악하기 어렵습니다.
  • 수동 작업의 위험성: 수많은 Host * Partition 조합에 대해 스크립트를 일일이 실행하고 로그를 확인하는 과정은 인적 실수를 유발할 수 있습니다.

Spring Batch를 사용하면 JobRepository를 통해 작업 상태를 자동으로 관리할 수 있습니다. 실패 시 재시작 기능을 통해 실패한 지점부터 작업을 이어서 수행할 수 있어 데이터 정합성을 보장하기 훨씬 유리하다고 판단했습니다.

이유 2. 병렬 처리를 통한 퍼포먼스 확보

앞서 언급한 N개의 Host * M개의 Partition 구조를 효율적으로 처리하기 위해서는 병렬 처리가 필수적입니다.
Spring Batch의 파티셔닝 기능을 활용하면 각 DB 파티션 별로 Job을 분배하여 동시에 처리할 수 있어 작업 시간을 획기적으로 단축할 수 있습니다.
(물론, 스토리지 I/O 부하를 고려한 쓰로틀링은 필요합니다.)

이유 3. 미래를 위한 투자

현재 저희 팀은 PHP 기반의 레거시를 Spring Framework로 전환하는 과도기에 있습니다.
이번 마이그레이션을 통해 구축한 배치 인프라는 일회용으로 끝나지 않습니다.

전자세금계산서 서비스는 도메인 특성상 배치 작업이 매우 중요합니다.

  • 역발행 요청 예약 전송
  • 국세청 자동 전송 및 가산세 방지 로직
  • 월말 거래 명세서 및 합계표 집계

이번 기회에 복잡한 DB 구조를 지원하는 배치 템플릿과 라이브러리를 구축해 둔다면, 향후 위와 같은 기능 도입 시 비즈니스 로직에만 집중할 수 있는 환경이 마련됩니다.
즉, 이번 마이그레이션은 미래의 생산성을 위한 '보일러 플레이트'를 만드는 작업이기도 합니다.


느낀점

[마치며: 코드를 넘어 '운영'을 고민하다]

개발 초기에는 단순히 "기능이 돌아가게 만드는 것"에만 급급했습니다.
하지만 이번 마이그레이션 업무를 진행하면서 처음으로 '내 코드가 운영 환경에서 어떻게 동작할까?', '실패했을 때 복구는 어떻게 하지?', '나중에 들어올 팀원이 이 코드를 이해할 수 있을까?' 라는 관점에서 고민해 볼 수 있었습니다.

단순히 스크립트로 빠르게 끝낼 수도 있었지만, 팀의 장기적인 생산성과 데이터의 안정성을 위해 Spring Batch 도입을 제안하고 설득했던 과정은 저에게 큰 자산이 되었습니다.
"왜 이 기술을 써야 하는가?"에 대해 스스로 근거를 찾고 답을 내리는 과정 자체가 개발자로서 한 단계 성장하는 계기가 된 것 같습니다.

물론 실제 구현 과정에서 겪은 시행착오들도 많았습니다.
그 치열했던 삽질(?)의 과정은 다음 포스팅에서 자세히 풀어보겠습니다.
긴 글 읽어주셔서 감사합니다!

profile
그냥 코딩할래요 재미있어요

0개의 댓글