선착순 쿠폰 발급이나 티켓 예매와 같이 동시에 트래픽이 많이 들어올 경우 동시성 문제가 발생하기 마련이다.
이러한 문제를 해결하기 위해 주로 락을 사용하여 동시성 문제를 해결한다.
이때 한가지 조심해야할 부분이 있다.
동시성 문제가 발생하는 코드 1
@Transactional
fun issue(couponId: Long, userId: Long){
val coupon = findCoupon(couponId);
coupon.issue()
saveCouponIssue(couponId, userId)
}
사용자가 쿠폰 발급 버튼을 누르면 해당하는 쿠폰을 찾아 쿠폰을 발급하는 간단한 로직이다.
동시에 여러명의 유저가 쿠폰발급을 누른다면 락이 존재하지 않기 때문에 쿠폰개수에 대해 동시성 문제가 발생하여 의도한대로 코드가 동작하지 않을 것이다.
동시성 문제가 발생하는 코드? 2
분산환경과 상관없이 테스트용으로 간단히 synchronize를 걸어 오직 하나의 스레드만이 접근할 수 있도록 변경했다.
@Transactional
fun issue(couponId: Long, userId: Long){
synchronized(this){
val coupon = findCoupon(couponId);
coupon.issue()
saveCouponIssue(couponId, userId)
}
}
이렇게 하면 결과가 어떻게 될까?
여전히 동시성 문제가 발생한다.
그 이유는 @Transcation과 관련되어 있다.
@Transaction은 AOP를 기반으로 함수가 시작하기전에 transcation을 열고 함수가 끝나는 시점에 commit을 진행한다.
위 코드는 함수 내부에서 락을 열고 락을 닫기 때문에 transcation이 commit되기전에 다른 스레드가 접근할 수 있게된다.
따라서 여전히 동시성 문제는 해결되지 않는다.
이러한 문제를 해결하기 위해선 해당 함수를 호출하는 곳에서 락을 걸어 해결해야한다.
fun issueRequestV1(requestDto: CouponIssueRequestDto){
synchronized(this){
couponIssueService.issue(requestDto.couponId, requestDto.userId)
}
log.info("쿠폰 발급 완료, couponId: ${requestDto.couponId}, userId: ${requestDto.userId}")
}
'web study > Spring' 카테고리의 다른 글
Spring 익명 객체 함수에 @Transactional을 사용하면 어떻게 될까? (0) | 2024.10.28 |
---|---|
Spring mongodb id mapping bug (0) | 2024.01.05 |
Spring BeanPostProcessor(빈 후처리기) (0) | 2023.12.22 |
프록시 팩토리 | Advice | Pointcut (0) | 2023.12.20 |
Spring Scheduler SchedLock MongoDB 설명 및 구현 (0) | 2023.12.01 |