450. 2단계 잠금 규약 (2PL - Two-Phase Locking)

⚠️ 이 문서는 여러 트랜잭션이 동시에 데이터를 수정할 때 자물쇠(Lock)를 아무 때나 걸고 풀면 데이터가 엉망진창으로 꼬이는 것을 막기 위해, 수학자들이 만들어낸 **"자물쇠를 거는 단계와 푸는 단계를 완벽하게 분리해야만 완벽한 고립성을 보장할 수 있다"는 절대 원칙인 '2PL'**을 다룹니다.

핵심 인사이트 (3줄 요약)

  1. 본질: 트랜잭션이 실행되는 동안 자물쇠를 거는 시간(확장 단계)과 자물쇠를 푸는 시간(수축 단계)이 결코 섞여서는 안 된다는 규칙이다.
  2. 가치: 이 규칙을 지키면 여러 트랜잭션이 동시에 실행되어도, 마치 한 줄로 서서 차례대로 실행된 것과 똑같은 결과(직렬 가능성, Serializability)를 100% 수학적으로 보장한다.
  3. 한계: 완벽한 데이터 정합성을 보장하지만, 자물쇠를 너무 오랫동안 쥐고 있어야 하므로 다른 트랜잭션들이 무한 대기에 빠지는 **교착 상태(Deadlock, 451번 문서)**를 유발하는 가장 큰 원인이기도 하다.

Ⅰ. 개요: 마음대로 문을 열고 닫으면 생기는 일 (Context & Necessity)

계좌 A에서 계좌 B로 1만 원을 이체하는 트랜잭션이 있다.

  1. A 계좌에 자물쇠를 건다.
  2. A 잔고를 깎는다.
  3. A 계좌 자물쇠를 푼다. ◀── (문제 발생!)
  4. B 계좌에 자물쇠를 건다.
  5. B 잔고를 늘린다.
  6. B 계좌 자물쇠를 푼다.

만약 3번과 4번 사이에 다른 트랜잭션이 난입해서 A 계좌를 읽어버리면 어떻게 될까? 그 사람은 A의 돈이 깎인 상태를 보게 되는데, 아직 B의 돈은 늘어나지 않았다. 즉, 전체 시스템의 돈 1만 원이 중간에 증발해버린 '불일치 상태'를 남이 훔쳐보게 되는 것이다.

이를 막기 위해 **2단계 잠금 규약(2PL)**은 이렇게 명령한다. "A를 잠그고, B도 잠가라. 모든 작업이 끝날 때까지 절대 자물쇠를 하나라도 먼저 풀지 마라!"

📢 섹션 요약 비유: 2PL은 **'우주선 에어록(Air-lock) 시스템'**과 같습니다. 우주선 밖으로 나갈 때, 안쪽 문을 열고 들어가서 안쪽 문을 '완전히 닫은(수축) 후'에야 바깥쪽 문을 열 수 있습니다. 두 문이 동시에 열리고 닫히는 일이 섞이면 우주선의 공기가 다 빠져나가 폭발해 버리기 때문입니다.


Ⅱ. 2PL의 2가지 단계 (Phase) ★

트랜잭션은 반드시 다음 두 단계를 순서대로 거쳐야 한다.

1. 확장 단계 (Growing Phase)

  • 할 수 있는 일: 새로운 데이터에 자물쇠(Lock)를 걸 수만 있다.
  • 절대 못 하는 일: 이미 걸어둔 자물쇠를 풀 수 없다. (Unlock 금지)
  • 이 단계에서는 트랜잭션이 필요한 모든 데이터의 멱살을 하나씩 쥐면서 권력을 '확장'해 나간다.

2. 수축 단계 (Shrinking Phase)

  • 할 수 있는 일: 쥐고 있던 자물쇠를 풀 수만 있다. (Unlock)
  • 절대 못 하는 일: 한 번이라도 자물쇠를 풀기 시작했다면, 이제부터는 새로운 자물쇠를 절대 걸 수 없다. (Lock 금지)
  • 이 단계에서는 트랜잭션이 마무리 작업을 하며 쥐고 있던 권력을 '수축'시켜 나간다.

