안녕하세요. 신입 개발자로 입사한 지 벌써 9개월 정도가 되었습니다.
오늘은 최근 사내에서 진행한 마이그레이션 업무에 대해 간단히 기록 겸 남겨보려고 합니다.
아마 총 두 편의 포스팅으로 이뤄질 것 같고, 오늘은 작업 설명과 기술 선택에 대한 근거를 작성해보려고 합니다.
글이나 내용적으로 부족한 면이 있을 수 있습니다.
언제든지 지적 혹은 피드백을 주신다면 꼭 확인하고 더 나은 개발자로 성장하도록 하겠습니다. 🙇🏻♂️
1. 작업 개요
현재 그룹웨어를 만드는 업무를 진행하고 있고, 그 중에서 전자세금계산서 개발 관련 업무를 진행하고 있습니다.
세금계산서 서비스 개편 업무를 진행하면서 기존 기능의 비효율적인 면을 개선하며 레거시 프로젝트를 개선하는 작업을 주로 하고 있습니다.
현재 레거시 프로젝트에선 파일 저장이 굉장히 비효율적인 구조로 되어 있습니다.
예를 들어 파일 종류에 따라서 column에 0~3의 값으로 관리하고, db에 저장된 값에 따라 파일 시스템의 고정된 위치에서 파일을 가져오는 방식이었습니다.
당시에는 합리적인 이유가 있어서 해당 방식을 선택했겠지만, 개편을 하는 지금 시점에선 여러 문제점이 있기 때문에 구조적 변경을 하기로 결정 했습니다.
파일 저장 방식을 바꾸는 이유
(1) 개편 버전에서는 정해진 파일(ex. 사업자 등록증)이 아닌 커스텀 파일도 올릴 수 있어야 합니다.
(2) 현재는 Pod에 파일을 업로드하지만, 커스텀 파일이 많아지는 경우, 외부 이미지 스토리지를 쓸 수가 있고 그 시점에 마이그레이션을 고려했을 땐 현재와 같은 방식은 마이그레이션이 복잡해질 가능성이 높습니다. 또한 프로덕션의 코드도 변경을 해야합니다.
(3) 0~3의 값으로 관리하는 현재 방식은 해당 각 값에 대한 지식이 없는 개발자에겐 각 숫자가 무엇을 의미하는지 문서가 없으면 파악하기 힘들고, 파일 메타데이터 관리와 그 데이터를 바탕으로 제약 혹은 다른 기능을 도입할 수가 없습니다.
따라서 요구사항을 준수하고 장기적인 유지보수를 위해 새로운 파일 관리 테이블을 추가하고, 파일 시스템에 저장하는 방식도 변경을 했습니다.
파일 마이그레이션 작업
사용자가 구조 변경 이후에도 기존 파일을 사용할 수 있어야 했기 때문에, 기존에 저장된 0~3의 파일에 해당하는 레거시 column 값을 바탕으로 파일 마이그레이션을 진행하고, row를 추가해줘야 했습니다.
2. 마이그레이션으로 Spring Batch 기술을 선택한 이유
같이 업무를 진행하시는 사수 분에게 여쭤봤을 때, 기존에는 스크립트를 작성해서 마이그레이션을 진행하셨다고 하셨습니다.
사실 간단한 1회성 마이그레이션 작업은 스크립트로 작성해도 충분하다고 생각합니다. 다만, 기존 문제처럼 실패 시 데이터 유실과 정합성이 깨질 수 있다는 문제점에서 추가적으로 아래와 같은 이유로 Spring Batch 도입을 말씀드렸고, 최종적으로 작업 승낙을 받았습니다.
1. 레거시 데이터의 수
저희 회사는 아래 이미지와 같은 구조로 DB가 구성되어 있습니다.

