한 줄 요약: 셀러 관리 시스템의 핵심은 입점 심사 자동화로 운영 병목을 없애고, 스코어링 엔진으로 셀러 품질을 실시간 추적하며, 정산 파이프라인으로 분쟁을 원천 차단하는 것이다.

실제 문제: 오픈마켓 셀러 관련 사고

지마켓·옥션 — 가짜 셀러 대량 입점 (2019)

지마켓에서 사업자등록증을 위조한 가짜 셀러 수백 명이 입점했습니다. 이들은 정상적인 상품 리스트를 며칠간 운영해 리뷰를 쌓은 뒤, 특정 날짜에 고가 상품(전자기기, 명품 가방)을 올리고 결제를 유도했습니다. 구매자가 입금하면 셀러 계정이 삭제되는 “먹튀” 수법이었습니다. 피해자 1인당 평균 30만 원, 총 피해 규모는 수십억 원에 달했습니다. 플랫폼이 사업자등록증 진위를 API로 실시간 검증하지 않고 이미지 파일만 받아 수동 확인한 것이 근본 원인이었습니다.

11번가 — 허위 원산지 상품 방치 (2021)

11번가에서 국내산으로 표기된 농수산물 수천 건이 실제로는 중국산이었습니다. 셀러가 상품 등록 시 원산지를 임의로 입력할 수 있었고, 플랫폼은 등록 시점에 별도 검증을 하지 않았습니다. 공정거래위원회 조사 후 플랫폼은 과징금 처분을 받았습니다. 카테고리별 필수 서류(원산지 증명서, 유기농 인증서 등) 자동 검증이 없었던 것이 원인입니다.

쿠팡 마켓플레이스 — 정산 지연 대규모 민원 (2022)

쿠팡 마켓플레이스 정산 시스템이 월말 일괄 정산 배치 중 장애를 일으켜 2,000여 명의 셀러에게 정산금이 지급되지 않았습니다. 셀러들은 재고 매입 자금이 묶이면서 운영 위기를 겪었고, 관련 커뮤니티와 언론에 대규모 항의가 이어졌습니다. 정산 배치가 단일 DB 트랜잭션으로 설계되어 중간 실패 시 전체가 롤백된 것이 원인이었습니다.

셀러 관리 시스템이 해결해야 할 핵심 문제:

  • 입점 심사 자동화: 위조 서류를 탐지하고 정부 API로 사업자 진위를 실시간 검증
  • 셀러 품질 관리: 배송 지연율·CS 응답률·반품률을 실시간 집계해 등급 자동 조정
  • 상품 컴플라이언스: 카테고리별 필수 서류, 금지 상품, 원산지 허위 표기 자동 감지
  • 정산 안정성: 건별 정산 파이프라인으로 일부 실패가 전체에 영향을 주지 않도록 설계
  • 페널티 집행: 경고·판매 제한·강제 탈퇴를 명확한 기준과 이의신청 절차와 함께 운영

설계 의사결정 로드맵

결정 1: 입점 심사 방식 — 수동 vs 자동 vs 하이브리드

후보 장점 단점 언제 적합
수동 심사 판단 정확, 예외 처리 유연 처리 속도 느림, 운영 인력 비용 높음 월 입점 신청 100건 이하 소규모
완전 자동 빠름, 24시간 운영, 확장 용이 위조 서류 탐지 한계, 이의신청 처리 난항 서류 표준화된 단순 카테고리
하이브리드 자동으로 1차 필터 후 사람이 2차 판단 구현 복잡, 파이프라인 설계 필요 대형 마켓플레이스, 다양한 카테고리

우리의 선택: 하이브리드 (자동 1차 + 전문 심사관 2차)

  • 사업자등록증 OCR 인식, 국세청 API 사업자 상태 조회, 통신판매업 신고 여부는 기계가 더 빠르고 정확하다. 단, 서류 조합이 카테고리 요건을 충족하는지, 판매 이력이 없는 신규 셀러의 신뢰도는 사람이 판단해야 한다. 자동 검증 통과율이 70~80%이므로 심사관은 나머지 20~30%에만 집중하면 되고, 전체 심사 시간이 평균 3일에서 4시간으로 단축된다.

결정 2: 셀러 등급/신뢰도 — 정적 기준 vs ML 기반

후보 장점 단점 언제 적합
정적 기준 (판매량/리뷰 수) 투명, 이해 쉬움, 조작 감지 쉬움 초기 셀러 불이익, 지표 어뷰징 가능 MVP, 소규모 마켓
룰 기반 가중 점수 다차원 평가, 직관적 설명 가능 가중치 업데이트 수동 관리 중규모, 명확한 KPI가 있을 때
ML 기반 스코어링 이상 패턴 자동 탐지, 계절 보정 가능 블랙박스, 이의신청 설명 어려움 셀러 10만 이상, 데이터 풍부 시

우리의 선택: 룰 기반 가중 점수 (ML 보조)

  • 셀러가 “왜 등급이 내려갔는가”를 이해하고 개선할 수 있어야 플랫폼 신뢰가 유지된다. 룰 기반으로 배송 지연율 25%, CS 응답률 25%, 반품률 20%, 구매자 만족도 30% 가중 합산을 기준으로 하고, ML은 이상 급등 패턴(리뷰 구매, 가짜 주문)을 탐지하는 보조 역할로만 사용한다.

결정 3: 상품 등록 방식 — 개별 vs 대량 업로드 vs API

후보 장점 단점 언제 적합
개별 등록 (웹 폼) UX 간단, 검증 즉시 가능 상품 수 많으면 비효율 소량 셀러, MVP
대량 업로드 (Excel/CSV) 수백~수천 건 일괄 처리 서식 오류 시 전체 실패 위험 중대형 셀러, 정기 재고 갱신
API 연동 실시간 동기화, 자동화 가능 셀러 측 개발 리소스 필요 ERP 보유 대형 셀러

우리의 선택: 세 가지 병행 (비동기 처리 통합)

  • 셀러 규모에 따라 채널이 달라지므로 모두 지원해야 한다. 단, 모든 채널의 입력이 동일한 비동기 검증 파이프라인을 거치도록 설계한다. Excel 업로드도 API 요청도 내부적으로 동일한 ProductIngestionJob으로 변환되어 처리된다. 이렇게 하면 검증 로직을 한 곳에서만 관리할 수 있다.

결정 4: 수수료 구조 — 고정 vs 카테고리별 vs 동적

후보 장점 단점 언제 적합
고정 수수료 단순, 셀러 예측 가능 마진율이 다른 카테고리에 불공평 단일 카테고리 전문몰
카테고리별 업종 특성 반영 가능 설정 복잡, 셀러 혼란 가능 종합 마켓플레이스
동적 수수료 시장 상황·셀러 등급 반영 예측 불가로 셀러 불신 유발 단기 프로모션, 등급 인센티브

우리의 선택: 카테고리별 기본 수수료 + 등급 할인

  • 식품 3%, 전자제품 6%, 패션 12% 등 카테고리별 마진 구조에 맞게 기본 요율을 설정하되, 우수 셀러(Gold 이상)에게는 0.5~1% 추가 할인을 적용해 품질 유지 인센티브를 제공한다. 동적 수수료는 셀러가 가격 예측을 할 수 없어 플랫폼 신뢰를 떨어뜨린다.

결정 5: 페널티 시스템 — 경고 누적 vs 점수제 vs 자동 제재

후보 장점 단점 언제 적합
경고 누적 (3회 시 제재) 단순, 이해 쉬움 중대 위반도 경고 3회까지 허용 소규모, 단순 정책
점수제 (위반 유형별 차감) 위반 심각도 반영, 유연 점수 기준 설명 복잡 다양한 위반 유형 있을 때
자동 제재 (임계 즉시 차단) 신속 대응, 피해 최소화 오탐 시 선의 셀러 피해 사기 탐지, 불법 상품

