Serializable 수준으로 처리하니까 왜 데드락이 발생할까? - Serializable 에 대한 오해

태그
데이터베이스
Spring

노트

  • H2로 동시성 관련 테스트를 하는 과정에서 Transaction 의 고립 수준을 SERIALIZABLE 로 높여서 동시 다발적으로 테스트 해보니 다음과 같이 Deadlock 발생하는 것을 볼 수 있다.
notion imagenotion image
  • 분명히 SERIALIZABLE 이면 각 트랜잭션이 직렬화되어 독립적으로 작동해야하는게 아닌가? 의문이 들었다.
  • 현재 상황은 다음과 같다.
    • 하나의 ticket 에 대해 발급 가능한 최대 수가 정해져있으며, 해당 수 이상만큼은 유저에게 발급을 해줄 수 없는 예약 시스템이다.
    • 여기서 편의상 발급하려는 티켓을 T 라고 명명하자.
  • 그런데 왜 트랜잭션이 베타적으로 접근하는데 데드락이 발생할까?
    • 트랜잭션 고립 수준이 높아질 수록 거는 Lock의 조건이 까다로워지기 때문
    • 따라서, SERIALIZABLE 수준으로 접근하더라도, T에 대해 거는 Lock은 여전히 유효하며, 여러 트랜잭션이 동시 다발적으로 Lock을 건다. 이 때 특정 상황에 데드락이 발생한다.
    • 그러면 여기서 특정 상황은 무엇일까. 그리고 고립수준에 따른 Lock 전략은 어떻게 바뀌는 것일까?
  • 일단 사고실험으로 데드락이 발생하는 조건은 다음과 같다.
    • A, B 트랜잭션이 각각 존재한다.
    • A 트랜잭션이 먼저 T에 대해 접근하며, READ LOCK 을 건다.
    • B 트랜잭션이 이후 T에 접근하며 마찬가지로 READ LOCK을 건다.
    • A 트랜잭션이 이후 T에 대해 업데이트 하기 위 WRITE LOCK을 건다.
    • B 트랜잭션이 이후 T에 대해 업데이트 하기 위 WRITE LOCK을 건다.
    • 그러나 Read Lock이 걸린 상태에서 A와 B는 Write Lock은 획득이 불가능하다. A는 Write Lock을 획득하기 위해 B의 Read Lock을 풀어야 하고 B도 마찬가지로 A의 Read Lock을 풀어야 한다. 따라서 데드락 발생

요약

📌
요약: Serializable에서는 Lock을 많이 걸어서