DB

[동시성제어] 다중단위 로킹 규약 (Multiple Granularity Locking)

타우루스 2025. 8. 30. 16:04

데이터베이스의 다중 단위 로킹(Multi-granularity Locking)  기법은 데이터베이스 시스템이 여러 사용자의 요청을 빠르고 안전하게 처리하는 데 아주 중요한 역할을 해요. 아주 흥미로운 주제랍니다! 🤓 

학습 계획: 다중 단위 로킹 정복하기!

  1. 다중 단위 로킹의 기본 개념: '단위(Granularity)'가 무엇인지 알아보고, 왜 다양한 크기의 잠금이 필요한지 이해해 봐요.
  2. 의향 잠금(Intention Lock)의 등장: 다중 단위 로킹의 핵심인 '의향 잠금'이 무엇인지, 왜 필요한지 살펴볼 거예요. (IS, IX, SIX 잠금 등)
  3. 잠금 규칙과 호환성: 어떤 규칙에 따라 잠금을 요청하고 허용하는지, 잠금끼리 서로 충돌하지는 않는지 '잠금 호환성 행렬'을 통해 알아봐요.

다중단위 로킹규약

 

1. 다중 단위 로킹의 기본 개념

혹시 도서관에 가본 적 있나요? 도서관 전체를 빌릴 수도 있고, 책 한 권만 빌릴 수도 있죠. 여기서 **'단위(Granularity)'**는 바로 이 '크기'를 의미해요. 데이터베이스에서도 마찬가지랍니다.

  • 작은 단위 (Fine Granularity): 데이터 하나하나 (레코드, 행)
  • 큰 단위 (Coarse Granularity): 테이블 전체, 혹은 데이터베이스 전체

왜 다양한 크기가 필요할까요? 🤔

 

상황에 따라 효율성이 달라지기 때문이에요.

  • 시나리오 1: 한 명의 학생 정보만 수정할 때 만약 학생 수천 명이 있는 테이블에서 딱 한 명의 주소만 바꾼다고 상상해 보세요. 이때 테이블 전체를 잠가버리면(큰 단위 잠금), 다른 사람들은 그 시간 동안 어떤 학생 정보도 조회하거나 수정할 수 없겠죠? 이건 너무 비효율적이에요. 이럴 땐 딱 그 학생의 데이터(작은 단위)만 잠그는 게 훨씬 좋아요. 다른 사람들은 나머지 학생 정보를 자유롭게 볼 수 있으니까요!
  • 시나리오 2: 모든 학생의 학년을 올릴 때 반대로, 새 학년이 되어 모든 학생의 학년을 1학년씩 올려야 한다고 생각해 봐요. 학생 한 명 한 명을 따로따로 잠그려면 수천 번의 잠금을 걸고 관리해야 해요. 이건 컴퓨터에게 엄청난 부담이겠죠? 이럴 땐 그냥 '학생 테이블' 전체를 한 번에 쾅! 하고 잠그는 게(큰 단위 잠금) 훨씬 간단하고 빨라요.

이처럼 다중 단위 로킹은 작업의 종류에 따라 가장 효율적인 크기의 '자물쇠'를 골라 사용할 수 있게 해주는 아주 똑똑한 방법이랍니다. 상황에 맞게 연장을 골라 쓰는 목수와 같다고 할 수 있죠! 🧰


🕵️‍♂️시나리오 퀴즈

상황: 당신은 대형 온라인 쇼핑몰의 데이터베이스 관리자입니다. 지금 두 가지 작업을 처리해야 해요.

  • 작업 A: 한 고객이 자신의 배송지 주소를 변경합니다.
  • 작업 B: 연말 정산을 위해 모든 상품의 올해 총 판매량을 계산합니다.

퀴즈: 작업 A와 작업 B에 각각 '작은 단위(Fine-grained)' 잠금과 '큰 단위(Coarse-grained)' 잠금 중 어느 것이 더 효율적일까요? 왜 그렇게 생각하는지 간단히 이유를 말씀해주세요! 😊

더보기

정답  : 

  • 작업 A (주소 변경)에는 작은 단위 잠금이 딱이죠. 특정 고객의 데이터(레코드)만 잠그면 다른 수많은 고객이 동시에 쇼핑하는 데 전혀 방해가 되지 않으니까요. 동시성(Concurrency)이 크게 향상돼요!
  • 작업 B (전체 판매량 계산)에는 큰 단위 잠금이 훨씬 효율적이에요. 상품 하나하나를 잠그려면 수만, 수백만 번의 잠금을 관리해야 하는 엄청난 오버헤드(Overhead)가 발생하겠지만, 상품 테이블 전체를 한 번만 잠그면 아주 간단하게 작업을 처리할 수 있죠.

 