우리의 선택: 점수제 + 위반 유형별 자동/수동 혼합

  • 배송 지연 1건은 1점 차감이지만 가짜 상품 판매 1건은 즉시 계정 정지 대상이다. 모든 경우를 동일한 경고 카운터로 처리하면 중대 위반이 과소 처리된다. 위반 유형을 크리티컬(즉시 정지)·메이저(점수 대폭 차감)·마이너(점수 소량 차감)로 분류하고, 크리티컬은 자동 제재 후 심사관 리뷰, 메이저·마이너는 점수 누적 후 임계 도달 시 제재한다.

1. 요구사항 분석 및 규모 추정

기능 요구사항

  1. 입점 심사: 사업자등록증 OCR, 국세청/공정위 API 연동 자동 검증, 심사관 2차 승인
  2. 셀러 정보 관리: 계정 정보, 배송·반품 정책, 정산 계좌, 카테고리 권한 관리
  3. 상품 등록·관리: 웹 폼, Excel 대량 업로드, API 연동, 상품 검수 파이프라인
  4. 셀러 스코어링: 배송 지연율·CS 응답률·반품률·만족도 실시간 집계 및 등급 산출
  5. 수수료 계산 및 정산: 주문 완료 시 수수료 계산, 주기별 자동 정산, 정산 내역 조회
  6. 페널티 관리: 위반 탐지, 경고/점수 차감/판매 제한/계정 정지, 이의신청 처리
  7. 셀러 대시보드: 매출 현황, 주문 처리 현황, 스코어 추이, 정산 내역

비기능 요구사항

  • 정확성: 정산 금액 오류 0건, 수수료 계산 소수점 4자리 정밀도 (금융 계산)
  • 가용성: 셀러 상품 등록·수정 API 99.9%, 정산 파이프라인 99.99%
  • 확장성: 셀러 10만 명, 일 상품 등록 50만 건, 초당 주문 완료 5,000건 수수료 계산
  • 감사 추적: 모든 정산·페널티 이벤트는 변경 불가 로그로 영구 보관

규모 추정

항목 수치
활성 셀러 수 10만 명
일 신규 입점 신청 500건
활성 상품 수 3,000만 건
일 상품 등록·수정 50만 건
일 주문 완료 (수수료 계산 트리거) 200만 건
수수료 계산 피크 QPS 5,000
월 정산 대상 셀러 8만 명
정산 총액 (월) 약 3,000억 원

스토리지 추정:

셀러 1명 기준:
  기본 정보: 2KB
  스코어 이력 (365일): 365 × 200B ≈ 70KB
  정산 내역 (월 100건 × 5년): 6,000건 × 500B ≈ 3MB
  페널티 이력: 1KB

셀러 10만 명 총 스토리지:
  기본 정보: 10만 × 2KB = 200MB
  스코어 이력: 10만 × 70KB = 7GB
  정산 내역 (5년): 10만 × 3MB = 300GB
  상품 메타데이터: 3,000만 건 × 2KB = 60GB
  합계: ≈ 370GB (복제·인덱스 포함 1TB)

2. 고수준 아키텍처

셀러 관리 시스템은 공항의 입국 심사대에 비유할 수 있습니다. 입국 신청자(셀러 지망생)는 여권과 비자(사업자등록증, 통신판매업 신고)를 제출하고, 자동 심사대(자동 검증 파이프라인)가 1차로 걸러낸 뒤, 유인 심사대(심사관)가 최종 판단합니다. 입국 후에도 행동(배송, CS, 품질)이 지속적으로 모니터링되고, 문제가 생기면 경고(페널티)가 누적됩니다.

graph LR
    A["셀러"] --> B["API Gateway"]
    B --> C["입점 심사 서비스"]
    B --> D["상품 관리 서비스"]
    B --> E["정산 서비스"]
    C --> F["심사 DB"]
    D --> G["상품 DB"]
    E --> H["정산 DB"]
    F --> I["스코어링 엔진"]
    G --> I
컴포넌트 역할
API Gateway 인증·인가, 셀러 계정 식별, 요청 라우팅
입점 심사 서비스 서류 OCR, 정부 API 검증, 심사 워크플로우 관리
상품 관리 서비스 상품 등록·수정·삭제, 비동기 검수 파이프라인
정산 서비스 주문 완료 이벤트 수신, 수수료 계산, 정산 실행
스코어링 엔진 배송·CS·반품 지표 집계, 등급 산출, 페널티 판단
페널티 서비스 위반 탐지, 제재 집행, 이의신청 워크플로우
심사 DB 입점 신청서, 서류 원본, 심사 결과 이력
상품 DB 상품 메타데이터, 카탈로그, 검수 상태
정산 DB 수수료 원장, 정산 내역, 지급 결과

3. 핵심 컴포넌트 상세 설계

3-1. 입점 심사 파이프라인

입점 심사는 조립 라인(Assembly Line)입니다. 각 단계는 독립적이며 한 단계가 실패하면 다음 단계로 넘어가지 않습니다. 자동화할 수 있는 단계는 기계가 처리하고, 판단이 필요한 단계만 사람에게 넘깁니다.

심사 단계 상세:

  1. 서류 수집 및 OCR: 사업자등록증·통신판매업신고증·계좌 사본을 업로드하면 OCR 엔진이 사업자번호, 대표자명, 업태·종목을 추출합니다. 이미지 품질이 낮거나(흐림, 잘림) OCR 신뢰도가 90% 미만이면 재업로드를 요청합니다.

  2. 정부 API 자동 검증: 국세청 사업자 상태 조회 API로 사업자번호 유효성, 폐업 여부, 휴업 여부를 확인합니다. 공정거래위원회 통신판매업 조회 API로 신고 번호와 대표자명 일치 여부를 확인합니다.

  3. 카테고리별 추가 서류: 식품 판매 신청 시 영업허가증, 의류 수입의 경우 KC 인증서를 요구하는 등 카테고리별 추가 서류 요건을 자동으로 체크합니다.

  4. 자동 검증 통과 후 심사관 배정: 자동 검증을 모두 통과한 신청만 심사관에게 넘깁니다. 심사관은 서류 조합의 정합성, 판매 예정 카테고리의 적합성, 계좌 명의 일치 여부를 확인합니다.

graph LR
    A["신청서 제출"] --> B["OCR 추출"]
    B --> C["국세청 API"]
    C --> D["카테고리 서류"]
    D --> E{"자동 통과?"}
    E -->|"예"| F["심사관 배정"]
    E -->|"아니오"| G["보완 요청"]

심사 결과 상태 전이:

SUBMITTED → DOCUMENT_REVIEW (자동 검증 중)
         → PENDING_SUPPLEMENT (보완 필요)
         → MANUAL_REVIEW (심사관 검토 중)
         → APPROVED (승인)
         → REJECTED (거부, 사유 첨부)

정부 API 연동 시 고려사항: 국세청 API는 일일 호출 한도가 있습니다. 동일 사업자번호를 여러 번 조회하지 않도록 Redis에 24시간 캐시를 두고, API 장애 시에는 심사를 멈추지 않고 “수동 검증 필요” 플래그를 달아 심사관이 직접 확인하도록 합니다.

3-2. 셀러 스코어링 엔진

셀러 스코어는 학교 성적표입니다. 배송(체육), CS(수학), 반품(과학), 만족도(국어) — 각 과목에 가중치가 있고, 총점으로 등급이 결정됩니다. 그런데 이 성적표는 매일 갱신됩니다.

점수 계산 공식:

셀러_점수 = (배송_점수 × 0.25)
           + (CS_점수 × 0.25)
           + (반품_점수 × 0.20)
           + (만족도_점수 × 0.30)

배송_점수 = 100 - (지연_건수 / 총_출고_건수 × 100)
CS_점수   = 문의_24h_응답_건수 / 총_문의_건수 × 100
반품_점수 = 100 - (반품_건수 / 총_판매_건수 × 100 × 2)
              [반품은 페널티 가중 2배]
만족도_점수 = 평균_별점 / 5.0 × 100

등급 기준:

등급 점수 범위 혜택
플래티넘 95점 이상 수수료 1% 추가 할인, 노출 우선순위 최상
골드 85~94점 수수료 0.5% 할인, 빠른 정산 (주 1회)
실버 70~84점 기본 수수료, 월 2회 정산
브론즈 50~69점 기본 수수료, 월 1회 정산, 노출 제한
주의 50점 미만 신규 상품 등록 제한, 개선 계획 제출 요구

집계 주기: 배송 지연은 주문 완료 이벤트 수신 즉시 실시간 집계합니다. CS 응답률은 6시간마다 배치로 계산합니다. 최종 등급은 매일 자정 배치로 산출합니다. 실시간 집계가 필요한 이유는 배송 지연이 연속으로 발생할 때 즉시 알림을 보내 셀러가 조치를 취하게 하기 위해서입니다.

스코어 이력 관리: seller_score_history 테이블에 일별 스냅샷을 저장합니다. 셀러가 “왜 등급이 떨어졌는지”를 조회할 수 있고, 이의신청 시 근거 데이터로 활용합니다.

graph LR
    A["주문 완료 이벤트"] --> B["지표 집계기"]
    C["CS 응답 이벤트"] --> B
    D["반품 이벤트"] --> B
    B --> E["Redis 집계 버퍼"]
    E --> F["등급 산출 배치"]
    F --> G["셀러 등급 DB"]

3-3. 대량 상품 등록 파이프라인

대량 상품 등록은 세관 통관에 비유할 수 있습니다. 화물(Excel 파일)이 항구(API)에 도착하면, 서류 검사(형식 검증) → 품목 검사(금지 상품 필터) → 세관 통관(최종 승인) 과정을 거쳐야 합니다. 컨테이너 하나가 문제가 있어도 다른 컨테이너는 통관됩니다. 즉, 행 단위로 독립 처리가 핵심입니다.

비동기 처리 설계:

1. 셀러가 Excel 파일 업로드 → S3 저장 → job_id 즉시 반환
2. Kafka Producer: UploadJob(job_id, s3_url, seller_id) 발행
3. Consumer: Excel 파싱 → 행별로 ProductIngestionTask 생성
4. 각 Task 독립 처리:
   a. 필수 필드 검증 (상품명, 가격, 카테고리)
   b. 금지어 필터 (불법 복제, 총기류 등)
   c. 이미지 URL 유효성 확인
   d. 카테고리별 추가 필드 검증
5. 결과 집계: job_id별 성공/실패 건수 → 셀러에게 결과 리포트 제공

멱등성 처리: (seller_id, external_product_id) 조합으로 UPSERT 처리합니다. 동일한 Excel을 두 번 업로드해도 중복 등록이 발생하지 않습니다. 네트워크 오류로 재업로드하는 경우가 흔하기 때문입니다.

검증 실패 처리: 10만 건 중 100건이 실패해도 나머지 99,900건은 정상 등록됩니다. 실패한 100건은 오류 사유와 함께 Excel 리포트로 셀러에게 반환됩니다.

이미지 처리: 상품 이미지는 등록 즉시 썸네일 생성, 불법 이미지 AI 검수를 비동기로 처리합니다. 검수 완료 전까지는 상품이 “검수 중” 상태로 노출되고, 검수 통과 시 자동으로 “판매 중”으로 전환됩니다.

3-4. 수수료 계산기

수수료 계산은 세금 계산서 발행과 같습니다. 한 번 계산된 수수료는 변경되어서는 안 되고(불변성), 어떤 근거로 계산됐는지 추적 가능해야 합니다(감사 가능성).

수수료 계산 로직:

주문_완료_이벤트 수신
  └─ 수수료_원장 조회 (seller_id, category_id, 주문_시각 기준)
     └─ 기본_수수료율 = category_fee_rate
     └─ 등급_할인율 = seller_grade_discount
     └─ 프로모션_할인율 = active_promotion_discount
     └─ 최종_수수료율 = 기본 - 등급할인 - 프로모션할인
     └─ 수수료_금액 = 판매금액 × 최종_수수료율 (BigDecimal, 반올림 없이 소수점 4자리)
  └─ fee_ledger 테이블에 INSERT (주문_id, 계산 근거, 금액 모두 기록)

수수료는 float 타입을 절대 사용하지 않습니다. 0.1 + 0.2 = 0.30000000000000004는 금융 계산에서 재앙입니다. Java BigDecimal, Python Decimal, DB DECIMAL(15,4) 타입을 사용합니다.

수수료 정책 변경 시: 기존 주문의 수수료는 바뀌지 않아야 합니다. fee_policy_versions 테이블에 정책을 버전 관리하고, 수수료 계산 시 주문 완료 시각 기준으로 유효한 버전을 조회합니다. 정책을 변경해도 과거 주문의 수수료 계산은 당시 정책 그대로 재현됩니다.

3-5. 정산 파이프라인

정산은 월급날 급여 이체와 같습니다. 정확하게, 빠짐없이, 중복 없이 이루어져야 합니다. 월말 배치 하나가 실패해서 8만 명 전원의 정산이 멈추면 안 됩니다.

건별 정산 설계:

graph LR
    A["정산 트리거"] --> B["미정산 원장 조회"]
    B --> C["셀러별 집계"]
    C --> D["은행 API 이체"]
    D --> E{"이체 성공?"}
    E -->|"예"| F["정산 완료 기록"]
    E -->|"아니오"| G["재시도 큐"]

핵심은 셀러별로 독립적인 정산 트랜잭션입니다. A 셀러 이체가 실패해도 B 셀러 정산은 계속 진행됩니다. 쿠팡 사고의 원인이 바로 전체를 하나의 배치 트랜잭션으로 묶은 것이었습니다.

정산 상태 관리:

PENDING → CALCULATING (집계 중)
        → READY (이체 대기)
        → TRANSFERRING (은행 API 호출 중)
        → COMPLETED (완료)
        → FAILED (실패, 재시도 큐 등록)
        → RECONCILED (대사 완료)

대사(Reconciliation): 정산 완료 다음 날 은행 입금 내역과 시스템 정산 기록을 대조합니다. 불일치 건은 알림을 발송하고 수동 처리 큐에 등록합니다.

3-6. 페널티 엔진

페널티 시스템은 교통 벌점 제도와 같습니다. 신호 위반(마이너)은 벌점 10점, 음주운전(크리티컬)은 즉시 면허 정지입니다. 누적 벌점이 기준을 넘으면 자동으로 면허가 정지됩니다.

위반 유형 분류:

유형 위반 사례 처리 방식
크리티컬 가짜 상품, 불법 상품, 결제 먹튀 즉시 계정 정지 + 심사관 리뷰
메이저 허위 원산지, 가짜 리뷰 구매, 허위 정보 30점 차감, 경고문 발송
마이너 배송 3일 이상 지연, CS 24시간 미응답 5점 차감, 개선 권고

점수 복구: 위반 후 30일간 동일 위반 없으면 마이너 5점을 자동 복구합니다. 좋은 행동(구매자 만족도 연속 상승)은 점수를 더 빠르게 회복합니다. 회복 경로가 없으면 셀러가 플랫폼을 떠납니다.