Ⅲ. 강엄격한 2PL (Strict 2PL / Rigorous 2PL)

기본적인 2PL은 수축 단계에서 자물쇠를 하나씩 차례대로 푼다. 하지만 이렇게 하면, 내가 1번 자물쇠를 풀었을 때 남이 잽싸게 들어와서 내 데이터를 읽었는데, 내가 나중에 에러가 나서 ROLLBACK을 해버리면 그 사람은 가짜 데이터를 읽은 게 되어버린다. (연쇄 롤백 발생)

이 문제를 막기 위해 현대의 데이터베이스는 **'엄격한 2PL(Strict 2PL)'**을 사용한다.

  • 원리: 쪼잔하게 하나씩 풀지 마라. 모든 자물쇠는 트랜잭션이 완전히 끝나는 COMMIT이나 ROLLBACK을 치는 순간에 한 방에 다 같이 폭파(Unlock)시켜라!
  • 효과: 연쇄 롤백의 위험이 완벽하게 사라진다. (대신 자물쇠를 쥐고 있는 시간이 더 길어짐)
┌──────────────────────────────────────────────────────────────┐
│           일반적인 2PL과 엄격한 2PL(Strict 2PL)의 차이 시각화             │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│ [ 일반 2PL ]                                                  │
│         (확장 단계)                  (수축 단계)                 │
│ Lock A ──▶ Lock B ──▶ 일한다 ──▶ Unlock A ──▶ Unlock B        │
│                                      │                       │
│                         (이 틈에 남이 A를 읽으면 위험함!)            │
│                                                              │
│ [ 엄격한 2PL (Strict 2PL) - 현대 DB의 표준 ]                       │
│         (확장 단계)                               (수축 단계)     │
│ Lock A ──▶ Lock B ──▶ 일한다 ─────────────▶ COMMIT 쾅! 💥     │
│                                           (동시에 전부 Unlock!)│
│                                                              │
│ ★ 특징: 100% 안전하지만, 남들이 밖에서 너무 오래 기다려야 함.               │
└──────────────────────────────────────────────────────────────┘

Ⅳ. 결론

"완벽한 순서는 완벽한 병목을 낳는다." 2단계 잠금 규약은 트랜잭션 격리 수준을 가장 높인 'Serializable' 상태를 수학적으로 구현하는 가장 아름다운 알고리즘이다. 하지만 현실의 비즈니스 세계에서 이 원칙을 100% 지키면 대규모 쇼핑몰이나 은행 시스템은 멈춰버리고 만다. 결국 2PL이 낳는 치명적인 부작용인 '데드락(Deadlock)'과 '성능 저하'를 피하기 위해, 천재 아키텍트들은 자물쇠를 아예 쓰지 않고 버전을 관리하는 MVCC(453번 문서)라는 새로운 마법을 발명해 내기에 이른다.


📌 관련 개념 맵

  • 관련 특성: 고립성 (Isolation - 443번 문서), 직렬 가능성 (Serializability)
  • 발생하는 문제: 데드락 (Deadlock - 교착 상태, 451번 문서)
  • 대안 기술: Timestamp Ordering (452번), MVCC (453번)
  • 잠금의 종류: S-Lock (공유 락), X-Lock (배타 락) - 449번 문서

👶 어린이를 위한 3줄 비유 설명

  1. 2PL은 마트에서 쇼핑하는 규칙이에요.
  2. '확장 단계'는 카트를 밀고 돌아다니면서 내가 사고 싶은 물건들을 카트에 다 담는 시간이에요. (이때 남들은 내 카트에 있는 물건을 못 만져요)
  3. '수축 단계'는 계산대에서 물건을 하나씩 꺼내서 계산하고 가져가는 시간이에요. 주의할 점은! 한 번 계산대에서 물건을 꺼내기 시작하면, 다시 매장으로 뛰어가서 새 물건을 가져올 수 없다는 거랍니다!