2. 의향 잠금(Intention Lock)의 등장

방금 우리가 배운 것처럼, 큰 단위(테이블) 잠금과 작은 단위(레코드) 잠금을 섞어 쓰면 아주 효율적이에요. 그런데 여기서 한 가지 문제가 생길 수 있어요.

 

문제 상황: 만약 제가 특정 학생의 레코드를 수정하려고 '작은 단위 잠금'을 걸었다고 상상해 보세요. 그런데 동시에 다른 관리자가 학생 테이블 전체를 바꾸려고 '큰 단위 잠금'을 걸려고 한다면 어떻게 될까요? 시스템은 제가 이미 작은 레코드를 잠그고 있다는 사실을 어떻게 알 수 있을까요? 테이블에 속한 수만 개의 레코드를 하나하나 다 확인해봐야 할까요? 😱

 

그건 너무 비효율적이겠죠! 바로 이 문제를 해결하기 위해 의향 잠금(Intention Lock), 즉 '의도'를 나타내는 잠금이 등장했답니다.

 

의향 잠금이란? 상위 객체(예: 테이블)에 잠금을 걸기 전에, "나 이제부터 이 테이블의 어떤 부분에 잠금을 걸 거야!"라고 미리 신호를 주는 약속 같은 거예요.

  • IS (Intention Shared): "이 테이블의 특정 레코드들을 읽을(공유 잠금) 예정이야."
  • IX (Intention Exclusive): "이 테이블의 특정 레코드들을 **수정(배타 잠금)**할 예정이야."
  • SIX (Shared with Intention Exclusive): "이 테이블 전체는 읽고, 내부의 특정 레코드는 수정할 예정이야." (조금 더 복잡한 경우죠!)

쉽게 비유하자면, 큰 회의실 문 앞에 "안에서 소그룹 미팅 중이니, 전체 대관은 불가능합니다"라고 팻말을 걸어두는 것과 같아요. 회의실 전체를 빌리고 싶은 사람은 문 앞의 팻말만 보고도 안에 누가 있다는 걸 바로 알 수 있죠. 방마다 들어가서 확인할 필요 없이요.

의향 잠금 덕분에 시스템은 큰 단위 잠금을 걸기 전에 하위 단위의 잠금 상태를 일일이 확인할 필요 없이, 상위 객체의 의향 잠금만 보고도 충돌 여부를 빠르고 효율적으로 판단할 수 있게 된답니다!

 

🕵️‍♂️ 퀴즈

상황: 저는 데이터베이스 관리 시스템(DBMS)이고, 당신은 '학생 테이블'에서 '김민준' 학생의 학점을 C에서 B로 수정하려는 하나의 트랜잭션(작업)입니다.

 

당신은 이제 '김민준' 학생의 데이터(레코드)에 배타 잠금(Exclusive Lock, X-lock) 을 걸어서 아무도 못 건드리게 막아야 해요.

퀴즈: 그 작은 잠금을 걸기 전에, 더 큰 단위인 '학생 테이블' 전체에는 어떤 의향 잠금(Intention Lock) 을 먼저 걸어서 신호를 보내야 할까요?

  1. IS (Intention Shared): "읽을 의도만 있어요!"
  2. IX (Intention Exclusive): "수정할 의도가 있어요!"
  3. S (Shared): "테이블 전체를 읽을 거예요!"

정답은 무엇일까요? 😊

더보기

정답은 2번 IX (Intention Exclusive) 입니다. 🥳

 

'김민준' 학생의 데이터를 **'수정'**한다는 것은 배타적인(Exclusive) 권한이 필요하다는 뜻이죠. 따라서 그 '의도(Intention)'를 상위 객체인 '학생 테이블'에 미리 알려줘야 하므로, IX 잠금을 거는 것이 맞습니다. "나 이 테이블 안에서 뭔가 수정할 거니까, 테이블 전체를 잠그려는 생각은 하지 마!" 하고 깃발을 꽂는 것과 같아요! 🚩

 

3. 잠금 규칙과 호환성