이의신청 절차: 제재 통보 후 7일 이내 이의신청이 가능합니다. 이의신청이 접수되면 제재가 일시 보류되고 심사관이 48시간 이내 검토합니다. 이의신청 결과와 근거는 반드시 셀러에게 서면으로 통보됩니다.


4. 극한 시나리오

극한 시나리오 1: 사기 셀러 대량 입점 — 자동 심사 우회

상황: 조직적 사기 그룹이 실제 폐업한 사업자등록증 정보를 암시장에서 구입했습니다. 해당 사업자번호는 국세청 API에서 “정상”으로 조회됩니다(폐업 처리가 3개월 지연되는 경우가 있음). 통신판매업 신고는 타인 명의로 실제 등록된 것을 도용했습니다. 입점 심사 자동 검증을 모두 통과해 500개 계정이 한 달 안에 승인됩니다.

어떻게 탐지하는가: 자동 검증 통과 자체는 막기 어렵습니다. 그러나 사기 패턴에는 특징이 있습니다. 정상 셀러는 입점 후 1~2주간 소량 테스트 판매를 하지만, 사기 셀러는 입점 즉시 고가 상품(평균 단가 20만 원 이상)을 대량 등록하고 광고를 집행합니다. 또한 동일 IP 대역, 동일 계좌 은행 지점에서 단기간 다수 가입하는 패턴이 나타납니다.

메커니즘과 대응:

1단계 — 입점 후 행동 모니터링: 첫 7일간 신규 셀러는 “관찰 모드”로 분류합니다. 관찰 모드 셀러의 일 판매 한도는 50건, 건당 최대 10만 원으로 제한됩니다. 사기 셀러는 빠르게 큰 돈을 가져가야 하므로 한도가 사기 유인을 크게 줄입니다.

2단계 — 클러스터 탐지: 가입 IP, 정산 계좌 은행, 대표자 전화번호 앞 6자리를 해시하여 7일 내 동일 해시 5개 이상 가입 시 자동 플래그를 세웁니다. 이 신호만으로 차단하지 않고 심사관에게 “유사 그룹 탐지” 알림을 보냅니다.

3단계 — 이상 거래 실시간 감지: 입점 3일 이내에 일 평균 대비 10배 이상 거래가 발생하면 해당 셀러 정산을 7일 보류(에스크로)합니다. 구매자 신고가 한 건도 없으면 보류 해제합니다.

4단계 — 구매자 보호 장치: 사기 셀러가 탈취한 금액은 플랫폼이 구매자에게 선보상하고 피해 금액을 셀러 보증금(입점 시 예치)에서 차감합니다.

이 시나리오에서 핵심은 “막을 수 없다면 피해를 최소화한다”는 원칙입니다. 100% 탐지보다 피해 규모를 제한하는 구조가 현실적입니다.

결과: 관찰 모드 한도 적용 시 셀러 1명의 최대 피해액은 50건 × 10만 원 = 500만 원으로 제한됩니다(기존 무제한 대비 99% 감소). 보증금 500만 원 제도와 결합하면 플랫폼 손실이 0원에 가까워집니다.


극한 시나리오 2: 월말 정산 배치 중 은행 API 장애

상황: 매월 말일 오후 11시, 8만 명 셀러에게 총 3,000억 원을 정산하는 배치가 실행됩니다. 배치 시작 2시간 후(60% 진행 시점), 은행 API가 “점검 중” 상태로 전환되어 이체 요청이 모두 실패합니다. 4만 8,000명은 정산이 완료됐고, 3만 2,000명은 정산 대기 중입니다.

잘못된 설계의 결과: 전체 배치가 단일 트랜잭션이면 60% 진행분이 모두 롤백됩니다. 8만 명 전원에게 재정산이 필요하고, 이미 입금된 4만 8,000명에게는 중복 지급이 발생합니다. 이것이 쿠팡 사고의 핵심이었습니다.

올바른 설계의 대응:

graph LR
    A["배치 실행기"] --> B["셀러별 정산 단위"]
    B --> C["이체 시도"]
    C -->|"성공"| D["COMPLETED 기록"]
    C -->|"실패"| E["FAILED + 재시도 큐"]
    E --> F["다음 배치 재시도"]

셀러별 정산은 독립적인 트랜잭션입니다. 은행 API 장애가 발생하는 시점부터의 셀러들은 FAILED 상태로 기록되고 재시도 큐에 등록됩니다. 이미 COMPLETED 처리된 4만 8,000명의 정산은 영향 없습니다.

재시도 전략: 은행 API 장애는 점검 시간(새벽 1~3시) 또는 순간 과부하로 발생합니다. 첫 번째 재시도는 30분 후, 두 번째는 2시간 후, 세 번째는 다음 날 오전 9시에 자동 실행합니다. 세 번 모두 실패하면 운영팀에 알림을 보내고 수동 처리합니다.

중복 지급 방지: 이체 요청마다 idempotency_key = SHA256(seller_id + settlement_period + amount)를 은행 API에 전달합니다. 은행 API가 동일한 idempotency_key를 수신하면 이미 처리된 것으로 판단하고 중복 이체를 거부합니다. 재시도가 몇 번이든 한 번만 입금됩니다.

모니터링: 배치 진행률을 1분마다 Prometheus에 기록하고, 오류율이 5%를 넘으면 Slack 알림을 발송합니다. 배치가 예정 시간의 200%를 초과하면 자동으로 배치를 중단하고 재시도 큐로 전환합니다.

정산 시스템은 비행기 블랙박스처럼 모든 상태 전이를 기록해야 합니다. “A 셀러에게 돈이 언제 나갔는가”를 1년 후에도 재현할 수 있어야 합니다.

결과: 기존 방식에서는 8만 명 전원 재처리 + 중복 지급 리스크가 발생했습니다. 건별 독립 트랜잭션 방식에서는 3만 2,000명만 재시도 대상이고, 중복 지급은 idempotency_key로 완전 차단됩니다. 정산 지연은 최대 2시간 이내로 제한됩니다.


극한 시나리오 3: 스코어링 데이터 오염 — 대규모 가짜 반품

상황: 경쟁 셀러를 고의로 망하게 하기 위해 조직적 어뷰저 그룹이 A 셀러의 상품을 대량 구매 후 48시간 내 전량 반품합니다. 2일 동안 반품 500건이 발생해 반품률이 0.1%에서 40%로 폭등합니다. 스코어링 엔진이 이를 정상 계산하여 A 셀러 등급이 플래티넘에서 주의 등급으로 추락하고, 신규 상품 등록이 차단됩니다.

이것이 위험한 이유: A 셀러는 정말 좋은 셀러입니다. 수년간 쌓은 평판이 경쟁자의 공격 이틀 만에 파괴됩니다. 플랫폼이 이를 신속하게 탐지하지 못하면 피해 셀러는 플랫폼을 떠나고, 이런 공격 패턴이 업계에 알려지면 플랫폼 신뢰도 전체가 훼손됩니다.

탐지 메커니즘:

1단계 — 이상 급등 알림: 셀러 반품률이 7일 이동평균 대비 5배 이상 급등하면 즉시 “이상 반품 탐지” 이벤트가 발생합니다. 이 이벤트는 스코어 반영을 일시 중단하고 조사 플래그를 세웁니다. 스코어를 즉시 반영하기 전에 검증 단계를 두는 것이 핵심입니다.

2단계 — 반품 클러스터 분석: 반품 요청자의 구매 이력, 계정 생성일, 기기 지문, IP 대역을 분석합니다. 최근 2일 이내 생성된 계정이 50% 이상이거나 동일 IP 대역에서 반품이 집중되면 “조직적 공격” 신호로 분류합니다.

