코딩관계론

DB Exclusive Lock 에러 본문

개발

DB Exclusive Lock 에러

개발자_티모 2025. 6. 7. 21:44
반응형

최근 업무 중 특정 기능 업데이트 이후 데이터베이스에서 예상치 못한 빈도의 Lock Raise 오류가 발생하였다. 장애 현상은 다음과 같은 트랜잭션 간 경쟁 상황에서 비롯되었다. 이러한 상황에서 발생하는 락과 이를 해결하기 위한 전략에 대해 정리하고자 한다.

장애 현상

  1. 트랜잭션 A가 특정 행(ROW1)에 대한 업데이트를 수행하며 배타적 락(Exclusive Lock)을 획득했다.
  2. 트랜잭션 A가 완료되지 않은 상태에서 트랜잭션 B가 같은 행(ROW1)에 대한 업데이트를 시도하면서 락 충돌(Lock conflict)이 발생하여 오류가 발생했다.

 

배타적 락(Exclusive Lock, X-Lock)

먼저 이 문제를 해결하기 위해선 배타적 락 대해서 알아야 한다. 배타적 락은 데이터 변경 작업을 수행할 때 발생하는 락으로, 주로 UPDATE, DELETE, 또는 SELECT FOR UPDATE 작업 시 획득된다. 배타적 락이 설정된 데이터는 다른 트랜잭션의 쓰기 작업을 차단하여 데이터의 일관성을 유지한다. 일반적인 읽기 작업(SELECT)은 허용되지만, 쓰기 작업을 위한 다른 배타적 락은 해당 락이 해제될 때까지 대기 상태로 전환된다.

배타적 락 실험 예시

다음의 실험을 통해 배타적 락의 동작 방식을 확인할 수 있다.

-- 테이블 생성
CREATE TABLE accounts (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL,
    balance INT NOT NULL
);

-- 초기 데이터 삽입
INSERT INTO accounts (name, balance) VALUES ('Alice', 1000);
INSERT INTO accounts (name, balance) VALUES ('Bob', 1000);

이후 트랜잭션을 통해 아래 작업을 수행한다.

-- 트랜잭션 A
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
SELECT * FROM accounts WHERE id = 1;

이 상태에서 새로운 트랜잭션 B를 생성하여 같은 행을 업데이트하면 락 충돌이 발생한다.

-- 트랜잭션 B (새로운 연결)
BEGIN;
UPDATE accounts SET balance = balance + 100 WHERE id = 1;

트랜잭션 A가 커밋 또는 롤백되지 않는 한 트랜잭션 B의 작업은 블로킹(blocking) 상태가 되어 기다리게 된다.

 

사진 1

해결 전략

이러한 문제를 해결하기 위해 특정 컬럼에 대한 명시적인 UPDATE 문을 제거하고 모든 변경 작업을 ORM의 save 메서드를 통해 수행하도록 변경하였다. 동시에 낙관적 락을 도입하였다. 이렇게 하면 특정 컬럼에 대한 배타적 락을 명시적으로 걸 위험이 없어지고, 충돌 발생 시 버저닝(versioning)을 통해 충돌을 효율적으로 관리할 수 있게 된다.

 

출처

https://stackoverflow.com/questions/11837428/whats-the-difference-between-an-exclusive-lock-and-a-shared-lock

반응형