이제 우리는 여러 종류의 잠금을 배웠어요. (S, X, IS, IX, SIX) 데이터베이스 시스템은 이 잠금들을 어떤 규칙에 따라 요청하고, 또 어떤 잠금끼리는 허용하고 어떤 것끼리는 충돌을 일으키는지 판단해야겠죠?

 

잠금 요청 규칙 (프로토콜)

아주 상식적인 규칙이에요. 잠금을 요청할 때는 항상 가장 큰 단위부터 가장 작은 단위 순서로 요청해야 합니다. 마치 큰 건물에 들어갈 때 정문을 먼저 통과하고, 그 다음 내 사무실 문을 여는 것과 같아요.

  1. 가장 상위 객체(데이터베이스)부터 잠금을 시작한다.
  2. 하위 객체에 잠금을 걸기 전에는, 반드시 그 상위 객체에 적절한 의향 잠금(IS, IX)을 먼저 걸어야 한다.
  3. 잠금을 해제할 때는 반대로, 작은 단위부터 큰 단위 순서로 해제한다. (내 사무실 문을 잠그고, 건물 정문을 잠그고 나오는 것처럼요!)

잠금 호환성 행렬 (Lock Compatibility Matrix)

이게 바로 이 시스템의 '교통 규칙'이에요. 어떤 잠금이 걸려 있을 때, 다른 종류의 잠금 요청이 들어오면 허용할지(Yes), 아니면 기다리게 할지(No)를 정의한 표죠.

요청 잠금 IS IX S SIX X
IS O O O O X
IX O O X X X
S O X O X X
SIX O X X X X
X X X X X X
 

표 읽는 법: 가로줄은 '이미 걸려있는 잠금', 세로줄은 '새로 요청된 잠금'을 의미해요.

  • 예를 들어, 어떤 객체에 IS 잠금이 걸려있을 때(가로 첫 번째 줄), 다른 사용자가 IX 잠금을 요청하면(세로 두 번째 칸) 'O' 이므로 허용돼요. "누가 읽을 준비를 하고 있구나, 나도 수정할 준비 좀 해야지" 하는 건 괜찮다는 뜻이죠.
  • 하지만 어떤 객체에 S 잠금(공유 잠금, 읽는 중)이 걸려있을 때(가로 세 번째 줄), 다른 사용자가 IX 잠금을 요청하면(세로 두 번째 칸) 'X' 이므로 거절돼요. 누군가 읽고 있는데 수정하겠다는 신호를 보내면 충돌이 나기 때문이죠!

이 표 덕분에 데이터베이스는 아주 빠르고 간단하게 잠금 요청을 처리하고 데이터의 일관성을 지킬 수 있답니다.


몇가지 예시를 들어 좀 더 깊은 이해를 해볼께요.

1) IX가 걸려있을 때 IX요청이 허용되는 이유

IX 잠금은 '의도'를 나타내는 경고 표지판일 뿐, 실제 자물쇠가 아니기 때문입니다.

조금 더 쉽게 사무실 비유를 통해 설명해 드릴게요.

## 사무실의 회의실 예약하기 🏢

여기 커다란 **사무실 한 층(테이블)**이 있고, 그 안에는 여러 개의 **회의실(레코드/행)**이 있다고 상상해 보세요.

  • IX 잠금 (Intention Exclusive Lock) = 층 입구 안내 데스크에 "회의실 사용 예정"이라고 이름을 적는 행위.
  • X 잠금 (Exclusive Lock) = 특정 회의실 문을 실제로 잠그는 행위.

상황 1: 첫 번째 팀(A팀)의 요청

  1. A팀이 '1번 회의실'을 단독으로 사용하고 싶어 합니다.
  2. A팀은 먼저 층 입구 안내 데스크로 가서 말합니다. "저희 A팀, 안쪽 회의실 중 하나를 단독으로 사용할 예정입니다!" 라고요. 이게 바로 '사무실 층'에 첫 번째 IX 잠금을 거는 것입니다.
  3. 그리고 A팀은 '1번 회의실'로 가서 문을 쾅 잠급니다. 이게 바로 '1번 회의실'에 X 잠금을 거는 것이죠.