3단계 — 조사 기간 스코어 동결: 조직적 공격 신호가 감지되면 해당 반품 건들은 “조사 중” 상태로 분류하고 스코어 계산에서 제외합니다. 셀러에게 조사 사실을 즉시 통보하고, 기존 등급을 최대 14일간 유지합니다.

4단계 — 구매 제한 역용: 조직적 반품 공격에 사용된 계정들은 해당 셀러 상품 구매를 1개월간 차단합니다. 반복 피해를 방지합니다.

graph LR
    A["반품 이벤트"] --> B["이상 감지기"]
    B -->|"정상"| C["스코어 반영"]
    B -->|"이상 급등"| D["조사 플래그"]
    D --> E["클러스터 분석"]
    E --> F["스코어 동결"]

스코어 복구: 조사 결과 공격으로 판명되면 해당 반품 건들을 스코어 계산에서 영구 제외하고, A 셀러는 공격 이전 등급으로 즉시 복구됩니다. 조사에 14일이 걸린다면 셀러는 14일간 플래티넘 등급을 유지합니다.

근거와 결과: 이 시나리오에서 중요한 설계 원칙은 “데이터가 비정상적으로 보일 때 즉시 반영하지 말고 검증을 거쳐라”입니다. 반품률이 갑자기 40배 오른 것은 셀러가 갑자기 나빠진 것이 아니라 데이터가 오염됐을 가능성이 높습니다. 이상 감지기가 스코어 엔진과 분리되어 있어야 하는 이유입니다. 이상 감지기 없이 실시간 반영 구조에서는 공격 후 2시간 내에 셀러 등급이 추락하고, 해당 셀러가 그날 예약된 대규모 프로모션이 취소되는 수억 원 피해로 이어질 수 있습니다.


4-추가. 이 설계의 한계와 대안

이 섹션은 “설계가 맞다”는 전제에 의문을 던집니다. 시니어 엔지니어가 코드 리뷰에서 가장 먼저 하는 질문, “이게 실패하면 어떻게 되는가?”를 각 컴포넌트에 적용합니다.

ML 스코어링 오판 비용 — False Positive vs False Negative

ML 이상 탐지를 도입하는 순간 두 가지 실패 모드가 생깁니다. 병원 오진에 비유하면, 건강한 사람을 환자로 판정하는 것(False Positive)과 환자를 건강하다고 보내는 것(False Negative)입니다. 셀러 시스템에서 두 오류의 비용은 비대칭입니다.

실패 모드 시나리오 직접 비용 간접 비용
False Positive (우수 셀러 오제재) 5년 경력 플래티넘 셀러를 가짜 리뷰 구매자로 판정 → 계정 정지 셀러 수익 손실, 플랫폼 수수료 손실 셀러 이탈, 법적 분쟁, 언론 보도
False Negative (사기 셀러 통과) 가짜 상품 셀러를 정상으로 판정 → 구매자 피해 구매자 환불 비용, 보증금 소진 플랫폼 신뢰도 하락, 규제 당국 조사

실무 판단 기준: False Positive 비용이 더 큰 경우(장기 우수 셀러)는 ML 임계값을 높게 잡아 인간 심사관 검토를 우선합니다. False Negative 비용이 더 큰 경우(신규 셀러 사기 탐지)는 임계값을 낮게 잡고 관찰 모드를 활용합니다. 단일 ML 모델로 두 케이스를 동시에 최적화할 수 없습니다.

graph LR
    A["ML 판정"] --> B{"임계값 설정"}
    B -->|"높음"| C["FP 감소 / FN 증가"]
    B -->|"낮음"| D["FN 감소 / FP 증가"]
    C --> E["우수 셀러 보호 우선"]
    D --> F["사기 차단 우선"]

데이터 부족 문제: ML 모델은 학습 데이터가 충분할 때만 동작합니다. 셀러 1,000명 규모에서는 사기 케이스가 연간 10건 미만으로, 모델이 “사기”를 학습할 데이터 자체가 없습니다. 이 단계에서 ML을 도입하면 오히려 과적합된 모델이 엉뚱한 패턴(예: 특정 지역 셀러)을 사기로 학습할 위험이 있습니다. 셀러 10,000명 이상, 누적 사기 케이스 500건 이상이 되기 전까지 ML은 도구 낭비입니다.

대량 상품 업로드 파싱 실패 — 트랜잭션 범위 결정

10만 건 Excel 업로드 중 50,000번째 행에서 파싱 오류가 발생하면 어떻게 됩니까? 두 가지 철학이 충돌합니다.

전체 롤백 방식: 1건이라도 실패하면 전체를 취소합니다. 데이터 일관성은 완벽하지만 셀러 입장에서 49,999건의 유효한 상품이 모두 등록 취소됩니다. 쿠팡 정산 장애와 동일한 패턴입니다.

행 단위 독립 처리 방식: 각 행을 독립 트랜잭션으로 처리합니다. 50,000번째 행이 실패해도 나머지 99,999건은 정상 등록됩니다. 단, 셀러가 나중에 실패 행만 재업로드하면 멱등성이 보장돼야 합니다.

실패 보고서 형식:
총 업로드: 100,000건
성공: 99,871건
실패: 129건

실패 상세:
행 50,000: 가격 필드 누락 (상품명: "겨울 패딩 자켓")
행 73,241: 금지어 포함 ("마약 다이어트")
행 98,100: 이미지 URL 접근 불가
...

부분 성공의 위험: 셀러가 가격·재고를 일괄 수정하는 용도로 업로드했는데 일부만 반영되면 가격 데이터 불일치가 발생합니다. “가격 수정” 목적의 업로드는 전체 성공/전체 롤백, “신규 상품 대량 등록”은 행 단위 독립 처리로 업로드 목적에 따라 트랜잭션 범위를 달리 설계해야 합니다.

수수료 계산 오류 시 셀러 이의제기 프로세스

수수료 원장은 INSERT만 허용하고 UPDATE는 금지합니다. 그렇다면 오류가 발견됐을 때 어떻게 수정합니까?

올바른 방법: 역분개(Reversal) + 재계산
  1. 원본 수수료 레코드: fee_id=1001, order_id=5000, amount=3,000원, status=APPLIED
  2. 수정 레코드: fee_id=1002, ref_fee_id=1001, amount=-3,000원, type=REVERSAL
  3. 재계산 레코드: fee_id=1003, ref_fee_id=1001, amount=2,700원, type=RECALCULATED

  최종 적용 금액 = SUM(amount WHERE order_id=5000) = 3,000 - 3,000 + 2,700 = 2,700원

이 방식은 감사 추적이 완벽합니다. “왜 수수료가 바뀌었는가”를 fee_id 체인으로 추적할 수 있고, 원본 레코드는 절대 삭제되지 않습니다.

이의제기 SLA: 셀러가 수수료 오류를 신고하면 영업일 3일 이내 검토 완료, 오류 확정 시 다음 정산에 자동 보정 반영, 보정 내역은 정산서에 별도 항목으로 표기합니다. SLA를 초과하면 셀러에게 자동 알림이 가야 합니다.

입점 심사 자동화의 구조적 한계

위조 서류 탐지의 현실: OCR과 정부 API 연동으로 탐지할 수 없는 위조 유형이 존재합니다. 사업자번호는 실제 존재하지만 해당 번호 소유자가 아닌 제3자가 사용하는 경우, 폐업 처리가 수개월 지연된 사업자번호를 악용하는 경우, 통신판매업 신고를 실제로 하고 심사를 통과한 뒤 전혀 다른 상품을 판매하는 경우입니다.

사업자등록번호 실시간 검증 API 한계: 국세청 사업자 상태 조회 API는 다음을 확인하지 못합니다.

  • 사업자번호 소유자가 신청인 본인인지 (명의 도용)
  • 실제 영업 중인지 (폐업 처리 지연)
  • 제출한 사업자등록증 이미지가 해당 번호의 원본과 동일한지

