동시성 제어

Shaun·2024년 12월 19일

Concurrency

목록 보기
1/3
post-thumbnail

ConCurrency

어플리케이션을 만들다보면 동시성 이슈는 항상이 일어난다.
예를들어 100개의 물건이 있을때 한사람당 하나씩 구매를 한다고 가정해 보자. 예상대로라면 한사람당 하나씩 가져가므로 100개의 요청을 동시에 보내면 정상동작 할것 같지만 그렇지 않다. a라는 유저가 구매후 차감된 데이터가 업데이트 되기전 b유저가 구매할수도 있는등등(정합성) 여러 문제들이 일어난다.

RowLock

  • update할때 는 row에 rowLock이라는게 걸린다.즉, 이 Row 데이터에대한 다른 트랜잭션의 수정을 막는다. 동시에 update요청이 와도 결국에는 rolwLock을 잡는 순서대로 순차적으로 처리함.
    -> 이미 update 하기전 select에서 동일한값을 가져왔으며로 rowLock이 있어도 동시성 이슈는 발생함

동시성 해결 방법

  • synchronized
  • pesmistic lock(비관적락)
  • optimistic lock(낙관적락)
  • named lock
  • redis lettuce
  • redisson
  • 동시성 해결 방법에는 여러 방법들이 존재 한다.

synchronized



  • synchronized는 그냥 붙여주기만해서 구현은 어렵지 않다.

  • 트랜잭션 빼고 synchronized만 구현했을경우

  • 트랜잭션 + synchronized

  • 이 경우 트랜잭션이 끝나기전에 다른 스레드가 자원에 접근하기 떄문에 테스트가 실패한다.

  • synchronized 한개의 쓰레드만 접근 가능하며 각 프로세스 안에서만 보장, 즉 여러 서버에서 동시에 접근하면 레이스 컨디션이 발생한다.

PesmisticLock




  • 비관적 락은 데이터베이스 레벨에서 락을 걸어 다른 트랜잭션이나 스레드의 접근을 제한

  • 다른 접근을 제한함으로써 데이터의 정합성은 높지만 그만큼 성능 저하가 발생함

OptimisticLock


  • optimistic Lock은 버전으로 상태를 모니터링 한다.

  • 예를들어 a 트랜잭션에서 데이터를 변경하고 버전 1에서 버전2로 바꾸고 그 과정에 동시접근한 b트랜잭션에서도 데이터를 변경하고 트랜잭션 종료할때 b트랜잭션의 버전은 아직 1이므로 버전 불일치로 예외가 발생한다.

  • 낙관적락은 재시도 로직 필요하다


NamedLock

  • 여기서는 stock id로 락을 건다. 락을 건 대상이 락을 풀어야 다음 트랜잭션에서 사용가능
  • 실무에서는 별도의 jdbc를 이용해야함, 여기서는 편의상 그냥 stock
  • mysql 의 getLock, releaseLcok 사용

  • 트랜잭션에 옵션을 안주고 decrease 메서드에서 에러가 발생하면 락을 해제 못하는 문제 발생!(트랜잭션이 끝난다해도 락해제가 안돼기 때문)

  • 그래서 부모의 트랜잭션과 별도로 실행하도록 트랜잭션에 옵션을 설정해준다(기존 트랜잭션과 완전분리)

  • 주로 분산락을 구현할때 사용
  • 트랜잭션이 끝날때 락이 자동으로 해제되지않아 따로 구현필요


Redis

lettuce

  • 처음에는 키가 1인 데이터가 없어서 성공

  • 그 뒤로는 데이터가 있으니 실패한다

  • 이 원리를 이용해보자

  • stockId로 Lock을 걸고 해제한다

  • 구현이 쉽지만 스핀락(락을 획들할 때까지 해당 스레드가 빙빙 돌고있음)이 걸릴 확률이 높으며 레디스에 부하를 줄 수 있다.

redission


  • 락해체가 되엇다고 알려주고 그제서야 락획득을 시도하기떄문에 한번 혹은 몇번만더 실행함으로써 레디스의 부하를 줄여준다

  • 락관련 클래스들을 라이브러리에서 제공 함으로 따로 레포지토리를 만들지 않아도 괜찮다.

profile
호주쉐프에서 개발자까지..

0개의 댓글