[DB] Transaction DeadLock

Jisoo Choi·2021년 10월 6일
3
post-thumbnail

Transaction

  • 트랜잭션은 하나의 작업을 수행하는데 필요한 데이터베이스의 연산을 모아놓은 것으로 데이터베이스 작업의 단위라고 생각하면 된다.

  • 일반적으로 데이터베이스의 연산은 SQL문으로 이루어져 있으며 트랜잭션을 SQL문의 집합이라고도 한다.

  • 트랜잭션에서 중요한 것은 트랜잭션 단위로 구분해서 모두 성공하거나 실패해야 데이터베이스의 일관성을 유지할 수 있다는 것이다. (트랜잭션 특징中)

Transaction Update

트랜잭션에서 UPDATE작업을 할 때 처리과정은 아래와 같다.

UPDATE TABLE
SET A = 300
WHERE A_ID = 201;

위의 쿼리를 실행하면

  1. 행 레벨 Lock
  2. UNDO SEGMENT Buffer 확보 및 정보 기록
  3. 데이터 UPDATE
  4. COMMIT & 행 Unlock

[설명]
1) 트랜잭션에서 UPDATE를 할 경우 읽기 일관성을 유지하기 위해 행 레벨에서 Lock을 걸어버린다. 다른 트랜잭션에서 Update 작업을 할 수 없도록 막는 작업이다.

2,3) 그 후 다른 트랜잭션에서 SELECT를 할 경우 아직 COMMIT을 하지 않았기 때문에 이전 정보를 UNDO BLOCK에서 조회할 수 있도록 정보를 기록해주고 데이터 UPDATE 작업을 진행한다.

4) Transaction이 최종적으로 끝나면 행 레벨 LOCK을 풀어준다.

Lock

대용량의 데이터를 처리하는 데이터베이스 애플리케이션의 경우 데이터의 정확성을 유지하면서 최대한 동시성을 높이는 것이 중요한 포인트이다. 그렇기 때문에 상황에 따른 여러가지 Lock을 통해 동시성을 제어하며 이를 통해 사용자가 설정한 대로 원하는 수준의 트랜잭션 격리 수준(Transaction Isolation Level)을 유지해준다.

Lock은 트랜잭션과 비슷한 개념같지만, Lock은 동시성을 제어하기 위한 기능이고, 트랜잭션은 정합성을 보장히기 위한 기능이다. 데이터의 일관성을 보장하기 위한 하나의 방법이다. 오라클과 같이 고가의 DBMS를 사용하는 이유가 데이터의 무결성과 일관성을 유지하기 좋기 때문이다.

Lock은 상황에 따라서 크게 두가지로 나뉜다.

1) Shared Lock(공유 Lock 또는 Read Lock): 데이터를 읽을 때 사용한다. 내가 보고 있는 데이터는 다른 사용자가 볼 수 있지만, 변경은 불가하다.

2) Exclusive Lock(배타적 Lock 또는 Write lock) : 데이터를 변경할 때 사용한다. 해당 Lock이 해제되기 전까지는, 다른 Lock에 대한 설정을 할 수 없다. 즉, 읽기 쓰기가 불가능하다는 의미!

DeadLock

배포 후 테스트를 하는 중에 갑자기 어떠한 기능의 API의 트랜잭션에서 DB Lock이 걸려 무한 대기하여 실행되지 않는 오류(?)를 발견했다. DeadLock이다!

  • 첫 번째, 테이블의 update를 할 때 timeout error 발생.
  • 두 번째, 트랜잭션에서 데드락이 발생해서 api자체가 무한 대기 중임을 발견.

DeadLock(교착상태)란, 둘 이상의 프로세스가 다른 프로세스가 점유하고 있는 자원을 서로 기다릴 때 무한 대기에 빠지는 상황을 말한다. 나의 경우는 트랜잭션간의 교착상태를 의미한다. 두개의 트랜잭션간에 각각의 트랜잭션이 가지고 이씨는 리소스의 Lock을 획득하려고 할 때 발생한다.

DeadLock 발생 원인

  • 예를 들어, 하나의 트랜잭션이 테이블A를 업데이트 한 뒤 테이블B를 업데이트 하려고 할 때, 다른 트랜잭션이 이미 테이블B에 업데이트 작업을 진행 중인 경우 해당작업을 완료할 때까지 대기 후 처리한다. 트랜잭션들이 서로 완료 될 때까지 기다리며 결과적으로 무한 대기 상태가 되면 교착상태라고 한다.

DeadLock의 해결방법

  • 데드락이 발생하지 않도록 예방하기

  • 데드락 발생 가능성을 인정하면서도 적절하게 회피하기

  • 데드락 발생을 허용하지만 데드락을 탐지하여, 데드락에서 회복하기

  • 트랜잭션 진행방향을 같은 방향으로 처리 (테이블A 업데이트 후 테이블B 업데이트, 블로킹)

  • 트랜잭션 처리속도를 최소화

  • SET LOCK_TIMEOUT: 잠금해제 시간 설정

    • 대용량 작업을 할 때는 작업단위를 쪼개거나 lock_timeout을 설정해서 해당 lock의 최대시간을 설정 할 수 있다.
      set lock_timeout 3000

.......라고 하지만, 사실 나는 직접 해보지 않으면 정확히 잘 이해가 되지 않는다.

👨‍💻 실제로 해결한 방법으로는

  • DB 서버 재시작(흠...)
  • 서버의 성능 문제가 아닐까 싶다..

해결은 위의 방법으로 했지만, 실제 Deadlock에 대해서 설명이 잘 되어 있는 부분이 있어서 다음 포스트에서는 DeadLock을 발생시키는 예제를 다뤄볼 것이다.


참고:
https://www.postgresql.org/docs/9.4/explicit-locking.html
https://chanhuiseok.github.io/posts/cs-2/
https://myjamong.tistory.com/181
https://sosopro.tistory.com/55

profile
👩‍🚀 No worries! Just record

0개의 댓글