SY 개발일지
article thumbnail

사용자가 쿠폰을 발급하는 과정에서 동시성 테스트를 해보았습니다.

 

동시성 문제 발생

현재 로직은 다음과 같습니다.

사용자가 쿠폰을 발급할 수 있는 상태를 확인하여 발급합니다.

@Override
@Transactional
public void issueCoupon(Long customerId, Long couponId) {
    Coupon coupon = couponRepository.findById(couponId).orElseThrow(() -> new RestApiException(CommonErrorCode.ENTITY_NOT_FOUND));
    Customer customer = customerRepository.findById(customerId).orElseThrow(() -> new RestApiException(UserErrorCode.USER_NOT_FOUND));

    // 발급 조건 확인
    // 1. 잔여 수량이 1 이상인지
    if (coupon.getRemainQuantity() == 0) throw new RestApiException(CouponErrorCode.REMAIN_QUANTITY_ZERO);
    // 2. 종료처리가 되어있지 않으면서 발급 기간인지
    else if (coupon.getDisable()) throw new RestApiException(CouponErrorCode.FINISH_COUPON_ISSUE); // 발급 종료 쿠폰
    // 3. 발급 기간인지
    else if (coupon.getStartAt().isAfter(LocalDateTime.now()) || coupon.getFinishAt().isBefore(LocalDateTime.now())) throw new RestApiException(CouponErrorCode.NOT_ISSUE_PERIOD); // 발급 종료 쿠폰
    
    coupon.issueCoupon();
    IssueCoupon issueCoupon = IssueCoupon.builder()
            .customer(customer)
            .coupon(coupon)
            .isUsed(false)
            .expiredAt(LocalDateTime.now().plusMinutes(coupon.getExpiredMinute()))
            .build();

    issueCouponRepository.save(issueCoupon);
    issueCoupon.setQrImage(makeQrCode(issueCoupon));
}

 

또한 레포지토리에는 따로 락을 사용하지 않았습니다.

 

테스트를 위해 수량이 20개인 쿠폰을 준비하였습니다.

 

테스트는 Jmeter를 이용하여 동시에 50명의 유저가 쿠폰발급을 신청한다고 가정하였습니다.

 

결과

결과는 다음과 같았습니다. 쿠폰 테이블에서는 단 3명만이 쿠폰을 발급하였다는 결과가 나왔지만,

실제로 아래 쿼리문을 보면 8명의 유저가 쿠폰을 발급받았음을 확인할 수 있었습니다.

심지어 스프링을 통해 테스트를 돌렸을 경우 데드락(DeadLock)도 발생하였음을 확인하였습니다.

 

 

비관적 락 사용

그래서 이번에는 쿠폰을 가져오는 레포지토리에 비관적락을 사용해보았습니다. 동일하게 50명의 유저가 동시에 쿠폰발급을 요청한다고 가정하였습니다.

 

 

 

결과

결과는 다음과 같이 나왔습니다. 정상적으로 잔여수량이 0이 나왔으며,

 

쿠폰 발급 테이블을 확인하여도, 정확하게 20개의 데이터만이 삽입되었음을 확인할 수 있었습니다.

count(*)로 확인

결론

선착순 쿠폰 등 뿐 아니라 동시에 값이 변경되는 위치에서는 락을 사용해 줌으로써 데이터의 정합성을 지킬 수 있음을 확인하였습니다. 이러한 요소 하나하나가 모여 서비스를 더욱 안정적으로 제공할 수 있다고 생각합니다.

profile

SY 개발일지

@SY 키키

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!