컬리가 3PL(Third-Party Logistics) 사업 확장에 따라 외부 채널에서 입고 예정 정보를 안전하게 동기화해야 하는 기술적 요구사항(Technical Requirement) 발생
아웃박스 패턴(Outbox Pattern)을 도입하여 DB 쓰기와 메시지 발행 간의 원자성(Atomicity) 보장 및 데이터 정합성(Data Consistency) 확보
Namastack Outbox for Spring Boot 라이브러리를 활용하여 아웃박스 패턴 구현의 복잡성(Complexity) 감소 및 개발 생산성 향상
Spring Kafka의 RetryableTopic을 활용하여 메시지 처리 실패 시 자동 재시도(Automatic Retry) 및 데드 레터 큐(Dead Letter Queue) 처리
아웃박스 패턴과 재시도 토픽 적용을 통해 외부 채널 입고 정보 동기화 시스템의 안정성(Stability) 및 운영 효율성(Operational Efficiency) 증대
본문에서는 외부 채널에서 수신된 입고 예정 정보를 데이터베이스(Database)에 저장하고, 카프카(Kafka) 메시지를 발행하는 과정에서 발생할 수 있는 데이터 불일치 문제를 해결하기 위해 아웃박스 패턴(Outbox Pattern)을 도입했다고 설명한다.
DB 쓰기(DB Write)와 메시지 발행(Message Publishing)의 원자성(Atomicity) 보장: 아웃박스 패턴은 두 작업을 하나의 트랜잭션(Transaction)으로 묶어, 둘 중 하나라도 실패하면 전체 작업을 롤백(Rollback)하여 데이터 정합성을 유지한다.
Namastack Outbox for Spring Boot: 아웃박스 테이블 관리, 폴링(Polling) 스케줄링, 재시도 횟수/상태 관리 등을 라이브러리에 위임하여 개발자가 직접 구현해야 하는 부담을 줄였다.
결론: 아웃박스 패턴은 분산 환경에서 데이터 일관성을 유지하기 위한 효과적인 방법이며, 특히 메시지 큐(Message Queue)를 사용하는 시스템에서 유용하다.
컬리는 아웃박스 패턴 구현을 위해 Namastack Outbox for Spring Boot 라이브러리를 사용했다. 이 라이브러리는 아웃박스 패턴 구현에 필요한 다양한 기능을 제공하여 개발 생산성을 향상시켰다.
간편한 설정: build.gradle에 의존성을 추가하고, application.yml에 아웃박스 관련 설정을 추가하는 것만으로 아웃박스 패턴을 적용할 수 있다.
자동화된 기능: 아웃박스 테이블 관리, 폴링(Polling) 스케줄링, 재시도 횟수/상태 관리 등을 자동화하여 개발자가 직접 구현해야 하는 부분을 최소화했다.
테이블 생성: DDL 권한이 없는 환경을 고려하여, 아웃박스 테이블을 수동으로 생성하는 방법을 제공한다.
결과적으로, Namastack Outbox for Spring Boot는 아웃박스 패턴 구현을 위한 보일러플레이트(Boilerplate) 코드를 줄이고, 핵심 비즈니스 로직(Business Logic)에 집중할 수 있도록 돕는다.
컬리는 Spring Kafka의 RetryableTopic 기능을 활용하여 메시지 처리 실패 시 자동 재시도 및 데드 레터 큐(Dead Letter Queue, DLT) 처리를 구현했다. 이를 통해 시스템의 안정성을 높이고, 운영 효율성을 향상시켰다.
자동 재시도(Automatic Retry): 메시지 처리 실패 시, 설정된 간격(10분)으로 최대 144회까지 재시도를 수행하여 일시적인 오류로 인한 메시지 유실을 방지한다.
데드 레터 큐(Dead Letter Queue, DLT) 처리: 재시도 횟수를 모두 소진한 메시지는 DLT로 전송하여, 관리자가 문제 발생 원인을 파악하고 수동으로 처리할 수 있도록 한다.
Spring Kafka RetryableTopic: 기존 컨슈머 로직에 어노테이션(@RetryableTopic)을 추가하는 것만으로 재시도 토픽을 구성할 수 있어, 구현의 편의성을 높였다.
이러한 재시도 토픽(Retry Topic) 도입은 메시지 처리 실패로 인한 데이터 유실(Data Loss) 위험을 줄이고, 시스템의 자가 치유 능력(Self-Healing Capability)을 향상시키는 데 기여한다.
컬리는 아웃박스 패턴과 재시도 토픽을 결합하여 외부 채널에서 수신되는 입고 예정 정보의 안정적인 동기화를 구현했다. 이 두 기술의 조합은 데이터 일관성(Data Consistency)을 보장하고, 시스템의 자가 치유 능력을 향상시키는 시너지를 창출한다.
아웃박스 패턴: DB 쓰기와 메시지 발행의 원자성을 보장하여 데이터 불일치 문제를 해결한다.
재시도 토픽: 메시지 처리 실패 시 자동 재시도를 통해 일시적인 오류를 극복하고, 데드 레터 큐(DLT)를 통해 문제 발생 시 관리자에게 알림을 제공한다.
결합 효과: 아웃박스 패턴은 메시지 발행의 신뢰성을 높이고, 재시도 토픽은 메시지 처리의 안정성을 높여, 전체 시스템의 데이터 동기화 프로세스를 견고하게 만든다.
결과적으로, 이 두 기술의 결합은 외부 채널에서 수신되는 입고 예정 정보의 정확성(Accuracy) 및 신뢰성(Reliability)을 극대화한다.
컬리는 아웃박스 패턴과 재시도 토픽을 도입하면서, 시스템 아키텍처(System Architecture) 설계에 대한 깊이 있는 고민을 보여주었다. 특히, 발행부와 수신부의 책임을 명확히 분리하는 데 중점을 두었다.
책임 분리: 발행부는 아웃박스 패턴을 통해 메시지를 안전하게 내보내는 데 집중하고, 수신부는 수신된 메시지를 처리하며 자신의 재시도 상태를 스스로 관리하도록 설계했다.
직접 구현 vs 라이브러리 활용: 스케줄링 배치(Batch) 잡을 직접 작성하는 대신, 검증된 라이브러리(Namastack Outbox, Spring Kafka)를 활용하여 개발 생산성을 높였다.
3PL 사업의 본질적인 비즈니스 로직(Business Logic) 집중: 아키텍처 설계에 대한 고민을 통해, 3PL 사업의 핵심 가치에 집중할 수 있는 기반을 마련했다.
이러한 설계 결정은 시스템의 유지보수성(Maintainability) 및 확장성(Scalability)을 향상시키고, 비즈니스 요구사항(Business Requirements)에 유연하게 대응할 수 있도록 돕는다.