[좌충우돌 개발일지 - AToZ 프로젝트] 동시성 이슈에 관한 내용

2022. 12. 16. 00:16프로그래머스/TIL

최근 팀 미팅 했을 때, 개인 프로젝트(AToZ 프로젝트)에 대해서 설명하는 발표시간을 가졌다.

내가 만든 프로젝트는 의류 주문 관리 프로젝트였다. 다음과 같은 피드백을 받았다.

  • Order의 validate에 대해서 잘 생각을 해보자 -> 들어온 가격이 주문에서 필요한 가격과 일치하는지, 더 들어왔는지 덜 들어왔는지 등
    • 특히 가격에 관리된 것 -> order에도 가격이 필요할 것 -> 나중에 쿠폰도 들어가면 total 금액을 order에 들고 있어도 달라짐
  • 그리고 OrderStatus에 대한 부분도 더 고민할 것 -> 더 세분화될 수 있음. (출고 준비 중, 배송 시작, 출고 완료, 배송 완료 등)
  • Product 카테고리도 더 세분화될 수 있는데 동적으로 만들어야함. Enum으로 만들 수 있는 부분과 아닌 부분을 잘 생각할 것. -> 동적으로 만들어져야 하는 부분과 아닌 부분.
  • 동시성에 대한 것 => 진짜 중요함. (예) 상품 재고가 하나 남았을 때, 두 명이 동시에 접근하는 경우 누가 살 수 있는가?

그래서 진짜 중요한 동시성에 대해서 찾아보고 학습해보자아!


동시성 이슈란?

동시성 이슈는 주문 도메인에서 생각했을 때 재고가 하나 남은 상품을 사기 위해서 두 명의 유저가 접근을 하는 경우를 생각해보면 접근 시에 둘 다 재고가 하나가 남아있다고 판단할 것이고 둘 다 상품을 살 수 있을 것이다. 그러면 재고는 결국 음수인데 0으로 기록되는 경우가 생기고 둘다 주문에 성공하는 경우가 생긴다. 이런 경우 동시성 이슈라고 한다.

 

이 경우를 어떤 식으로 해결할 수 있을까? 해결방법을 알아보자.

 

동시성 문제 해결방법

일반 변수에 대한 동시성 이슈 해결 방법

static 변수를 공유하여 사용하는 경우 발생할 수 있고 이를 해결하기 위해서 Synchronized, Volatile, Atomic 클래스 와 같은 방식들이 있는데 Synchronized(임계 구역)와 Volatile은 성능 문제가 있어서 Atomic 클래스를 사용한다고 한다. 

DB의 동시성 이슈

먼저 DB의 트랜잭션 성질과 격리 수준에 대한 내용을 공부하면 좋을 것 같다.

https://techvu.dev/115

 

트랜잭션이란?

트랜잭션(Transacation) 정의 트랜잭션이란 데이터베이스의 상태를 변화시키는 하나의 논리적인 작업 단위라고 할 수 있으며, 트랜잭션에는 여러개의 연산이 수행될 수 있다. 특징 하나의 트랜잭션

techvu.dev

https://private-space.tistory.com/97

 

트랜잭션 격리 수준(Isolation Level)

트랜잭션 격리 수준 개발을 하다 보면 여러 스레드에서 동시에 하나의 자원에 접근하는 경우가 있다. 접근을 적절하게 제한하지 않는다면 생각지 못한 버그가 발생할 수 있다. 게다가 이런 경우

private-space.tistory.com

=> 해당 글을 읽어보자.

일반 변수에서 말했던 Synchronized로도 해결할 수 있다. 하지만 말했듯 성능이슈가 생길 수 있다.

그래서 Lock에 대해서 알아보자.

JPA Optimistic Lock, Pessimistic Lock

Optimistic Lock

낙관적 잠근은 데이터 갱신 시 충돌이 발생하지 않을 것이라고 낙관적으로 생각하고 Lock을 거는 방식이다.

DB에 Lock을 걸지 않고 Conrflict Detection에 가깝다고 볼 수 있다. 이를 사용하기 위해서 @Version을 Int, Long 타입의 변수를 구현해줌으로써 간단하게 구현이 가능하다.

주의 사항은 다음과 같다.

  • 각 엔티티 클래스는 하나의 버전 속성만 있어야함.
  • 여러 테이블에 매핑된 엔티티의 경우 기본 테이블에 배치되어야함.
  • 버전에 명시할 타입은 int, Integer, long, Long, short, Short, Timestamp 중 하나여야 함.

JPA는 SELECT 시에 트랜잭션 내부에 버전 속성으 값을 보유하고 트랜잭션이 업데이트 하기 전에 버전 속성을 다시 확인함. 그 동안 버전 속성이 변경 되었으면 OptimisticLockException이 발생, 변경 X -> 버전속성을 증가하는 업데이트.

Pessimistic Lock

비관적 잠금은 트랜잭션이 충돌 한다고 비관적으로 생각하고 우선 Lock을 거는 방법

트랜잭션 안에서 서비스 로직이 진행되어야하고 DB 수준에서 엔티티 Lock을 포함한다.

비관적 잠금은 3가지 모드가 존재한다. (모두 트랜잭션이 커밋되거나 롤백될때까지 유지)

  1. PESSIMISTIC_READdirty read가 발생하지 않을 때 마다 Shared Lock을 획득하고 데이터가 UPDATE, DELETE 되는 것을 방지.
  2. PESSIMISTIC_WRITEExclusive Lock을 획득하고 데이터를 다른 트랜잭션에서 READ, UPDATE, DELETE 하는 것을 방지.
  3. PESSIMISTIC_FORCE_INCREMENTWRITE와 유사한데 @Version이 지정된 엔티티와 협력하기 위해 도입 -> 잠금 획득 시 버전 업데이트

- JPA Lock에 대한 오해를 말한다 읽어보면 좋을 것 같다.

 

동시성(Concurrency) 이슈와 JPA Lock 메커니즘의 오해

최근에 동시성에 관한 이슈를 검색하고 공부했던 것을 글로 간략하게 정리하고자 한다. 동시성 이슈는 개발을 하면서 빈번하게 발생할 이슈는 아니지만 발생 여지가 있다면 개발자로서 알아야

stir.tistory.com

https://catch-me-java.tistory.com/60

내가 받은 피드백과 거의 유사한 부분에 관한 내용을 담고 있다 읽으면 좋을 것 같다.

 

내가 선택한 DB 동시성 해결방법

내가 선택한 DB 동시성 해결방법 서론 오랜만에 블로그 포스팅이다. 포스팅 아이템들은 넘처나는데, 시간이 없어서(핑계) 작성할 시간은 없었던 것 같다. 마침 진행하던 프로젝트에서 동시성 이

catch-me-java.tistory.com