본문 바로가기

소프트웨어 이야기/데이터 저장소 + 시각화

(PostgreSQL) Transaction과 Lock에 대한 이모저모

Table Lock Mode

  • Table Lock Mode에 따라 공존할 수 있는 Lock이 있고, Conflict나는 Lock이 있다. 
  • SELECT를 막는 Table Lock은 ACCESS EXCLUSIVE 뿐이다. Lock Mode의 최종보스다. 
  • SELECT FOR SHARE는 FOR UDPATE, FOR SHARE 쿼리에서 필요하다.
  • EXCLUSIVE는 UDPATE / DELETE 등의 쿼리에서 필요하다. EXCLUSIVE Lock 모드는 서로 충돌난다. 그래서 동일한 Row를 여러 트랜잭션에서 동시에 업데이트할 수 없는거다. 
  • SHARE UPDATE EXCLUSIVE는 Vacuum, 인덱스 추가 등의 쿼리에서 필요하다. 

Transaction과 Lock Blocking

  • 트랜잭션이 느린 경우, 어디서 Lock이 Blocking이 되고 있는지 찾아봐야한다. 
  • Transaction A가 특정 Row에 Lock을 잡았다고 생각해보자. 그리고 Transaction B가 Lock을 잡으려는데, Transaction A와 충돌나는 Lock Mode를 갖고있다고 생각해보자. 그러면 Transaction B는 Transaction A가 Commit되거나 Rollback 될 때까지 기다려야한다. 
  • 이와중에 Transaction C가 나타났는데, Transaction C가 필요로하는 Lock이, Trasaction A와는 공존할 수 있지만, Transcation B와는 공존할 수 없는 Lock이라면, Transaction B가 Commit되거나, Rollback 될 때까지 기다려야한다. 
  • 이렇게 Lock Blocking이 시작된다.
  • 그래서 Transaction을 짧게 유지하고, Lock을 반환해줘야한다. 
  • DeadLock은 그나마 에러라도 바로 나서 괜찮다. 그리고 바로 고치면 된다. 
  • 그런데 Lock Blocking은 추적하기도 어렵고, 서비스 장애 전파가 되기도 쉽다. 
  • Lock Blocking이 발생하면, Idle in Transaction 상태인 DB Connection이 늘어나게 된다. 그러면서 점점 애플리케이션 Connection도 많이 물게 되면서, 서비스 장애로 이어지게 된다. 

DeadLock

  • 트랜잭션들이 서로가 잡고있는 Lock을 얻으려고 할 때, DeadLock이 발생한다.
  • 서로가 쥐고 있는 Lock을 얻어야지만, 트랜잭션이 끝날 수 있으니, 영원히 Transaction이 안끝나게 된다. 
  • 그래서 트랜잭션 짤 때, DeadLock 안걸리게 순서를 잘 구성해야한다. 

Postgres Locking Revealed

PostgreSQL Rocks, Except When it Blocks: Understanding Locks

13.4. Data Consistency Checks at the Application Level