레거시 결제 원장을 확장 가능한 시스템으로 (새 탭에서 열림)
토스페이먼츠는 20년 된 레거시 결제 원장의 구조적 한계와 도메인 간 강한 결합을 해결하기 위해 MySQL 기반의 신규 원장 시스템을 구축했습니다. 데이터 불변성을 보장하는 INSERT-only 원칙과 이벤트 기반 아키텍처를 도입하여 복합 결제 지원 등 비즈니스 확장성을 확보했습니다. 이 과정에서 발생한 데이터 불일치와 타임아웃 문제를 해결하며 시스템의 자가 회복 능력을 강화하고 안정적인 운영 환경을 마련했습니다.
레거시 원장 시스템의 한계와 과제
- 데이터 구조의 불일치: 결제수단별로 테이블 구조가 다르고, 동일한 성격의 데이터가 서로 다른 테이블에 저장되어 유지보수와 온보딩에 큰 비용이 발생했습니다.
- 도메인 간 강한 결합: 결제, 정산, 회계 등 여러 서비스가 하나의 원장 테이블과 컬럼을 공유하여, 작은 기능 수정 시에도 전사적인 영향도 분석이 필요했습니다.
- 구조적 확장성 부족: 결제와 결제수단이 1:1 관계로 묶여 있어, 더치페이나 복합 결제(카드+포인트)와 같은 현대적인 결제 시나리오를 지원할 수 없었습니다.
신규 원장 설계의 3가지 전략
- 데이터 불변성과 일관성: 모든 승인 내역을 공통 테이블(
approve)에 저장하고, 수정 대신 INSERT-only 방식을 채택하여 데이터의 정합성을 높이고 데드락을 방지했습니다. - 이벤트 기반의 도메인 분리: 각 도메인이 직접 DB를 조회하는 대신 Kafka 이벤트를 구독하여 데이터를 처리하게 함으로써 도메인 간 의존성을 제거했습니다.
- 결제와 승인 개념의 분리: '결제'는 주문의 상태를, '승인'은 실제 결제수단의 실행을 의미하도록 분리하여 하나의 결제에 여러 승인 수단이 연결될 수 있는 유연한 구조를 만들었습니다.
무중단 마이그레이션 및 정합성 검증
- 비동기 점진적 적재: 실서비스 장애를 방지하기 위해 기존 원장에 먼저 저장한 후, 신규 원장에는 별도의 ThreadPool을 통한 비동기 방식으로 데이터를 적재했습니다.
- 검증 배치 운영: 비동기 적재 중 발생할 수 있는 누락을 방지하기 위해, 매 5분마다 Read-Only DB를 기반으로 기존 원장과 신규 원장의 데이터를 비교하고 보정하는 배치를 실행했습니다.
- 고성능 이관 작업: 수억 건의 데이터 이관을 위해 Bulk Insert를 도입하고, 네트워크 지연 최소화를 위해 마이그레이션 서버를 DB와 동일한 가용 영역(AZ)에 배치했습니다.
운영 중 장애 대응과 시스템 고도화
- 쿼리 최적화: 옵티마이저의 판단 오류로 발생한 풀 스캔(Full Scan) 문제를 인덱스 힌트(Index Hint) 추가와 롤백 시스템을 통해 빠르게 해결했습니다.
- 타임아웃 및 정합성 관리: MSA 구조에서 서버 간 타임아웃 설정을 일치시키고, 외부 원천사와의 상태 불일치를 해결하기 위한 망취소(Network Cancellation) 로직을 강화했습니다.
- 이벤트 처리의 신뢰성: 아웃박스(Outbox) 패턴과 로그 기반 복구를 통해 이벤트 누락을 방지하고, 헤더에 멱등키를 포함해 중복 이벤트 처리 문제를 해결했습니다.
신규 시스템으로의 전환은 단순한 DB 교체가 아니라 시스템의 지속 가능성을 확보하는 과정입니다. 초기 설계의 완벽함보다 중요한 것은 운영 중 발생하는 예외 상황에 시스템이 스스로 대응하고 회복할 수 있는 '자가 회복 구조'를 갖추는 것이며, 이를 위해 데이터 보정 배치와 로깅 시스템 같은 안전장치를 반드시 고려해야 합니다.