상황 2: 두 번째 팀(B팀)의 요청

  1. 이제 B팀이 '2번 회의실'을 단독으로 사용하고 싶어 합니다.
  2. B팀도 층 입구 안내 데스크로 갑니다. A팀이 이미 "회의실 사용 예정"이라고 적어놓은 것을 봅니다.
  3. B팀은 생각하죠. 'A팀이 어딘가를 쓰고 있구나. 하지만 우린 다른 회의실을 쓸 거니까 괜찮아.' 그리고 안내 데스크에 말합니다. "저희 B팀도, 안쪽 다른 회의실을 단독으로 사용할 예정입니다!"
  4. 안내 데스크 직원은 "네, 알겠습니다." 하고 B팀의 이름도 적어줍니다. 이것이 바로 기존 IX 잠금이 걸려있는 상태에서, 또 다른 IX 잠금 요청이 허용되는 순간입니다.

## 왜 허용될까요?

안내 데스크에 이름을 적는 행위(IX 잠금)는 그 층 전체를 못 쓰게 막는 것이 아닙니다. 그저 "이 층 어딘가에서 누군가 독립적인 작업을 하고 있으니, 층 전체를 사용하는 작업(예: 전체 대청소, 전체 정전 작업)은 잠시 기다려주세요" 라는 신호일 뿐이죠.

 

A팀과 B팀은 서로 다른 회의실(레코드)을 사용하기 때문에 충돌이 나지 않습니다. 따라서 두 팀 모두 "회의실 사용할 거예요!" 라는 의도(IX)를 표시하는 것은 전혀 문제가 되지 않는 것입니다.

 

만약 누군가 층 전체를 대청소하려고 S 잠금(층 전체를 읽는 잠금)이나 X 잠금(층 전체를 수정하는 잠금)을 요청했다면, 안내 데스크 직원은 "잠시만요, 지금 안에 회의하는 팀들이 있습니다!" 라며 요청을 거절했을 겁니다. 이것이 바로 IX 잠금이 존재하는 진짜 이유죠.


한 줄 요약: IX 잠금끼리는 서로 충돌하지 않습니다. 왜냐하면 이들은 각자 다른 하위 레코드를 목표로 하는, 충돌하지 않는 '의도'들이기 때문입니다.

 

1) IS가 걸려있을 때 IX요청이 허용되는 이유

IS와 IX 잠금 요청이 서로 허용되는 이유는, 이 둘은 실제 데이터를 잠그는 것이 아니라 앞으로의 '의도'만 알려주는 신호이며, 각자의 최종 목표가 되는 데이터(레코드)가 서로 다를 수 있기 때문입니다.

쉽게 말해, "누군가 읽으려 해요"라는 신호와 "누군가 수정하려 해요"라는 신호는 서로 다른 데이터를 대상으로 할 수 있으므로 굳이 막을 필요가 없는 것이죠.

도서관 비유를 통해 확실하게 이해해 봐요! 📚

## 도서관의 '과학' 섹션

여기 도서관의 커다란 '과학' 섹션(테이블)이 있고, 그 안에는 '물리학 원론'(레코드 A)과 '화학의 정석'(레코드 B)이라는 책이 있다고 상상해 보세요.

  • IS 잠금 (Intention Shared) = 섹션 입구에 "안에서 누가 책 '읽는 중'" 이라고 메모를 붙이는 것.
  • IX 잠금 (Intention Exclusive) = 섹션 입구에 "안에서 누가 책 '수정 중'(필기 등)" 이라고 메모를 붙이는 것.

상황:

  1. 철수(IS 잠금 요청): 철수는 '물리학 원론'을 읽고 싶어요.
    • 그는 먼저 '과학' 섹션 입구로 가서 "안에서 책 읽는 중" (IS) 이라는 메모를 붙입니다.
    • 그리고 '물리학 원론' 책을 집어 들어 조용히 읽기 시작합니다. (책에 대한 S 잠금)
  2. 영희(IX 잠금 요청): 잠시 후, 영희가 '과학' 섹션으로 옵니다. 그녀는 '화학의 정석' 연습문제에 풀이를 적어 넣고 싶어요.
    • 영희는 섹션 입구에서 철수가 붙인 "안에서 책 읽는 중"(IS) 메모를 봅니다.
    • 영희는 생각하죠. '누가 책을 읽고 있구나. 하지만 난 다른 책에 필기할 거니까 괜찮겠지.'
    • 그래서 영희도 그 옆에 "안에서 책 수정 중"(IX) 이라는 메모를 붙입니다. 이것이 바로 IS가 걸린 상태에서 IX 요청이 허용되는 순간입니다.
    • 그리고 영희는 철수가 보던 책이 아닌 '화학의 정석'을 꺼내서 풀이를 적기 시작합니다. (책에 대한 X 잠금)

## 핵심은 이것입니다