크게 보면 sub-db와 asp-db로 이뤄져있습니다.
sub-db의 경우 호스트(인스턴스)에 Schema가 파티셔닝 된 방식으로 존재를 하고 이런 구조가 병렬로 구성되어 있습니다.
asp-db는 서비스의 공통적인 것(ex. 미회원 사용자를 대상으로 한 역발행 요청 건 등등)을 공유하는 하나의 호스트라고 보시면 됩니다.
세금계산서 서비스가 오래 됐기 때문에, schema에 존재하는 세금계산서 데이터의 수가 많습니다.
이를 스크립트를 통해 마이그레이션을 진행한다면 데이터베이스 호스트 연결도 번거롭고, 실패가 발생했을 때 어디서부터 실패 했는지 로그를 확인하고 그 부분부터 다시 하나 하나 작업을 진행해주는 번거로움이 생깁니다. 즉 재처리도 없고 sub_db와 partition별 단발성 작업을 진행하기 때문에 실수할 여지도 생기고, 작업 자체도 굉장히 오래 걸립니다.
Spring Batch를 통해 { Host N개 * Partition M개 } NM개의 Job으로 두고 마이그레이션을 진행한다면 이런 문제를 해결할 수가 있게 됩니다.
물론 병렬 처리의 경우 Row Bulk Insert는 큰 문제가 없지만, 파일 스토리지에서 많은 작업을 견딜 수 있는지 확인이 필요하긴 합니다. 다만, 확실한 건 Timeout이나 다른 문제가 생긴 경우 재처리와 동일 Job Parameter 기준으로 재실행을 통해 스크립트와 같이 수동적으로 처리하는 방식의 비효율적인 면은 피할 수 있다고 생각했습니다.
2. 새로운 기능을 위한 안정적인 운영을 위한 작업 준비
아직은 부족하지만, 업무를 진행하다보니 세금계산서에 대한 전반적인 이해와, 왜 기업에서 세금계산서를 작성하고 발급하는지, 왜 우리 서비스를 쓰면 좋은 지에 대해서도 자연스럽게 업무를 통해 알게 되었습니다.
그러다보니 "사용자 입장에선 어떤 기능이 있으면 참 좋겠다."라는 생각을 가끔씩 합니다.
(1) 정해진 날짜에 공급자에게 역발행 요청을 예약하는 것이 있을 수도 있고,
(2) 사용자 설정에 따라 가산세를 물기 전에 작성한 정발행 문서를 자동으로 국세청에 발급해주는 것도 있고,
(3) 매달 말에 사용자의 거래 내역을 바탕으로 명세서를 만들어서 거래처 별 합계표 및 매출 관리 장부를 만들어 보내주는 기능도 있을 것 같습니다.
물론 기획적으로 안되는 것이 있을 수도 있지만, 도입이 된다면 사용자들의 서비스 만족감이 높아질 것이고 더욱 많은 사용자들이 유입이 될 수도 있을 거라고 생각합니다.
어쨋든 PHP에서 스프링 프레임워크 기반으로 넘어가고 있는 저희 팀에서 추후 이런 기능들이 도입 됐을 때 MVC로 처리할 순 있겠지만, Spring Batch도 여러 가지 장점을 봤을 때 충분히 고려할 수 있을 것이라고 생각했습니다.
만약 나중에 도입했을 경우, 세금계산서의 경우 DB 구조가 복잡하기 때문에 (N개의 sub-db와 M개의 partition, 전체가 바라보는 1개의 asp-db) DataSource를 동적으로 설정하는 것과 테스트 소스 설정, Lock 제어 등등 많은 부분에 대해 다시 만들고 시간도 오래 걸릴 거라고 생각합니다.
따라서 이번 마이그레이션 작업을 하면서 추가적으로 세금계산서 서비스 특성에 맞는 보일러 템플릿을 만들거나, 라이브러리를 만들어서 나중에는 로직 작성에만 집중할 수 있도록 겸사겸사 진행하려고 합니다.
이런 이유로 현재 작업에서 Spring Batch를 사용하는 것으로 결정했습니다.
다음 포스팅에선 작업 방식에 대해 작성하도록 하겠습니다! 감사합니다.
글이나 내용적으로 부족한 면이 있을 수 있습니다.
언제든지 지적 혹은 피드백을 주신다면 꼭 확인하고 더 나은 개발자로 성장하도록 하겠습니다. 🙇🏻♂️
'Backend' 카테고리의 다른 글
| [Spring] 외부 API를 호출할 때 주의할 점에 대해서 (1) | 2025.09.16 |
|---|---|
| [Spring] MySQL을 이용한 중복 발급 방지와 동시성 해결 이야기 (멱등성, 분산락) (1) | 2025.09.10 |
| [Kafka] Kafka 개념을 훑어보고, 주의할 점에 대해서 가볍게 알아보자 (1) | 2025.07.15 |