이전 블로그에서는 자바 Synchronized를 이용한 동시성 이슈 해결방법을 살펴보았습니다. 하지만 서버가 여러대일 경우, 다른 서버에서 가변 공유데이터에 접근하는 것을 막을 수 없는 문제가 존재하였습니다.
예를들어 Server 1 DB 데이터를 가져올 떄, Lock 을 걸어버리면, 다른 서버에서는 Server1의 작업이 끝나 락이 풀릴 때 까지, 데이터에 접근하지 못하게 됩니다.
🔍결국 Pesimistic Lock이란, 데이터에는 락을 가진 스레드만 접근이 가능하도록 제어하는 방법입니다.
public interface StockRepository extends JpaRepository<Stock, Long> {
@Lock(value = LockModeType.PESSIMISTIC_WRITE)
@Query("select s from Stock s where s.id = :id")
Stock findByWithPessimisticLock(final Long id);
}
Pessimistic Lock 의 장점
- 충돌이 빈번하게 일어난다면 롤백의 횟수를 줄일 수 있기 때문에, Optimistic Lock 보다는 성능이 좋을 수 있습니다
- 비관적 락을 통해 데이터를 제어하기 때문에 데이터 정합성을 어느정도 보장할 수 있습니다.
Pessimistic Lock 의 단점
- 데이터 자체에 별도의 락을 잡기때문에 동시성이 떨어져 성능저하가 발생할 수 있습니다.
- 특히 읽기가 많이 이루어지는 데이터베이스의 경우에는 손해가 더 크다고 합니다.
- 서로 자원이 필요한 경우, 락이 걸려있으므로 데드락이 일어날 가능성이 있습니다.
낙관적 락(Optimisstic Lock)은 DB의 Lock을 사용하지 않고 Version관리를 통해 애플리케이션 레벨에서 처리합니다.
Optimisitc Lock의 과정
1. 서버 1이 version1 임을 조건절에 명시하면서 업데이트 쿼리를 날립니다🔽
2. version1 쿼리가 업데이트 되어서, 디비는 version 2가 됩니다🔽
server2 가 version1 로 업데이트 쿼리를 날리면 버전이 맞지않아 실패합니다.
쿼리가 실패하면 server2 에서 다시 조회하여 버전을 맞춘 후 업데이트 쿼리를 날리는 과정을 거칩니다.
Optimistic Lock 은 실제 락을 사용하지 않고, 버전을 이용해서 락과 유사한 과정을 가지는 논리적인 락이라고 생각이 듭니다
@Version을 명시할때는 다음과 같은 주의사항이 있습니다.
- 각 엔티티 클래스에는 하나의 버전 속성 만 있어야합니다.
- 여러 테이블에 매핑 된 엔티티의 경우 기본 테이블에 배치되어야합니다.
- 버전에 명시할 타입은 int, Integer, long, Long, short, Short, java.sql.Timestamp 중 하나 여야합니다.
@Entity
@Getter
@NoArgsConstructor
public class Stock {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private Long productId;
private Long quantity;
//버전 칼럼 추가
@Version
private Long version;
}
public interface StockRepository extends JpaRepository<Stock, Long> {
//pessimistic Lock
@Lock(value = LockModeType.PESSIMISTIC_WRITE)
@Query("select s from Stock s where s.id = :id")
Stock findByWithPessimisticLock(final Long id);
//Optimistic Lock
@Lock(value = LockModeType.OPTIMISTIC)
@Query("select s from Stock s where s.id = :id")
Stock findByWithOptimisticLock(final Long id);
}
Optimistic Lock 의 장점
- 충돌이 안난다는 가정하에, 별도의 락을 잡지 않으므로 Pessimistic Lock 보다는 성능적 이점을 가집니다.
Optimistic Lock 의 단점
- 업데이트가 실패했을 떄, 재시도 로직을 개발자가 직접 작성해 주어야 합니다.
- 충돌이 빈번하게 일어나거나 예상이되면, 롤백처리를 해주어야하기 때문에 Pessimistic Lock 이 더 성능이 좋을 수도 있습니다.
다음 블로그에서는 Redis를 이용한 동시성 이슈 해결에 대해 알아보겠습니다.