철수가 '읽으려는 의도(IS)'와 영희가 '수정하려는 의도(IX)'는 '과학' 섹션 전체에 대한 약속이 아닙니다. 이 신호들은 "이 섹션 어딘가에서 그런 일이 벌어질 겁니다"라는 뜻일 뿐이죠.

 

데이터베이스 시스템은 이렇게 생각합니다. "철수가 읽으려는 책과 영희가 수정하려는 책이 서로 다른 책일 가능성이 있네? 그럼 일단 둘 다 섹션 안으로 들여보내 주자. 실제 충돌은 이들이 같은 책을 잡았을 때만 막으면 돼!"

만약 영희가 철수가 읽고 있는 '물리학 원론'을 수정하려고 했다면, 그때는 '물리학 원론' 책 자체에 걸린 S 잠금 때문에 영희의 X 잠금 요청이 거절되었을 겁니다.

 

결론적으로, IS와 IX는 상위 레벨에서 서로 다른 하위 데이터에 접근할 가능성을 열어두는, 매우 효율적인 '가능성의 신호'이기 때문에 서로를 막지 않는 것입니다.

 
 
 

핵심 내용 요약

  1. 다중 단위 로킹 (Multi-granularity Locking)
    • 데이터베이스 객체를 다양한 크기(단위, Granularity)로 잠글 수 있게 하는 기법이에요.
    • 작업의 성격에 따라 레코드(작은 단위)부터 테이블(큰 단위)까지 가장 효율적인 잠금을 선택해 동시성오버헤드 사이의 균형을 맞추는 것이 목표죠.
  2. 의향 잠금 (Intention Lock)
    • 하위 단위에 잠금을 걸기 전, 상위 단위에 "내 의도는 ~야!" 라고 미리 신호를 보내는 특별한 잠금이에요. (IS, IX, SIX 등)
    • 이 신호 덕분에 시스템은 하위 객체를 일일이 확인할 필요 없이, 잠금 충돌을 빠르고 효율적으로 감지할 수 있어요.
  3. 잠금 규칙과 호환성 행렬
    • 규칙: 잠금을 요청할 땐 위에서 아래로(큰 단위 → 작은 단위), 해제할 땐 아래서 위로(작은 단위 → 큰 단위) 순서로 진행해요.
    • 호환성 행렬: 어떤 잠금끼리 동시에 허용될 수 있는지 정의한 '교통 규칙'으로, 데이터의 일관성을 지켜주는 역할을 해요.
 

최종 퀴즈!

지금까지 배운 모든 지식을 활용해서 풀어보세요. 파이팅! 🦾

상황: '전자제품'이라는 데이터베이스 안에 'TV'라는 테이블이 있고, 그 안에 'OLED-X1'이라는 **레코드(행)**가 있습니다. 당신은 이 'OLED-X1' 레코드의 가격을 인상(수정)하려고 합니다.

문제: 이 작업을 올바르게 수행하기 위한 잠금 요청 순서로 가장 적절한 것은 무엇일까요?

  1. 'OLED-X1' 레코드에 X 잠금을 건다.
  2. 'TV' 테이블에 IX 잠금을 건다. → 'OLED-X1' 레코드에 X 잠금을 건다.
  3. '전자제품' 데이터베이스에 IX 잠금을 건다. → 'TV' 테이블에 IX 잠금을 건다. → 'OLED-X1' 레코드에 X 잠금을 건다.
  4. '전자제품' 데이터베이스에 IS 잠금을 건다. → 'TV' 테이블에 IS 잠금을 건다. → 'OLED-X1' 레코드에 S 잠금을 건다.
더보기

정답 : 3번🏆

  • (규칙 1: 위에서 아래로!) 가장 큰 단위인 '전자제품' 데이터베이스부터 시작했고요.
  • (규칙 2: 의도 알리기!) 최종 목표가 '수정'이므로, 그 의도를 알리는 IX 잠금을 데이터베이스와 테이블에 순서대로 잘 걸어주었죠.
  • (규칙 3: 최종 작업!) 마지막으로 실제 목표물인 'OLED-X1' 레코드에 수정을 위한 X 잠금을 걸었네요.

다른 보기들이 틀린 이유도 한번 짚어볼까요?

  • 1번, 2번은 가장 상위 객체부터 시작해야 한다는 규칙을 어겼어요.
  • 4번은 '수정'을 해야 하는데 '읽기'에 사용하는 IS, S 잠금을 사용해서 틀렸죠.