본문 바로가기
개발 이것저것

밀키트 도메인의 주문-결제 흐름 개선하기

by chanwoodev 2023. 9. 3.

밀키트 도메인의 특성 분석

  • 사용자는 유통기한이 5일 이상 남아있는 제품을 받아야함
  • 재고의 유통기한을 주기적으로 관리해주어야함 - 유통기한 임박 제품을 사용자에게 제공하면 안됨
  • 일자별 재고를 따로 관리해주어야 함

상품 - 재고 데이터

주문 흐름 설계

 

전체적으로 주문 flow를 동기적으로 구성했음

 

1. 주문을 하려면 수량을 확보해야함

2. 재고 감소를 반영해야함 (향후 배치 작업으로 분리함)

3. 상품 수량을 감소시켜야함

4. 결제 처리를 진행해야 함 (Toss 테스트 결제 서버)

 

위의 동기적 방식을 진행하면서 상품 수량에 대해 동시성 이슈가 있기 때문에 비관적 락을 걸어 문제를 해결함

 

 

주문-결제 진행(Front 붙힘)

 

문제 발생

부하 테스트 진행 

- EC2 t4small server 대상 테스트입니다

 

nGrinder을 사용해 vUser 20 기준으로 한 상품 구매 요청 진행

  • 결제 지연 시간은 Toss 테스트 서버 기준 평균 1.2초 ->  평균 1.2, 표준편차 0.2 정규 분포로 지연시간 부과 

DB connection pending / 평균 TPS 0.8

DB connection은 pending 상태이며 TPS평균 0.8인 매우 좋지 않은 성능 

 

문제점: 주문과 결제가 한 트랜잭션으로 묶여있음

  • DB 커넥션을 획득하고 결제 처리가 끝날 때까지 놓지 않음 (지연 시간 평균 1.2초)
  • 비관적 락 때문에 다른 사용자들은 을 획득하지 못함

문제 해결

 

트랜잭션 분리 진행

 

주문 처리를 진행하는 트랜잭션, 결제 처리를 진행하는 트랜잭션을 분리함

 

//주문 흐름
//No Transaction
public void pay(final AuthPrincipal authPrincipal, final Long orderId, final OrderPayRequest request) {
    orderPlaceService.place(authPrincipal, orderId);  // @Transactional
    orderPayService.pay(orderId, request.getPaymentKey()); // No Transaction
}

 

// OrderPayService.class

@Counted("order.payment.request")
public void pay(final Long orderId, final String paymentKey) {
    log.info("결제 요청 subscribe event: {}", paymentKey);

    Order order = orderRepository.findById(orderId).orElseThrow(OrderNotFoundException::new);

    paymentClient.validatePayment(paymentKey, order.getUuid(), order.getTotalPrice())
        .publishOn(Schedulers.boundedElastic())
        .doOnSuccess(ignore -> payResultHandler.save(orderId, paymentKey))
        .doOnError(error -> payResultHandler.rollback(orderId, error))
        .onErrorMap(IllegalArgumentException.class, InvalidPayRequestException::new)
        .onErrorMap(IllegalStateException.class, PayFailedException::new)
        .block();
}

위와 같이 트랜잭션을 분리함으로써 DB커넥션을 빨리 놓을 수 있었음

 

nGrinder 상품 구매 테스트

Vuser 20명 기준 평균 TPS 14.6, 평균 응답시간 1.37s

처음에 비해 같은 조건에서 17배의 주문-결제 처리로 개선  (EC2 t4 small 1대 기준)

 

다양한 상품 구매 테스트 진행 - 추가 진행

20% 상품에 80%의 구매가 몰리도록 설정  (EC2 t4 small 1대 기준)

 

120 Vser 기준 평균 84 TPS 

 

Load Average/ CPU Core Size가 1을 넘지 않는 기준으로 측정했으며 예상한 시나리오보다 더 충분한 TPS 성능을 보여주었음