#Backend

사장님 입점신청 자동승인 주기를 10분에서 10초로

사장님 입점신청 자동승인 주기를 10분에서 10초로
01

Summary

10분 걸리던 배민 사장님 입점 승인, 단 10초 만에 끝내는 DB & 폴링 아키텍처 개편기

아웃박스 큐를 걷어내고 Level-Triggered Reconciliation 패턴과 Redis 분산락으로 성능을 60배 끌어올린 실무 인사이트

우아한형제들 기술블로그에서 소개하는 이 아티클은 배달의민족 사장님 입점신청 자동승인 시스템의 병목 현상을 해결한 대규모 개선 과정을 다룹니다. 기존 배치 아웃박스 패턴의 대기 시간을 극복하기 위해 Redis 분산락, 10초 폴링 전략, 그리고 DB 상태 관리를 결합하여 10초 이내 반응성을 확보했습니다. 시스템 부하 상승 없이 분산 환경의 동시성 및 재시도 메커니즘을 깔끔하게 정돈한 백엔드 엔지니어링의 정수를 보여줍니다.

  • 01아웃박스 대기 큐를 없애고 자동승인 전용 상태 관리 테이블(auto_approve_state)을 신설하여 구조 단순화
  • 02폴링 주기(10초)와 재시도 주기(10분)를 분리 설계하여 외부 시스템 추가 부하 방지
  • 03cron 스케줄러 대신 fixedDelay와 서버별 무작위 initialDelay를 조합하여 N대 워커 간 락 경합 방지
  • 04DB SKIP LOCKED 및 조건부 UPDATE 대비 Redis 분산락의 장단점 비교 분석 및 채택
  • 05이벤트 기반(Edge-triggered) 대신 상태 조정(Level-triggered) 방식을 선택하여 자가 회복력 확보

RECOMMENDATION

배치 처리 시스템의 반응 시간을 줄이면서도 외부 시스템 과부하 및 동시성 문제를 안전하게 해결하고 싶은 백엔드 개발자 및 아키트에게 강하게 추천합니다.

The Problem

입점 신청 자동승인 처리가 수집과 처리로 분리된 10분 주기 스케줄러와 무거운 DB 쿼리로 인해 신청부터 처리 시작까지 최소 3분에서 최대 12분 59초의 대기 시간이 발생하였습니다.

The Solution

아웃박스 대기 큐를 제거하고 단일 스케줄러 구조로 전환하였으며, 재시도 시간 추적용 상태 테이블 도입 및 Redis 분산락과 10초 폴링 방식을 적용하여 조회를 경량화하고 동시성을 제어했습니다.

The Result

자동승인 대상 생성 후 처리 시작까지의 대기 시간을 기존 최대 12분 59초에서 10초 이내로 대폭 단축시켰으며, 재시도 주기를 폴링 주기와 분리함으로써 외부 시스템 부하 증가 없이 1/60 주기를 달성했습니다.

Trade-off

폴링 주기가 10초로 짧아짐에 따라 DB 조회 빈도가 급증하는 부담이 존재하며, Redis와 DB 간 두 저장소의 상태를 동기화하고 락 만료 및 분산 환경 레이스 컨디션을 방지하기 위한 복잡한 방어 로직이 추가되었습니다.

03

Key Concepts

Concept · 01

Level-Triggered Reconciliation (상태 조정)

단순 이벤트 발생(Edge)에 의존하지 않고 현재 상태와 목표 상태 간의 차이를 반복적으로 관찰 및 비교하여 목표 상태로 수렴시키는 아키텍처 패턴입니다.

  • 외부 조건 변경 이벤트를 놓치더라도 현재 상태 레코드를 재조회하여 스스로 자가 회복할 수 있는 구조를 완성함
Concept · 02

Redis Distributed Lock (분산락)

여러 워커 서버가 분산 환경에서 동일한 자원에 동시 접근하는 것을 방지하기 위해 인메모리 저장소인 Redis를 활용하여 선점 권한을 관리하는 기법입니다.

  • 선점 실패 건이 DB까지 도달하지 않도록 Redis 단에서 빠르게 차단하여 쓰기 DB 부하를 대폭 줄임
Concept · 03

fixedDelay & Initial Delay Randomization

이전 스케줄링 작업이 완료된 시점부터 일정 시간을 대기 후 실행하며, 서비스 기동 시 첫 실행 시점을 무작위로 분산시키는 스케줄링 기법입니다.

  • N대의 워커 서버가 동일한 시각에 동시 실행되어 발생하는 DB 및 락 경합을 방지하기 위해 initialDelayString SpEL을 활용함