AI Briefing

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

·2026.01.12 00:00

Outbox 패턴과 재시도로 외부 입고 예정 정보를 안전하게 동기화한다.

컬리는 1P 중심 구조에서 3PL 확장으로 전환하면서, 외부 파트너사로부터 들어오는 입고 예정 정보를 안전하게 동기화해야 했다. 내부에서만 생성되던 데이터와 달리, 이제는 다양한 외부 채널의 서로 다른 규격을 받아 처리해야 한다는 점이 핵심 과제가 됐다.

기존 구조는 수신 데이터 저장과 Kafka 메시지 발행을 하나의 트랜잭션으로 묶는 방식이었다. 하지만 다음과 같은 실패 지점이 남아 있었다.

  • 메시지는 발행됐지만 DB 커밋이 실패해 원자성이 깨지는 경우
  • 컨슈머는 메시지를 읽었지만, 파트너 정보나 상품 정보가 아직 준비되지 않아 최종 생성에 실패하는 경우

이 문제를 풀기 위해 Outbox 패턴을 도입했다. 수신한 데이터는 먼저 인터페이스 테이블에 저장하고, 발행할 메시지는 바로 보내지 않고 outbox_record 테이블에 적재한다. 이후 별도의 Poller가 outbox를 읽어 Kafka로 발행하고, 성공한 레코드는 중복 발행되지 않도록 상태를 마킹한다.

구현 부담을 줄이기 위해 Namastack Outbox for Spring Boot 0.3.0을 사용했다. 이 라이브러리를 통해 outbox 테이블 관리, polling, retry, 상태 관리까지 상당 부분 위임할 수 있었고, 직접 준비한 것은 다음 정도였다.

  • outbox 관련 테이블을 수동 생성
  • Clock Bean 등록
  • 메인 애플리케이션에 @EnableOutbox 추가
  • Poller를 돌릴 배치 애플리케이션에 @EnableScheduling@EnableOutbox 추가

서비스 로직도 단순해졌다. 기존에는 저장 후 즉시 Kafka를 보내던 코드를, 이제는 메시지를 JSON으로 직렬화해 OutboxRecordRepository에 저장하는 방식으로 바꿨다. 실제 발행은 OutboxRecordProcessor 구현체가 담당하며, eventType에 따라 메시지를 읽어 Kafka로 전송한다.

설정 예시로는 poll-interval, batch-size, max-retries, exponential 백오프, jittered 정책 같은 재처리 옵션을 세밀하게 조정할 수 있었다. 글은 특히 0.3.0 기준으로 설명하며, 0.4.xSpring Boot 4 이상과만 호환된다는 점도 함께 짚는다.

이 요약은 원문 이해를 돕기 위한 큐레이션입니다. 저작권은 원저작자에게 있으며, 정확한 내용과 맥락은 원문을 확인하세요.

요약 오류, 출처 표기 문제, 삭제 요청은 문의 · 건의로 알려주세요.