따라서 자동 심사 통과는 “서류가 형식적으로 유효하다”는 의미이지 “이 사람이 믿을 수 있다”는 의미가 아닙니다. 이 간극을 입점 후 행동 모니터링(관찰 모드)이 메웁니다.

페널티 시스템 오작동 — 자동 제재 + 복구 시나리오

자동 제재 시스템은 버그가 있을 때 가장 위험합니다. 스코어링 엔진의 집계 쿼리 오류로 정상 셀러 1,000명이 동시에 “주의” 등급으로 잘못 분류된 사례를 가정합니다.

오작동 탐지 지표: 평소 일 페널티 발생 건수가 50건인데 갑자기 1,000건이 발생하면 시스템 오류를 먼저 의심해야 합니다. “페널티 발생 건수 전일 대비 5배 초과” 알림을 운영팀에 즉시 발송하고, 해당 배치 실행을 일시 중단합니다.

graph LR
    A["제재 배치 실행"] --> B["이상 건수 감지기"]
    B -->|"정상 범위"| C["제재 적용"]
    B -->|"5배 초과"| D["배치 중단"]
    D --> E["운영팀 알림"]
    E --> F["수동 검토"]
    F -->|"오류 확인"| G["일괄 복구"]

대량 오제재 복구 절차:

  1. 오제재 대상 셀러 명단 추출 (영향 범위 파악)
  2. 제재로 인해 차단된 기능 즉시 복구 (신규 상품 등록 재활성화)
  3. 셀러 전원에게 사과 문자 + 보상 쿠폰 자동 발송
  4. 원인 분석 보고서 작성 및 재발 방지 방안 수립

4-추가2. 동시성과 락 — 실무에서 놓치는 두 가지 시나리오

시나리오 A: 동일 셀러가 상품 1,000개 동시 업로드

셀러가 프론트엔드 버그로 동일한 10만 건짜리 Excel을 세 번 연속 업로드했습니다. 세 개의 UploadJob이 Kafka에 동시에 들어갑니다. 각 Job이 10만 건씩 처리하면 30만 건이 생성되고, 멱등성이 없으면 상품이 세 벌로 복제됩니다.

DB 큐 방식 vs Kafka 순서 보장 비교:

방식 장점 단점 동시 업로드 처리
파일 락 (S3 Object Lock) 단순 분산 환경에서 구현 어려움 두 번째 업로드 차단
DB 큐 (상태 머신) 명확한 상태 관리 DB 부하 PENDING 상태 확인 후 중복 거부
Kafka + 멱등 UPSERT 높은 처리량 중복 메시지 가능 (seller_id, external_product_id) UPSERT

실무 선택: Kafka Consumer가 ProductIngestionTask를 처리할 때 (seller_id, external_product_id) 조합으로 UPSERT를 수행합니다. 동일 상품이 세 번 처리돼도 DB에는 한 건만 남습니다. 단, 셀러가 의도적으로 서로 다른 external_product_id를 붙여 업로드하면 중복이 발생하므로, 상품명+카테고리+가격 해시를 퍼지 중복 감지에 활용합니다.

Kafka Producer 배치 설정 최적화: 대량 업로드 시 Producer가 각 행을 개별 메시지로 발행하면 10만 건 = 10만 번의 네트워크 왕복이 발생합니다.

# 비효율 설정 (기본값)
linger.ms=0          # 즉시 발송
batch.size=16384     # 16KB 배치

# 대량 업로드 최적화 설정
linger.ms=50         # 50ms 대기 후 묶어서 발송
batch.size=1048576   # 1MB 배치
compression.type=snappy  # CPU 사용 대비 네트워크 절감

이 설정으로 10만 건 업로드의 Kafka 발행 시간이 약 80% 단축됩니다. 단, linger.ms를 높이면 실시간성이 낮아지므로 대량 업로드 전용 Kafka Topic을 별도로 운영하고 일반 상품 등록 Topic과 분리합니다.

상품 등록 이벤트 팬아웃: 상품이 등록되면 여러 하위 시스템이 동시에 반응해야 합니다.

graph LR
    A["ProductCreated 이벤트"] --> B["검색 인덱싱"]
    A --> C["가격 동기화"]
    A --> D["재고 초기화"]
    A --> E["카탈로그 매칭"]

각 Consumer는 독립적으로 실패할 수 있습니다. 검색 인덱싱이 실패해도 재고 초기화는 완료됩니다. 실패한 Consumer는 자체 재시도 큐에서 복구합니다. 이 팬아웃 구조가 없으면 상품 등록 서비스가 검색, 재고, 가격 서비스를 직접 HTTP로 호출하게 되어 하나의 장애가 전체 등록 실패로 전파됩니다.

시나리오 B: 수수료율 변경 중 정산 배치 실행

오전 10시에 전자제품 수수료율을 6%에서 7%로 변경하는 작업이 진행 중입니다. 정확히 같은 시각, 어젯밤부터 실행 중이던 정산 배치가 전자제품 주문의 수수료를 계산하고 있습니다. 정산 배치는 6%를 읽어야 하는가, 7%를 읽어야 하는가?

읽기 일관성 보장 방법 — 스냅샷 격리:

-- 수수료 정책 버전 관리 테이블
fee_policy_versions:
  version_id  | category_id | rate | valid_from          | valid_to
  v_101       | electronics | 0.06 | 2024-01-01 00:00:00 | 2026-05-21 10:00:00
  v_102       | electronics | 0.07 | 2026-05-21 10:00:00 | NULL (현재 유효)

-- 정산 배치의 수수료 조회 (주문 완료 시각 기준)
SELECT rate FROM fee_policy_versions
WHERE category_id = 'electronics'
  AND valid_from <= :order_completed_at
  AND (valid_to IS NULL OR valid_to > :order_completed_at)

정산 배치는 “주문이 완료된 시각”을 기준으로 그 시점에 유효했던 정책 버전을 조회합니다. 수수료율 변경이 아무리 많이 일어나도 과거 주문의 수수료는 바뀌지 않습니다. 트랜잭션 격리 수준(Isolation Level)을 REPEATABLE READ 이상으로 설정하고, 배치 시작 시점의 스냅샷으로 일관되게 읽습니다.

위험한 설계: fee_policies 테이블에서 현재 유효한 율만 관리하고 UPDATE로 변경하면, 배치 실행 중 율이 바뀌는 순간 이미 처리된 주문과 아직 처리되지 않은 주문이 서로 다른 율로 계산됩니다. 동일 정산 기간 내에 일부는 6%, 일부는 7%로 계산되는 데이터 불일치가 발생합니다.


4-추가3. 오버엔지니어링 경고 — 셀러 규모별 적정 복잡도

가장 흔한 실수는 “언젠가 10만 명이 될 것”을 대비해 처음부터 ML 스코어링과 Kafka 팬아웃을 설계하는 것입니다. 식당이 손님 3명일 때 미쉐린 3스타 주방 시스템을 도입하는 것과 같습니다.

셀러 100명: 어드민 + 수동이 정답

적정 스택: 어드민 페이지(Django Admin/ActiveAdmin) + MySQL 1대
입점 심사: 이메일로 서류 수신 → 담당자 수동 검토 → 슬랙 메시지로 결과 통보
스코어링: 주 1회 SQL 쿼리 실행 → 스프레드시트 업데이트
정산: 월말 엑셀 집계 → 수동 이체
페널티: 운영팀 텔레그램 그룹 채팅으로 처리

이 단계에서 Kafka를 도입하면 메시지 유실, Consumer Group 관리,
Schema Registry 운영 부담이 셀러 심사 업무보다 더 많아집니다.

