Skip to content
isdnetworks
Go back

드롭쉬핑 플랫폼을 마이크로서비스로 설계한 과정

배경

드롭쉬핑 기반의 이커머스 자동화 플랫폼을 새로 설계할 기회가 생겼다. 도매몰에서 상품을 수집하고, 여러 오픈마켓에 자동 등록하며, 주문 발생 시 도매몰에 자동 발주하는 전 과정을 자동화하는 시스템이다.

초기에는 모놀리식으로 빠르게 만들까 고민했지만, 이 플랫폼의 특성상 외부 API 의존도가 매우 높고 각 기능의 장애 특성이 달랐다. 마켓 API 장애가 주문 처리를 멈추거나, AI 분석 실패가 상품 등록을 막는 상황은 피해야 했다.

8개 마이크로서비스 분해

비즈니스 도메인을 기준으로 8개 서비스를 도출했다.

#서비스역할핵심 기능
1상품 수집기도매몰 연동도매몰 API에서 상품 수집, 표준 구조로 변환
2상품 분석기AI 분석동일상품 그룹화, 콘텐츠 자동 생성
3마켓 등록기마켓 연동마켓별 API로 상품 등록/수정/삭제
4주문 처리기주문 자동화마켓 주문 수신 후 최저가 도매몰에 자동 발주
5배송 관리기물류 추적송장 연동, 배송 상태 추적, 반송 처리
6정산 관리기수익 계산실시간 수익 계산, 마켓 정산 검증
7클레임 처리기CS 자동화취소/반품 모니터링 및 자동 처리
8알림 봇알림 발송취소 안내, 반품 안내 메시지 전송

서비스 분해의 기준은 단순했다. 장애가 발생했을 때 독립적으로 격리할 수 있는가이다. 상품 수집이 멈춰도 이미 등록된 상품의 주문은 정상 처리되어야 하고, AI 분석이 실패해도 수동 등록은 가능해야 한다.

Go + Python 혼합 전략

모든 서비스를 하나의 언어로 통일하지 않았다. 서비스의 특성에 따라 Go와 Python을 나눠 적용했다.

Go를 선택한 서비스 (6개)

상품 수집기, 마켓 등록기, 주문 처리기, 배송 관리기, 정산 관리기, 클레임 처리기에 Go를 적용했다.

이 서비스들의 공통점은 다음과 같다.

Go의 goroutine은 수천 개의 동시 API 호출을 적은 메모리로 처리할 수 있었고, 컴파일된 바이너리는 컨테이너 이미지 크기도 작게 유지할 수 있었다.

Python을 선택한 서비스 (2개)

상품 분석기와 알림 봇에는 Python을 적용했다.

언어 혼합의 핵심 원칙은 서비스 간 통신은 언어에 무관하게 동일한 프로토콜을 사용하는 것이었다. REST API와 Redis Streams 기반 메시지 큐를 표준 통신 채널로 정했다.

Redis Streams를 메시지 큐로 선택한 이유

서비스 간 비동기 통신에 Kafka나 RabbitMQ 대신 Redis Streams를 선택했다.

선택 이유:

  1. 이미 Redis를 캐시로 사용 중: 별도 MQ 인프라 추가 없이 기존 Redis에 통합
  2. Consumer Group 지원: Kafka와 유사한 컨슈머 그룹 기능으로 메시지 분배와 ACK 처리 가능
  3. 운영 복잡도 감소: 소규모 팀에서 Kafka 클러스터를 운영하는 것은 오버엔지니어링
  4. 충분한 처리량: 초당 수천 건 수준의 메시지 처리에는 Redis Streams로 충분

물론 트레이드오프가 있다. 메시지 영속성이나 대규모 스트림 처리에서는 Kafka가 유리하다. 하지만 이 플랫폼의 규모에서는 Redis Streams가 적절한 선택이었다.

데이터 파이프라인 설계

이 플랫폼의 핵심 설계 원칙은 중간 결과 보존이다. 상품이 수집되고 분석되어 마켓에 등록되기까지, 각 단계의 결과가 DB에 저장된다.

[수집] → DB 저장 → [분석] → DB 저장 → [등록] → DB 저장 → [주문처리]

이렇게 설계한 이유는 명확하다.

작업 상태 머신

모든 작업은 상태 머신으로 관리된다.

PENDING → PROCESSING → COMPLETED
                    ↘ FAILED → PENDING (재처리)
          COMPLETED → ROLLBACK → PENDING (재처리)

각 작업에는 상태와 함께 시도 횟수, 마지막 오류 메시지, 처리 시작/완료 시각이 기록된다. 이를 통해 실패한 작업의 패턴을 파악하고 자동 재처리 전략을 세울 수 있었다.

인프라 구성

소규모 프로젝트였기 때문에 Kubernetes 대신 Docker Compose를 선택했다.

컴포넌트기술역할
API GatewayNginxSSL 종료, 리버스 프록시, 라우팅
DatabaseMariaDB데이터 영속 저장
Cache + MQRedis캐싱, Redis Streams MQ
ContainerDocker Compose서비스 오케스트레이션

인증 구조

서비스 간 통신에 mTLS를 적용한 이유는, 내부 네트워크라도 서비스 간 신뢰를 보장해야 하기 때문이다. 각 서비스가 독립적으로 배포되므로, 잘못된 서비스가 다른 서비스의 API를 호출하는 것을 방지한다.

데이터베이스 전략

초기에는 단일 MariaDB 인스턴스에 공유 DB를 사용한다. 마이크로서비스 순수주의자들은 서비스별 DB 분리를 주장하지만, 현실적으로 소규모 팀에서 여러 DB를 운영하는 것은 부담이 크다.

대신 서비스별 스키마를 논리적으로 분리하고, 향후 필요 시 물리적으로 분리할 수 있는 구조로 설계했다.

MariaDB Instance
  ├── schema: product    (상품 수집기, 상품 분석기)
  ├── schema: market     (마켓 등록기)
  ├── schema: order      (주문 처리기, 배송 관리기)
  ├── schema: settlement (정산 관리기)
  └── schema: common     (공통 코드, 설정)

설계하면서 배운 점

마이크로서비스는 만능이 아니다. 분산 시스템의 복잡성, 서비스 간 데이터 정합성, 네트워크 장애 처리 등 모놀리식에서는 신경 쓰지 않아도 되는 문제들이 생긴다.

하지만 이 플랫폼처럼 외부 API 의존도가 높고 각 도메인의 장애 특성이 뚜렷한 경우, 마이크로서비스의 장애 격리 이점은 운영 복잡성을 상쇄하고도 남았다.

다음 글에서는 이 아키텍처에서 적용한 장애 격리 패턴들(Circuit Breaker, Bulkhead, Dead Letter Queue 등)을 구체적으로 다룬다.

참고 자료


Share this post on:

Previous Post
Go + Python 혼합 마이크로서비스에서 장애 격리 패턴 적용기
Next Post
도매 API 연동 시 Rate Limit 분산 전략