#Backend

Spring 트랜잭션 동기화로 레거시 알림톡 발송 시스템 한계 넘어서기

Spring 트랜잭션 동기화로 레거시 알림톡 발송 시스템 한계 넘어서기
01

Summary

레거시 알림톡의 대변신! Spring 트랜잭션 동기화로 1,600만 고객의 신뢰를 지키는 법

비즈니스 로직과 알림 발송의 '완벽한 결별'을 통해 데이터 정합성과 개발 생산성을 동시에 잡은 기술 전환기

올리브영의 급성장하는 비즈니스 요구사항을 감당하기 위해, 파편화된 레거시 알림 시스템을 Kafka 기반 MSA 환경으로 전환한 과정을 다룹니다. 신입 엔지니어의 시선에서 겪은 기술적 제약 사항과 이를 해결하기 위한 트랜잭션 동기화 기법, 그리고 책임 분리를 통한 아키텍처 개선 과정을 상세히 공유합니다. 단순한 기능 구현을 넘어 시스템 설계의 본질과 안정적인 데이터 흐름을 고민하는 개발자들에게 실질적인 인사이트를 제공합니다.

  • 01복잡한 레거시 의존성 문제를 극복하기 위한 TransactionSynchronizationManager 활용 전략
  • 02Kafka 메시징을 통한 레거시와 모던 시스템 간의 안정적인 비동기 통신 구조 설계
  • 03데이터 일관성 확보를 위해 배송 유형별 공통 쿼리 및 통합 조회 기준 수립
  • 04비즈니스 로직 성공 후 발송을 보장하는 커밋 이후(After Commit) 콜백 메커니즘 구현
  • 0540여 종의 알림톡을 효율적으로 관리하기 위한 역할 중심의 서비스 분리

RECOMMENDATION

레거시 시스템을 점진적으로 MSA로 전환하고 있거나, 비즈니스 로직과 외부 연동 로직 사이의 데이터 정합성 문제로 고민하는 백엔드 엔지니어에게 적극 추천합니다. 특히 Spring 프레임워크 버전 제약으로 인해 최신 기능을 사용하기 어려운 환경에서 트랜잭션 커밋 시점을 제어하는 실용적인 대안을 제시합니다.

The Problem

기존 알림톡 시스템은 로직이 비즈니스 코드에 산재해 있어 수정이 어렵고, 데이터 조회 기준이 서비스마다 달라 일관성이 부족했습니다. 특히 비즈니스 로직과 발송 처리가 강하게 결합되어 있어, 발송 후 로직 오류 발생 시 데이터 상태와 안내 내용이 불일치하는 안정성 문제가 존재했습니다.

The Solution

Spring의 TransactionSynchronizationManager를 활용하여 비즈니스 트랜잭션 커밋 이후에만 Kafka 메시지를 발행하도록 콜백 구조를 구현했습니다. 이를 통해 레거시 시스템은 발송 시점만 결정하고, 모던 아키텍처 기반의 컨슈머가 메시지를 소비하여 배송 유형별 공통 쿼리 조회 및 발송 처리를 전담하도록 역할을 분리했습니다.

The Result

발송 로직이 모던 시스템으로 일원화되면서 새로운 알림톡 추가 시 템플릿과 시점만 등록하면 되는 간편한 구조가 완성되었습니다. 또한 데이터 상태와 알림 발송 간의 정합성이 확보되었으며, 산재해 있던 데이터 조회 기준을 통합하여 시스템의 일관성과 유지보수성이 크게 향상되었습니다.

Trade-off

초기에는 @TransactionalEventListener를 도입하려 했으나 레거시 환경의 프레임워크 버전 충돌 및 의존성 문제로 인해 TransactionSynchronizationManager를 활용한 차선책을 선택했습니다. 본문에 구체적인 한계는 없으나, 현재 구조는 메시지 발행 실패 시 로그 기반 재처리에 의존하므로 트랜잭션 아웃박스 패턴(Outbox Pattern) 대비 발행 보장 측면에서 상대적으로 완결성이 낮을 수 있습니다.

03

Key Concepts

Concept · 01

TransactionSynchronizationManager

Spring에서 트랜잭션의 생명주기에 맞춰 특정 작업을 동기화하거나 등록된 리소스를 관리하는 중앙 관리 클래스입니다.

  • 비즈니스 로직이 담긴 DB 트랜잭션이 성공적으로 커밋된 이후에만 Kafka 메시지를 발행하도록 콜백을 등록하는 데 사용되었습니다.
  • @TransactionalEventListener를 사용할 수 없는 하위 버전의 레거시 환경에서 안정적인 실행 시점을 보장하는 대안으로 활용되었습니다.
Concept · 02

Kafka Message-driven Architecture

메시지 브로커인 Kafka를 중심으로 시스템 간 이벤트를 주고받아 결합도를 낮추는 아키텍처 스타일입니다.

  • 레거시 시스템은 발송 트리거(Publisher) 역할만 수행하고, 실제 발송 처리는 컨슈머(Consumer)가 담당하도록 분리했습니다.
  • 메시지에는 주문번호와 유형 등 최소한의 정보만 담아 시스템 간 데이터 전송 부하를 최소화했습니다.
Concept · 03

Role Separation (SOC)

프로그램의 각 부분이 서로 겹치지 않는 별개의 관심사를 가지도록 기능을 분리하는 설계 원칙입니다.

  • 레거시에서는 '알림 전송 시점 결정'을, 컨슈머 서비스에서는 '데이터 구성 및 발송 API 호출'을 전담하게 했습니다.
  • 기능 분리를 통해 새로운 알림 유형 추가 시 기존 비즈니스 로직을 건드리지 않고도 확장이 가능한 구조를 구축했습니다.