컬리, 아웃박스 패턴과 재시도 토픽으로 입고 데이터 동기화 문제 해결!

by DD
4개월 전
조회수 28

컬리가 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) 증대

아웃박스 패턴(Outbox Pattern)을 통한 데이터 정합성 확보

본문에서는 외부 채널에서 수신된 입고 예정 정보를 데이터베이스(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 라이브러리 활용

컬리는 아웃박스 패턴 구현을 위해 Namastack Outbox for Spring Boot 라이브러리를 사용했다. 이 라이브러리는 아웃박스 패턴 구현에 필요한 다양한 기능을 제공하여 개발 생산성을 향상시켰다.

간편한 설정: build.gradle에 의존성을 추가하고, application.yml에 아웃박스 관련 설정을 추가하는 것만으로 아웃박스 패턴을 적용할 수 있다.

자동화된 기능: 아웃박스 테이블 관리, 폴링(Polling) 스케줄링, 재시도 횟수/상태 관리 등을 자동화하여 개발자가 직접 구현해야 하는 부분을 최소화했다.

테이블 생성: DDL 권한이 없는 환경을 고려하여, 아웃박스 테이블을 수동으로 생성하는 방법을 제공한다.

결과적으로, Namastack Outbox for Spring Boot는 아웃박스 패턴 구현을 위한 보일러플레이트(Boilerplate) 코드를 줄이고, 핵심 비즈니스 로직(Business Logic)에 집중할 수 있도록 돕는다.

재시도 토픽(Retry Topic)을 이용한 메시지 처리 안정성 확보

컬리는 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)에 유연하게 대응할 수 있도록 돕는다.

컬리의 입고 시스템이 외부 인입 데이터를 안전하게 동기화하는 방법