재고시스템으로 알아보는 동시성이슈 해결방법 - 인프런 | 강의
동시성 이슈란 무엇인지 알아보고 처리하는 방법들을 학습합니다., - 강의 소개 | 인프런...
www.inflearn.com
우리의 프로그램을 자원을 감시하는 감시자라 생각해보자.
그리고 필요한 데이터를 자원이라하고 자원을 사용하는 여러명의 사용자들을 각각의 쓰레드라고 가정하고 생각을 해보자.
만약 100개의 자원이 존재하고 쓰레드들이 자원을 하나씩 가져가는 상황일때,
감시자는 자원을 쓰레드들에게 하나씩 내어주고 하나씩 자원의 수를 감소시켜 관리할 것이다.
그런데 이때 쓰레드들이 거의 동시다발적으로 자원을 가져가면 어떻게될까?
감시자는 멘봉이 올 것이다...
쓰레드 1에게 자원을 나눠주고 아직 자원의 수량을 감소시키지도 않았는데 다른 쓰레드 2가 자원을 가져가고 이러한 상황이 반복된다면,
재고 수량과 실제 남아있는 수량은 같지 않을 것이다. 바로 이러한 문제가 동시성 문제라고 할 수 있다.
- Synchronized 를 사용해서 해결할 수 있다. 단 2대 이상의 서버에는 좋은 해결책이 아니다.
멀티쓰레드 환경에서 데이터의 안정성을 보장하기 위해서는 이러한 동시성 문제를 고려해야한다.
자바는 이러한 동시성을 해결하기 위해 Synchronized 키워드를 사용해 해결 할 수 있다.
그러나 Synchronized 메서드에 접근시 사용하는 쓰레드가 다 끝날때까지 다른 쓰레드는 메서드에 접근할 수 없어 기다려야한다. 이또한 자원의 낭비가 될 수 있고, 근본적으로 Synchronized 는 단일 서버에서만 효과가 있다고 할 수 있기에 좋은 해결책이 아니라고 할 수 있다.
만약 두대의 서버를 띄운 프로그램이라고 가정해보자. 우리의 데이터를 관리하는 것은 실질적으로 Database 라고 할 수 있다.
때문에 Database 에 lock 을 거는게 아닌이상 프로그램내에서 Synchronized 를 사용해 동시성 문제를 해결하려 하는것은 또 다시 동시성 문제를 불러올 수 있는 환경이 되는것이다.
- Database 에서 데이터를 사용할 때 lock 을 사용해서 해결할 수 있다.
- Pessimistic Lock (비관적 잠금)
- Optimistic Lock (낙관적 잠금)
- Pessimistic Lock (비관적 잠금)
Perssimistic Lock 은 한 트렌젝션이 Database 에서 데이터를 꺼내 쓸때 다른 트랜젝션이 해당 데이터를 삭제하거나 수정 할 수 없도록 Lock을 걸고, 작업이 끝나면 다시 Lock을 풀어 다른 트랜젝션이 사용할 수 있도록 한다.
Jpa 에서는 @Lock 애노테이션을 사용해 Perssimistic Lock(비관적 잠금) 을 사용할 수 있다.
@Lock(value = LockModeType.PESSIMISTIC_WRITE)
@Query("select s from Stock s where s.id = :id")
Stock findByWithPessimisticLock(Long id);
제공되는 Perssimistic LockModeType 은 세가지이다.
- PESSIMISTIC_WRITE
- PESSIMISTIC_READ
- PESSINISTIC_FORCE_INCREMENT
Perssimistic_WRITE
일반적인 옵션. 데이터베이스에 쓰기 락
다른 트랜잭션에서 읽기도 쓰기도 못함. (배타적 잠금)
PESSIMISTIC_READ
반복 읽기만하고 수정하지 않는 용도로 락을 걸 때 사용
다른 트랜잭션에서 읽기는 가능함. (공유 잠금)
PESSINISTIC_FORCE_INCREMENT
Version 정보를 사용하는 비관적 락
Pessimistic Locking in JPA | Baeldung
A quick guide to using pessimistic locking in JPA
www.baeldung.com
- Optimistic Lock (낙관적 잠금)
데이터의 버전 정보를 사용해 논리적인 락을 거는 것이다.
Jpa 에서는 @Lock 애노테이션을 사용해 Optimistic Lock(낙관적 잠금) 을 사용할 수 있다.
추가적으로 Lock 을 사용할 Entity 필드에 @Version 사용해야한다.
Stock
@Entity
public class Stock {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Version
private Long version;
}
StockRepository
@Lock(value = LockModeType.OPTIMISTIC)
@Query("select s from Stock s where s.id = :id")
Stock findByWithOptimisticLock(Long id);
제공되는 Optimistic LockModeType 은 다음과 같다.
- OPTIMITIC ( 버전 값을 증가시키지 않기 때문에 읽기 전용 Lock 이라 할 수 있다. )
- OPTIMISTIC_FORCE_INCREMENT ( Lock 을 획득한 후 버전 속성 값을 증가시킨다. )
- READ ( OPTIMITIC 와 같다.)
- WRITE ( OPTIMISTIC_FORCE_INCREMENT 와 같다. )
Optimistic Locking in JPA | Baeldung
A guide to understanding optimistic locking in JPA as well as its use cases.
www.baeldung.com
Optimistic Lock 은 Version 정보를 활용해 Version 이 맞지 않으면 데이터를 수정하거나 삭제할 수 없다.
그렇다면 비관적 락과 낙관적 락 어느때 써야할까?
Pessimistic Lock(비관적 락)의 경우 Database Level 에서 Lock 을 걸게된다. 때문에 동시성 충돌이 많이 일어날것 같은 경우에 데이터의 안정성 및 무결성이 확실히 보장되어야하는 상황에서 사용하는 것이 좋다.
Optimistic Lock(낙관적 락) 에 경우 Version 정보를 사용하여 Database Level 에서 Lock 을 거는 것이 아닌 논리적인 락을 걸게된다.
때문에 업데이트나 삭제보다는 읽기가 더 많이 수행되는 상황에서 사용하는 것이 좋다.
'Java' 카테고리의 다른 글
Jpa 의 변경감지를 통한 업데이트를 Reflection 을 이용해 해보자 (0) | 2022.10.09 |
---|---|
암호화 Digest (0) | 2022.07.10 |
JDK, JRE, JVM (0) | 2022.06.21 |
Java Compile Process (0) | 2022.06.19 |