경매서비스 #6 - 경매 API

이번에는 본 서비스의 핵심 기능인 경매기능을 설계하고 구현합니다.

경매기능에서 가장 중요한건 무엇일까요? 그것은 정확한 가격입찰입니다. 현재 가격보다 높은 가격의 입찰만 성공시키고 같은 가격의 입찰이 동시에 여러건 발생하는 경우 가장 먼저 발생한 하나의 입찰만 성공시켜야합니다. 그리고 이를 동시성 제어라고 합니다. 물리적 제한이 없는 온라인 서비스에서는 동시성을 제어해서 데이터 정합성, 무결성을 보장하는것이 보장하는것이 매우 중요합니다.

  • 정합성 (Inconsistency)
    • 데이터가 서로 모순되지 않고 일관성을 유지하는 것
  • 무결성 (Integrity)
    • 데이터의 정확성, 완전성, 신뢰성을 보장하는 것

위와 같은 사항을 보장하기 위해 다음과 같이 정의합니다.

  • 레디스 사용
  • 경매시에는 레디스 정보만 신뢰함, 즉 MySql과 싱크가 안맞아도 괜찮음

레디스

[레디스 설명]

[경매 동작에 대한 그림]

경매 시작

  • 상품정보를 레디스에 해시로 저장
    • 키: product:{id}
    • 값: 시작가격, 현재가격(0), 구매자, 시작시간, 종료시간, 상태(중지여부)
  • MySql의 상품상태 업데이트

가격 제시

  • 가격 입찰 가능 검증
    • product:{id}가 존재하는지
    • 현재 시간이 시작 시간 ~ 종료시간 사이에 존재하는지
    • 상태가 판매중인지
    • 제시한 가격이 현재 가격보다 높은지
  • product:{id} 갱신
    • 현재가격, 구매자
  • 입찰 기록을 레디스에 리스트로 저장
    • 키: product:{id}:auctions
    • 값: json, 입찰 시도 정보 (유저id, 가격, 시간)
  • 메시지(카프카) 발행
  • 메시지 소모 및 MySql 정보 저장
    • 상품 정보 업데이트
    • 경매 기록 저장

경매 중지

  • product:{id}stateSTOP로 변경

경매 종료

  • product:{id}stateFINISHED로 변경
    • 또는 제거

가격제시시 상품의 상태와 함께 종료시간을 확인합니다. 때문에 상태를 변경하지 않아도 더이상 가격을 제시할 수는 없지만 타이밍 이슈상 사용자에게 경매중의 정보를 보여줄 수 있습니다. 이를 방어하기 위해 경매 종료시간이 되면 레디스의 product:{id}에 존재하는 stateFINISHED로 변경합니다.

경매기능에서는 경매가능 여부 판단입찰 성공 여부 판단을 하는것이 중요합니다. 상품 가격에 대한 현재 상품가격보다 더 높은 가격을 제시하면 구매권한을 받을 수 있는 기능입니다. 만약 정말 좋은 제품이

  • 레디스 정보와 데이터베이스 정보의 싱크를 어떻게 맞출것인가?
  • 경매 기록 목록을 어디에 저장할 것인가?

References