나몰닭 서비스는 게임이다보니, 게임룸을 입장할 경우 충돌이 발생할 수 있다고 가정하였다. 실제로 팀원들과 테스트해 본 결과 게임룸에 여러명이 동시 입장을 시도할 경우 서버가 터져버리는 버그가 발생하였다. 우리 팀은 게임룸 입장 로직에 아래와 같이 비관적 락을 DB에 걸어주었다. 아래의 조치를 통해 DB엔 트랜잭셔널 직렬화가 잘 처리되었지만, 웹소켓 연결은 여전히 충돌이 일어났다. 웹소켓 동시성 제어 관련은 다음 게시글에 포스팅하기로 하고, 오늘은 일단 DB관련 동시성 제어에 대해 포스팅 해보려 한다.

@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("select b from GameRoom b where b.gameRoomId = :gameRoomId")
Optional<GameRoom> findByGameRoomId2(Long gameRoomId); // 게임룸 단건 조회

 

비관적 락

  • 자원 요청에 따른 동시성문제가 발생할것이라고 예상하고 락을 걸어버리는 방법론
  • 트랜잭션의 충돌이 발생한다고 가정 = 사용자들이 같은 데이터를 동시에 수정 할 것이라고 가정
  • 하나의 트랜잭션이 자원에 접근시 락을 걸고, 다른 트랜잭션이 접근하지 못하게 하는 방식 = 한사용자가 데이터를 읽는 시점에 Lock을 걸고 조회 또는 갱신 처리가 완료될 때 까지 유지
  • 데이터베이스에서 Shared Lock(공유, 읽기 잠금) 이나 Exclusive Lock(배타, 쓰기 잠금) 을 건다.
  • Shared Lock 의 경우, 다른 트랜잭션에서 읽기만 가능. 또한 Exclusive lock 적용이 불가능(읽는동안 변경하는것을 막기 위해)
  • Exclusive lock 의 경우. 다른 트랜잭션에서 읽기, 쓰기가 둘다 불가능. 또한 Shared, Exclusive Lock 적용이 추가적으로 불가능 (쓰는동안 읽거나, 다른 쓰기가 오는것을 막기위해)
 

장점

  • 충돌이 자주 발생하는 환경에 대해서는 롤백의 횟수를 줄일 수 있으므로 성능에서 유리
  • 데이터 무결성을 보장하는 수준이 매우 높다.

단점

  • 데이터 자체에 락을 걸어버리므로 동시성이 떨어져 성능 손해를 많이 보게 된다. 특히 읽기가 많이 이루어지는 데이터베이스의 경우에는 손해가 더 두드러짐.
  • 첫번째 사용자가 트랜잭션을 완료하기 전까지 다른 사용자들이 데이터를 수정할수 없기때문에 제어를 잘못하면 동시성을 저해 받게 된다.
  • 서로 자원이 필요한 경우에, 락이 걸려있으므로 데드락이 일어날 가능성이 있다.

 

낙관적 락

  • 자원에 락을 걸어서 선점하지말고, 동시성 문제가 발생하면 그때 가서 처리 하자는 방법론 
  • 낙관적 동시성 제어는 사용자들이 동시에 데이터를 수정하지 않을 것이라고 가정한다. = 트랜잭션의 충돌이 발생하지 않을것이라고 기대
  • 일단 충돌이 나는것을 막지 않고, 충돌이 난것을 감지하면 그때 처리
  • 따라서 데이터를 읽을때는 Lock을 설정하지 않는다. 그러므로 데이터를 수정하고자 하는 시점에 앞서 반드시 읽은데이터가 다른 사용자에 의해 변경 되었는지를 검사해야 한다.
  • 일반적으로 version 의 상태를 보고 충돌을 확인하며, 충돌이 확인된경우 롤백을 진행시킴 (hashcode나 timestamp를 이용해서 충돌을 확인할 수 도 있다.)
  • DB단에서 동시성을 처리하는것이 아닌, 어플리케이션단에서 처리
  • 이때 여러 작업이 묶인 트랜잭션으로 요청이 간 경우가 실패한경우, 개발자가 직접 롤백 처리 를 해주어야합니다.

 

장점

  • 충돌이 안난다는 가정하에, 동시 요청에 대해서 처리 성능이 좋다.

단점

  • 잦은 충돌이 일어나는경우 롤백처리에 대한 비용이 많이 들어 오히려 성능에서 손해를 볼 수 있다.
  • 롤백 처리를 구현하는게 복잡할 수 있다.

 

언제 사용할까?

  • 비관적락 은 데이터의 무결성이 중요하고, 충돌이 많이 발생하여 잦은 롤백으로 인한 효율성 문제가 발생하는것이 예상되는 시나리오에서좋다.
  • 비관적 동시성 제어는 동시성이 저하 되지만 데이터를 일일이 검사하지 않아도 된다. 만약 데이터 정합성이 중요한 업무(금융) 라면 비관적 동시성 제어로 동시성이 저하 되더라도 for update 문으로 예외처리를 하여 오히여 동시성을 높이면서 좋은 데이터 정합성을 가질 수 있다.
  • 낙관적락 은 실제로 데이터 충돌이 자주 일어나지 않을것이라고 예상되는 시나리오에서 좋다.
  • 낙관적 동시성 제어크게 경합이 벌어지지 않는 업무 ( 쇼핑몰) 등에서 사용하고, Lock이 짧아져 동시성을 높이는것이 좋다.
    하지만 상품 조회시점과 결제 시점에 가격이 다를 수 있으므로 반드시 데이터 수정시 일관성 검사를 거쳐야만 한다.

 

 


[ 참고 자료 ]

 

https://velog.io/@kw78999/DB-%EB%B9%84%EA%B4%80%EC%A0%81-vs-%EB%82%99%EA%B4%80%EC%A0%81-%EB%8F%99%EC%8B%9C%EC%84%B1-%EC%A0%9C%EC%96%B4

 

[DB] 비관적 vs 낙관적 동시성 제어

n-Tier구조가 지배적인 요즘은 DBMS의 트랜잭션 고립화 수준을 변경하는 방법을 사용하기가 어렵다.그리하여 개발자가 직접 동시성 제어를 개발한다.비관적 동시성 제어비관적 동시성 제어는 사

velog.io

https://unluckyjung.github.io/db/2022/03/07/Optimistic-vs-Pessimistic-Lock/

 

낙관적(Optimistic) 락과 비관적(Pessimisitc)락

낙관적(Optimistic) 락과 비관적(Pessimisitc)락 두 락의 차이를 알아봅니다.

unluckyjung.github.io

https://cult.honeypot.io/reads/optimistic-vs-pessimistic-concurrency/

 

Optimistic vs Pessimistic Concurrency: What Every Developer Should Know | .cult by Honeypot

Here are the differences between optimistic and pessimistic concurrency.

cult.honeypot.io

 

+ Recent posts