pile·
백엔드·마켓컬리마켓컬리 Hello World·

쿠폰과 할인으로 앞다리살 하나 더 판매한 이야기

컬리 쿠폰 시스템에서 "사용할 수 없는 쿠폰을 사용 시도"한 이상 현상을 Zipkin traceId와 Kibana 로그로 추적한 디버깅 사례다. 주문서 단계에선 쿠폰이 유효했는데 결제 단계에서 상품 할인율이 20%에서 25%로 바뀌며 장바구니 총액이 3만원 아래로 떨어져 쿠폰 조건에 미달한 것이 원인이었고, 애플리케이션이 조건 미달 쿠폰을 정상 차단한 것을 검증한 케이스다.

핵심 포인트
  • 11만 건 쿠폰 발급일 저녁, 사용 불가 쿠폰 사용 시도가 보고돼 시스템 오류나 공격 가능성을 열어두고 분석을 시작했다.
  • Zipkin에서 traceId로 사용자 번호(3391434)와 쿠폰(1만원 할인, 3만원 이상 주문 조건)을 역추적했고, RESTful URI 설계가 추적에 도움이 됐다.
  • Kibana API 호출 로그에서 주문서 단계 쿠폰 조회 API는 "사용 가능"을 리턴한 것을 확인했다.
  • 결제 단계에서 상품(오로라 생연어) 할인율이 20%에서 25%로 변동돼 총액이 30,080원에서 28,930원으로 떨어져 조건에 미달했다.
  • 결론은 악의적 조작이 아니라 할인율 변동으로 조건이 어긋난 것이고, 앱이 쿠폰 사용을 정상 차단한 정상 케이스였다.
상세 정리
  • 발견: 사용자 UI상 불가능한 쿠폰 사용 시도가 22시 12분경 보고돼 오류 또는 공격 가능성으로 보고 분석에 착수했다.
  • Zipkin 조회: 보고된 traceId로 사용자 번호와 쿠폰 발행번호를 특정해 어떤 쿠폰이 문제인지 좁혔다.
  • 로그 대조: Kibana에서 사용 불가 로그 바로 아래 주문서 쿠폰 조회 로그가 "사용 가능"을 리턴한 것을 보고, 주문서와 결제 사이에 상태가 바뀌었음을 파악했다.
  • 장바구니 비교: 주문서 22:05 총액 30,080원, 결제 22:12 총액 28,930원으로, 오로라 생연어 가격이 18,400원에서 17,250원으로 하락했다.
  • 원인: 두 시점 사이 약 6분 동안 해당 상품 할인율이 20%에서 25%로 변동돼 총액이 쿠폰 조건 3만원 아래로 떨어졌고, 사용자의 가격 조작은 아니었다.
  • 마무리: 사용자는 앞다리살 상품을 추가로 담아 총액 31,090원을 맞춰 쿠폰을 사용했고, 결과적으로 매출 1,010원이 늘었으며 앱은 조건 미달 쿠폰을 정상 방어했다.
왜 읽나분산 추적(Zipkin)과 로그(Kibana)로 커머스 쿠폰·결제 이상을 단계별로 진단하는 실제 흐름을 보고 싶은 백엔드 개발자에게.
마켓컬리
마켓컬리 Hello World 블로그
원문은 여기서 이어서 읽을 수 있어요
원문 읽기
읽음 (0)

이 글과 비슷한

  1. 백엔드·github-engGitHub Engineering·

    조기 종료를 없애야 벡터화된다 — 메모리 속도 소스 코드 케이스 폴딩

    GitHub의 코드 검색 엔진 Blackbird는 480TB 이상의 소스 코드를 인덱싱하기 전 모든 바이트에 case folding을 적용한다. 이 글은 Rust로 구현한 case folding을 메모리 대역폭 한계(45+ GiB/s)까지 끌어올린 두 가지 반직관적 최적화를 상세히 다룬다. 핵심은 루프 조기 종료(break) 제거로 LLVM 벡터화를 유도하고, UTF-8을 디코딩하지 않고 바이트 공간 산술만으로 fold를 수행하는 것이다.

    #rust#unicode#simd+2
  2. 백엔드·여기어때 (GC컴퍼니)여기어때 (GC컴퍼니)·

    트랜잭션 스크립트에서 숙소 메타 + 가격 계산 모듈로 — 전시 아키텍처 개선기 (2/3)

    여기어때 전시개발팀이 숙소 상세(PDP) API를 해부한 결과, 코드상으로는 DB 호출 3번처럼 보이던 요청이 실제로는 MongoDB $lookup 체인으로 컬렉션을 19회 접근하는 구조였다. 이 트랜잭션 스크립트 방식의 핵심 문제는 "aggregation이 I/O를 가린다"는 점으로, 독립적인 쿼리 10개가 단일 파이프라인에 직렬화되어 병렬화 기회를 잃고, 가격 때문에 거의 안 바뀌는 이미지까지 매 요청마다 읽어야 하는 읽기 증폭이 발생했다. V3에서는 "조회 시점 조립"을 "쓰기 시점 사전 조립"으로 전환하고, 화면별로 복제되던 가격 계산 로직을 goodsprice 단일 모듈로 수렴했다. 4개 API(PLP/PDP/RDP/ILP)의 반복 마이그레이션은 Claude Code skill로 절차를 고정하고 쉐도잉 + 동일성 검증으로 안전망을 마련하는 방식으로 진행됐다.

    #architecture#migration#caching+2