프로덕션 급 마켓플레이스 백엔드
Source: Dev.to
왜 마켓플레이스 백엔드는 출시 후에 실패하는가 (그리고 정확성을 위해 설계하는 방법)
대부분의 마켓플레이스 백엔드는 기능이 부족해서 실패하는 것이 아니다.
인벤토리, 금전, 그리고 재시도가 실제 운영 환경에서 충돌하기 때문에 실패한다.
마켓플레이스(B2B 또는 B2C)를 운영해 본 적이 있다면 다음 상황이 익숙하게 들릴 것이다:
- 부하가 걸리면 인벤토리가 음수가 된다
- 주문이 잘못된 상태에 머문다
- 재시도가 조용히 중복을 만든다
- 인보이스가 고객이 실제로 결제한 금액과 일치하지 않는다
- “유지보수 모드”가 사고 발생 시 관리자 접근을 차단한다
이러한 문제들은 보통 개발 단계에서는 나타나지 않는다. 출시 후, 동시성, 재시도, 부분 실패 상황에서 드러난다.
공통된 근본 원인
내 경험에 따르면, 대부분의 문제는 몇 가지 설계 지름길에서 비롯된다:
- 인벤토리를 제품에 직접 저장
- 주문 상태 전환을 여러 컨트롤러에 분산
- 부동소수점 금액 사용
- “요청을 그냥 재시도” 로직
- 비즈니스 규칙을 강제하는 전역 가드
이 모든 것이 처음엔 동작하지만, 결국 문제가 된다.
정확성을 최우선으로 하는 마켓플레이스 백엔드의 모습
실제 운영을 염두에 둔 마켓플레이스 백엔드를 설계할 때, 나는 몇 가지 절대 타협할 수 없는 원칙을 갖게 되었다.
인벤토리는 구조적으로 안전해야 함
인벤토리는 다음과 같이 관리되어야 한다:
- 별도의 테이블에 격리
- 데이터베이스 수준의 락으로 보호
- 예약, 해제, 최종 확정을 명시적으로 수행
과잉 판매가 가능하면 결국 발생한다.
주문은 실제 상태 머신을 가져야 함
주문은 다음을 만족해야 한다:
- 명시적인 상태를 순차적으로 이동
- 중앙에서 검증
- 전이(skip)를 절대 허용하지 않음
주문 로직이 여기저기 흩어지면 데이터 손상이 불가피하다.
금액은 불변이며 정수 기반이어야 함
- 부동소수점 금액 금지
- 실시간 제품 데이터를 기반으로 총액을 재계산 금지
- 주문 항목과 인보이스는 스냅샷 기반이어야 함
주문이 확정되면 재무 데이터는 절대 변하지 않아야 한다.
재시도는 기본적으로 안전해야 함
재시도는 예외 상황이 아니라 일상이다. 따라서:
- 쓰기 연산에 멱등성 키(idempotency key) 적용
- 데이터베이스 차원의 유니크 제약 적용
- 중복 부작용 대신 안전한 재실행 보장
운영 도구는 절대 운영자를 차단해서는 안 됨
전역 가드와 하드코딩된 설정은 위험 요소다. 유지보수 모드, 피처 플래그, 런타임 설정은 다음을 만족해야 한다:
- 데이터베이스에 저장
- 감사 가능(auditable)
- 언제든지 관리자가 우회할 수 있어야 함
운영 중 사고가 발생했을 때 자신이 스스로를 차단한 사실을 알게 되는 일은 최악이다.
왜 이것이 중요한가
대부분의 팀은 이러한 교훈을 실제 운영에서 깨달은 뒤 백엔드를 다시 구축하게 된다.
나는 처음부터 다음 원칙을 기반으로 설계한 프로덕션‑그레이드 B2B 마켓플레이스 백엔드를 구축해 왔다:
- 설계 단계부터 과잉 판매 방지
- 엄격한 주문 라이프사이클 강제
- 스냅샷 기반 재무 정확성 보장
- 멱등성·재시도‑안전한 쓰기 경로 구현
- 관리자를 위한 안전한 운영 제어
이는 MVP 스캐폴드가 아니라, 출시 6개월 후에 “이게 있으면 좋겠다”고 생각하게 되는 백엔드다.
마켓플레이스를 구축하고 프로덕션 준비성을 고민하고 있다면, 언제든지 의견을 교환하거나 설계 결정을 함께 검토하고 싶다.
정확성을 최우선으로.
운영에서는 지루함을 추구.
그것이 목표다.