셀러 1,000명: 자동 서류 검증 도입

추가할 것:
  - 국세청 API 자동 검증 (일 호출 500건 이하, 무료 티어 충분)
  - 수수료 계산 자동화 배치 (일 1회)
  - 정산 자동 이체 배치 (주 1회)
  - 기본 알림 (이메일/SMS)

아직 필요 없는 것:
  - Kafka (RabbitMQ나 DB 폴링으로 충분)
  - ML 스코어링 (사기 케이스 데이터 부족)
  - 마이크로서비스 (단일 서비스로 충분)
  - Redis Cluster (단일 Redis 인스턴스로 충분)

셀러 10,000명+: ML 스코어링 조건부 도입

ML 도입 전 충족 조건:
  1. 사기/어뷰징 케이스 누적 500건 이상 (학습 데이터)
  2. 룰 기반 시스템의 False Positive율 > 15% (ML 개선 여지 있음)
  3. ML 모델 설명 가능성 확보 (셀러에게 "왜?"를 답할 수 있어야 함)
  4. 모델 재학습 파이프라인 운영 인력 확보

조건 미충족 시 ML 도입 위험:
  - 데이터 부족 → 과적합 → 특정 지역/업종 셀러 편향 제재
  - 블랙박스 판정 → 이의신청 대응 불가 → 법적 분쟁
  - 모델 드리프트 감지 부재 → 시간이 지날수록 정확도 하락

단계별 복잡도 요약:

규모 핵심 도구 금지 사항
셀러 100명 어드민 + 수동 처리 Kafka, ML, 마이크로서비스
셀러 1,000명 자동 검증 API + 배치 ML 스코어링, Kafka
셀러 10,000명+ Kafka + 실시간 스코어링 ML (데이터 500건 미만이면)
셀러 100,000명 ML + Flink + 마이크로서비스 단일 모놀리식 유지

“셀러가 적을 때 ML은 데이터 부족으로 오히려 위험합니다. 룰 기반으로 쌓은 레이블 데이터가 ML의 원료입니다. 룰 없이 ML을 먼저 도입하면 학습 데이터도, 검증 기준도 없는 상태에서 모델이 운영됩니다.”


5. 실무 실수 Top 5

# 실수 결과 올바른 방법
1 정산 전체를 단일 배치 트랜잭션으로 처리 중간 장애 시 전원 롤백, 대규모 민원 셀러별 독립 트랜잭션 + 재시도 큐
2 수수료 계산에 float/double 사용 소수점 오차 누적으로 월 수십만 원 불일치 BigDecimal, DB DECIMAL(15,4) 타입
3 스코어 하락 즉시 제재 적용 일시적 이상치(공격·시스템 오류)로 선의 셀러 피해 이상 감지 후 검증 기간 + 이의신청 보장
4 입점 심사 자동 검증 통과 = 신뢰 가짜 서류·도용 정보 100% 탐지 불가 자동 검증 + 입점 후 행동 모니터링 병행
5 페널티 사유 불명확한 통보 셀러 이탈, 법적 분쟁 구체적 위반 건수·날짜·기준 명시 + 이의신청 절차 안내

6. Phase 1→4 진화

Phase 1 — MVP (셀러 1,000명 이하)

월 비용: 약 100만 원

수동 심사 비중이 높고, 스코어링은 주 1회 배치로 단순 계산합니다. 정산은 월 1회 수동 처리도 가능합니다.

구성: API 서버 2대 + MySQL 1대 + S3
입점 심사: 이메일로 서류 수신, 담당자 수동 검토
스코어링: 주 1회 Python 스크립트 배치
정산: 월말 Excel 집계 후 수동 이체 또는 단순 배치
페널티: 운영자 수동 처리

Phase 2 — 성장기 (셀러 1만 명)

월 비용: 약 500만 원

입점 심사 자동화 파이프라인 도입, 스코어링을 일 배치로 전환합니다. 정산 자동화 배치를 구축합니다.

구성: API 서버 4대 + MySQL Primary-Replica + Redis + S3 + Kafka
입점 심사: OCR + 국세청 API 자동 검증, 심사관 2차
스코어링: 일 1회 자동 배치, 이상 급등 알림
정산: 주 1회 자동 배치, 은행 API 연동, 재시도 큐
상품 검수: 금지어 자동 필터, 이미지 AI 검수

Phase 3 — 중규모 (셀러 5만 명)

월 비용: 약 2,000만 원

서비스별 분리, 스코어링 실시간 집계, 정산 셀러별 독립 트랜잭션 전환이 필요해지는 시점입니다.

구성: 마이크로서비스 분리 (입점/상품/정산/스코어/페널티)
      API 서버 8대 + MySQL 샤딩 + Redis Cluster + Kafka + Elasticsearch
입점 심사: 자동화율 80%, 카테고리별 추가 서류 자동 체크
스코어링: 이벤트 기반 실시간 집계 (배송/CS/반품)
정산: 셀러별 독립 트랜잭션, 주 2회 정산, idempotency 키
페널티: 위반 유형별 자동/수동 혼합, 이의신청 워크플로우

Phase 4 — 대규모 (셀러 10만 명)

월 비용: 약 5,000만 원

ML 기반 이상 탐지, 셀러 성장 코칭 자동화, 글로벌 셀러 지원이 추가됩니다.

구성: 서비스별 독립 배포 + API 서버 20대 이상 + MySQL 샤딩 + Redis Cluster
      Kafka + Flink + ML 서빙 인프라 + Elasticsearch + 글로벌 CDN
입점 심사: 사기 셀러 ML 탐지, 서류 위조 이미지 AI 분석
스코어링: ML 이상 탐지 (가짜 리뷰·반품 공격), 실시간 이벤트 스트리밍
정산: 일 1회 정산, 10분 이내 즉시 정산 옵션 (수수료 추가)
셀러 코칭: 스코어 하락 예측 + 개선 액션 자동 추천

7. 핵심 메트릭

메트릭 설명 목표값 측정 방법
입점 심사 소요 시간 신청 접수부터 최종 결정까지 영업일 1일 이내 심사 상태 전이 타임스탬프
자동 검증 통과율 자동 검증 1차 통과 비율 70% 이상 검증 단계별 결과 카운트
정산 오류율 전체 정산 건 중 금액 오류·미지급 비율 0% 대사 배치 결과
정산 처리 시간 트리거 발생부터 이체 완료까지 2시간 이내 (배치 기준) 정산 상태 전이 타임스탬프
스코어 산출 지연 이벤트 발생부터 스코어 갱신까지 6시간 이내 이벤트 타임스탬프 vs 스코어 갱신 시각
페널티 이의신청 인용율 제기된 이의신청 중 인용된 비율 10% 이하 (과도하면 기준 재검토) 이의신청 처리 결과
셀러 이탈율 (월) 월간 활동 중단 셀러 비율 2% 이하 활성 셀러 수 추이
수수료 계산 레이턴시 P99 주문 완료 이벤트 수신부터 수수료 원장 기록까지 200ms 이내 이벤트 처리 타이머

8. 실제 장애 사례

사례 1: 쿠팡 마켓플레이스 — 정산 배치 전체 롤백 (2022)

월말 정산 배치가 DB 연결 풀 고갈로 중간에 실패했고, 단일 트랜잭션 설계로 인해 60% 완료된 정산이 전부 롤백됐습니다. 이미 은행 이체가 완료된 셀러에게는 금액이 빠져나갔지만 DB에는 완료 기록이 없는 “유령 이체”가 일부 발생했습니다. 복구에 3일이 소요됐고 대규모 셀러 민원이 발생했습니다.

