동시성 이슈 해결방법
- 이번 시간에는 Application Level에서의 해결방법을 알아보자.
해결법1. Synchronized
- Java에서 지원하는 방법 ( 어플리케이션 단 )
- 해당 키워드는 한 개의 스레드만 접근이 가능하도록 해준다.
@Transactional
public synchronized void decrease(Long id, Long quantity) {
Stock stock = stockRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("재고가 존재하지 않습니다."));
stock.decrease(quantity);
stockRepository.saveAndFlush(stock);
}
synchronized
를 추가하고 테스트를 돌려보면?
그래도 실패한다…..
왜 그럴까?
이유는 스프링의 @Transactional
에 있다.
스프링의 트랜잭션 어노테이션은 AOP이므로 프록시를 통해 프록시 객체를 만들어서 수행하게 된다.
대략적으로 아래와 같은 모습으로 진행하게 된다.
/*
프록시 객체
*/
public class TransactionStockService {
private final StockService stockService;
public TransactionStockService(StockService stockService) {
this.stockService = stockService;
}
public void decrease(Long id, Long quantity) {
startTransaction();
stockService.decrease(id, quantity);
endTransaction();
}
private void startTransaction() {
// 트랙잭션 시작
}
private void endTransaction() {
// 트랙잭션 끝 ( 커밋 )
}
}
- 여기서 문제점이 decrease 메서드는
synchronized
처리를 통해 한 스레드만 접근할 수 있지만 decrease매서드가 끝남과 동시에는 다른 스레드가 접근할 수 있다. - 즉, A라는 스레드가 decrease 메서드를 끝낸 후 endTransaction메서드를 수행하려 할 때 B 스레드는 decrease 메서드에 접근할 수 있게 되고 앞써 본 문제점이 동일하게 나타나 테스트가 실패하게 되는 것이다.
해결하려면?
- 간단하다.
@Transactional
을 없애면 된다! - 그렇게 되면 decrease 메서드는 무조건 한 스레드만 접근할 수 있게 되니 동시성 문제가 사라지게 된다.
- 테스트도 통과한 모습
@Transactional
이 없어도 동작하는 이유
- 처음에 강의에서 더티 체킹을 하지 않고
saveAndFlush
메서드로 업데이트하길래 왜 그런가 생각했다. - 알고보니 해당 예제를 보여주기 위해서 인 것 같다.
- 그럼 트랜잭션 어노테이션이 없더라도 업데이트가 되는 이유가 뭘까?
- 사실
JpaRepository
의saveAndFlush
메서드는 자체적으로@Transactional
을 가지고 있다.- 구현체인
SimpleJpaRepository
에서 확인할 수 있다. save
메서드도 마찬가지!- save에 어노테이션이 붙어있는 데 saveAll에도 붙어있는 이유는
self invocation
때문이다.
- 구현체인
- 그렇기에 더티체킹으로 할 경우 테스트는 실패하게 된다.
문제점
- 단일서버일 때는 문제가 되지 않는다.
- 만약 다중 서버라면?
synchronized
는 각 인스턴스안에서만thread-safe
가 보장이 된다.- 그렇기 때문에 다중 서버일땐 레이스 컨디션이 발생하게 된다.
- 위의 문제점에서 A,B Thread를 A,B 서버로 생각하면 된다.
- 요즘 서비스는 다중 서버를 사용하기 때문에
synchronized
는 거의 사용되지 않는다.
결론
- 자바에서 지원하는
Synchronized
키워드를 통해 어플리케이션 단에서 쉽게 동시성 문제를 해결할 수 있다. - 하지만 해당 문제는 단일 서버에서의 해결방법일뿐 다중 서버에서는 해결되지 않는다.
Reference
'Back-End > 강의' 카테고리의 다른 글
[재고시스템으로 알아보는 동시성이슈 해결방법] 3. Redis Distributed Lock (0) | 2022.08.30 |
---|---|
[재고시스템으로 알아보는 동시성이슈 해결방법] 3. Database Lock (0) | 2022.08.28 |
[재고시스템으로 알아보는 동시성이슈 해결방법] 1. 들어가며 (1) | 2022.08.24 |
댓글