근본 원인: 정산 배치 전체를 @Transactional로 묶고, 내부에서 은행 외부 API를 동기 호출한 것이 문제였습니다. 외부 API 응답 지연으로 트랜잭션이 길어졌고, DB 커넥션이 모두 소진됐습니다.

대응: 은행 이체를 트랜잭션 외부로 분리하고, 이체 결과를 별도 이벤트로 수신해 DB를 갱신하는 이벤트 소싱 방식으로 전환했습니다. 셀러별 독립 트랜잭션으로 재설계했습니다.

사례 2: G마켓 — 수수료 계산 float 오류로 정산 불일치

2020년 대규모 정산 감사에서 셀러 수백 명의 정산 금액이 실제보다 수백 원에서 수만 원 차이 나는 것이 발견됐습니다. 원인은 수수료 계산에 Java double 타입을 사용한 것이었습니다. 개별 주문에서는 1~2원 오차지만 월 10만 건 누적 시 수만 원 차이로 벌어졌습니다.

근본 원인: double 타입의 부동소수점 연산 오차. 10000 * 0.03 = 299.99999999999994 같은 계산이 누적됩니다.

대응: 모든 수수료 계산을 BigDecimal로 교체하고, DB 컬럼 타입을 DOUBLE에서 DECIMAL(15,4)로 변경했습니다. 기존 3년치 정산 데이터를 재검증해 차이가 있는 셀러에게 소급 보정했습니다.

사례 3: 11번가 — 카테고리 권한 없는 셀러 상품 노출

상품 관리 서비스 배포 중 카테고리 권한 검증 로직이 실수로 비활성화됐습니다. 12시간 동안 의약품·총기 관련 카테고리에 일반 셀러 상품이 등록되어 노출됐습니다. 플랫폼이 인지하기 전에 일부 상품이 구매됐고, 규제 당국으로부터 행정지도를 받았습니다.

근본 원인: 배포 시 기능 플래그(Feature Flag)가 잘못 설정됐고, 카테고리 권한 검증을 우회하는 테스트 코드가 프로덕션에 남아있었습니다.

대응: 카테고리 권한 검증을 API Gateway 레벨에서 2중으로 적용하고, 배포 전 보안 카테고리 등록 시도 시나리오를 자동화 테스트에 포함했습니다.


9. 확장 포인트

셀러 성장 코칭 자동화: 스코어 구성 요소 중 하위 지표를 분석해 “배송 지연율이 업종 평균보다 3%p 높습니다. 출고 마감 시간을 2시간 앞당기는 것을 권장합니다”와 같은 자동 코칭 메시지를 발송합니다. 셀러 품질이 올라가면 플랫폼 전체 신뢰도도 올라갑니다.

셀러 자금 조달 연동: 정산 이력과 스코어를 기반으로 플랫폼이 직접 또는 제휴 금융사와 셀러 운영자금 대출을 연결합니다. 정산 데이터는 신용 평가에 활용할 수 있는 고품질 데이터입니다.

크로스보더 셀러 지원: 해외 셀러 입점 시 국가별 사업자 인증 API(예: 중국 국가시장감督管理总局 API), 해외 통관 서류 검증, 다통화 정산 기능을 확장 포인트로 설계합니다.

셀러 마켓플레이스 API 개방: 대형 셀러가 자체 ERP·WMS 시스템과 실시간 연동할 수 있도록 Webhook + REST API를 공개합니다. 셀러 이탈을 줄이는 “잠금 효과(Lock-in)”가 있습니다.


면접 포인트

Q. 셀러 스코어링에서 이동평균을 쓰는 이유가 무엇인가요? 셀러의 배송 지연이 어제 하루 폭설로 인해 10건 발생했다고 해서 등급을 즉시 떨어뜨리는 것은 불공평합니다. 이동평균은 일시적 이상치의 영향을 희석합니다. 30일 이동평균을 쓰면 어제 하루 10건은 전체 30일 데이터 중 1/30의 가중치만 갖습니다. 반면 지속적으로 나쁜 셀러는 30일 모든 구간에서 나쁜 수치가 누적되므로 평균이 낮게 유지됩니다. 다만, 이동평균 기간이 너무 길면 실제로 개선된 셀러가 과거 데이터 때문에 낮은 등급을 유지하는 문제가 생깁니다. 30일과 7일 가중 복합을 쓰는 이유가 여기에 있습니다.
Q. 정산에서 idempotency key를 왜 셀러 ID + 정산 주기 + 금액으로 만드나요? 정산 재시도는 반드시 발생합니다. 은행 API 타임아웃, 네트워크 오류, 서버 재시작 등 수십 가지 이유로 이미 이체됐는지 모른 채 재시도하게 됩니다. idempotency key가 없으면 1억 원이 두 번 이체됩니다. 키를 셀러 ID + 정산 주기(2026년 5월)로만 만들면 금액이 바뀐 수정 정산을 처리할 수 없습니다. 금액까지 포함하면 금액이 달라진 수정 정산은 새 키가 되어 정상 처리되고, 동일 금액의 중복 요청만 차단됩니다. 단, 은행 API가 idempotency key를 지원하지 않으면 플랫폼 레이어에서 중복 요청 여부를 직접 DB에서 확인 후 실행합니다.
Q. 입점 심사 자동화율을 100%로 높이지 않는 이유는 무엇인가요? 자동화가 할 수 없는 판단이 있습니다. 사업자등록증이 진짜이고 API 검증도 통과했지만, 판매 예정 상품 설명이 해당 카테고리와 맞지 않거나, 대표자 이름과 실제 운영자가 다른 명의 도용 의심이 있는 경우입니다. 또한 신규 카테고리(예: AI 소프트웨어 판매)처럼 기존 규칙에 없는 형태의 셀러는 자동 시스템이 판단 기준을 갖지 못합니다. 자동화 80% + 심사관 20% 구조에서 심사관은 가장 판단이 필요한 케이스에만 집중하므로 품질과 속도를 동시에 달성합니다. 100% 자동화를 추구하면 오히려 사기 셀러 유입이 늘어납니다.
Q. 셀러가 페널티를 받았을 때 이의신청을 허용하면 운영 부담이 크지 않나요? 이의신청은 비용이 아니라 투자입니다. 이의신청이 없으면 부당 제재를 받은 셀러가 조용히 플랫폼을 떠나고 나중에 소송이나 언론 보도로 돌아옵니다. 이의신청을 허용하면 제재 기준의 오류를 조기에 발견할 수 있습니다. 이의신청 인용율이 30%를 넘으면 제재 기준 자체가 잘못된 것입니다. 운영 부담을 줄이려면 이의신청 폼을 표준화하고, 명백한 기준 위반(예: 가짜 상품)은 이의신청 대상에서 제외하며, 심사 결과를 템플릿으로 빠르게 발송하는 반자동화 처리 시스템을 갖추면 됩니다.
Q. 셀러 스코어와 노출 알고리즘을 어떻게 연결하나요? 직접 연결과 간접 연결 두 가지 방식이 있습니다. 직접 연결은 스코어가 높을수록 검색 결과 상단에 노출합니다. 이 방식은 투명하지만 오래된 대형 셀러가 항상 상위를 독점해 신규 우수 셀러의 진입이 어렵습니다. 간접 연결은 스코어를 노출 알고리즘의 여러 시그널 중 하나로 사용하고, 상품 관련성·가격 경쟁력·신선도를 함께 고려합니다. 실무에서는 스코어 하위 셀러에게 노출 페널티를 적용하는 네거티브 방식이 더 흔합니다. 스코어 70점 미만이면 검색 노출에서 제외하는 임계 기반 설계가 단순하고 셀러에게 명확한 기준을 제시합니다.

함께 읽으면 좋은 글

댓글

이 글이 도움이 됐다면?

같은 카테고리의 다른 글도 확인해보세요

더 많은 글 보기 →