래치와 락

오라클의 동기화 메커니즘
동시에 수많은 프로세스가 동일 리소스를 사용 - > 리소스를 보호할 정밀한 메커니즘 필요 : 래치와 락을 이용한다

래치 ->
목적 : 하나의 목적을 수행함. 메모리 구조에 대한 배타적인 접근을 위함 (오라클 9i부터 cache buffers chains latch들은 읽기 전용시에 공유가 가능함)
사용범위 : SGA내부의 데이터 구조에만 적용. 메모리 오브젝트를 임시적으로 보호함. 단일 오퍼레이션으로 메모리 구조에 대한 접근 제어. 트랜잭션 단위가 아님.
획득방식 : 두 가지 모드로 요청이 가능 : willing-to-wait 또는 no-wait
범위 : SGA내부에 정보가 존재하며, 로컬 인스턴스에서만 볼 수 있음 - 래치는 인스턴스 레벨로 작동
복잡도 : 단순한 명령어를 사용하여 구현됨. 일반적으로 test-and-set, compare-and-swap 또는 단순한 CPU명령어. 구현이 쉬움
지속기간 : 아주 짧은 순간만 지속됨 (microsecond단위)
큐 : 프로세스가 래치 획득을 실패한 후 슬립(sleep) 상태로 들어갈 때, 해당 요청은 큐(queue)로 관리되지 않으며,
요청한 순서대로 서비스되지 않음(latch wait list를 이용하여 큐 방식으로 사용되는 래치들은 예외임)
데드락 : 래치는 데드락(deadlock)이 발생되지 않도록 구현됨


락 ->
목적 : 두 가지 목적을 수행함. 락 모드가 호환 가능하면 다수의 프로세스가 동일한 리소스를 공유하는 것을 허용하며, 락 모드가 호환 가능하지 않으면 리소스에 대한 배타적인 접근만 허용함
사용범위 : 테이블, 데이터 블록 및 state object와 같은 오브젝트를 보호함. 데이터베이스의 데이터 또는 메타데이터 접근 제어. 트랜잭션 단위
획득방식 : 6가지 모드로 요청이 가능. null, row sharem row exclusive, share, share row exclusive, exclusive
범위 : 데이터베이스 내부에 정보가 존재하며, 모든 인스턴스에서 볼 수 있음 - 락은 데이터베이스 레벨에서 작동
복잡도 : 문맥 교환(context switch)을 포함한 일련의 명령어들을 사용하여 구현됨. 구현이 복잡함
지속기간 : 일정 시간 동안 지속됨 (트랜잭션 동안)
큐 : 프로세스가 락 획득을 실패한 후, 해당 요청은 큐(queue)로 관리되며, 요청한 순서대로 서비스됨(NOWAIT 모드는 예외임)
데드락 : 락은 큐(queue)방식을 사용하며, 데드락이 발생될 가능성이 높다. 데드락이 발생될 때마다 트레이스 파일이 생성

오라클 자원 보호를 위해 락과 래치를 이용하지만 -> 동시에 사용자가 너무 많이 접근하여 -> 락과 래치에 대한 경합이 발생할 수 있다.


래치
래치란? -> 가벼운락
락 중에서도 아주 빠른 속도로 작동하게끔 구현된 경량화된 락 : 이해하기는 편하겠지만 사실 래치와 락은 완전히 별개의 내용이다.
뮤텍스와 유사하다 - 뮤텍스 : 특정 리소스에 대한 배타적인 접근을 가능하게 하는 동기화 메커니즘.
아주 빠르고 가볍게 특정 리소스에 대한 동기화를 구현한다.
Shared Pool영역에 존재하는 일종의 메모리 구조체 - 간단하고 작은 메모리영역을 사용하며, 래치 획득.해제는 하드웨어 칩셋이 제공하는 명령을 사용하게된다(원자성 보장)
래치와 관련된 작업들의 부하를 최소화하기 위해 래치 획득의 순서를 보장하지 않는다.

래치가 보호하는 리소스
래치가 보호하는 리소스는 SGA이다 - SGA의 특정 영역을 탐색하거나 변경하고자 하는 프로세스는 반드시 해당 영역을 관장하는 래치를 획득해야한다.
래치를 획득하는데 실패한 프로세스는 래치를 획득할 때 까지 특정 대기 이벤트 발생 - latch free // 10g부터 중요한 래치는 따로 이름이 있다.

부모래치 : 여러개의 자식 래치를 거느리는 래치
독립래치 : 전체 인스턴스에 단 하나만 존재하는 래치
자식래치 : 부모 래치에 속한 래치
-> V$LATCH_PARENT, V$LATCH_CHILDREN뷰를 통해 관찰 가능하다.

메모리의 구조와 알고리즘이 여러 개의 래치를 통해 관리할 수 있다면 부모-자식 래치를 사용한다.
ex) 각각의 해시 체인을 독립적으로 관리할 수 있는 구조의 버퍼 캐시 - cache buffers cahins 래치는 보통 1024개의 자식 래치가 존재한다.

독립래치들이 부모-자식 래치로 변해가는 추세.
락 자체도 Shared Pool영역에 존재하는 메모리 구조체이다 -> 래치에 의해 보호된다.

래치 동작 메커니즘
래치 레벨 - 래치 획득 과정에서의 데드락을 원천적으로 방지하기 위해 래치에 0~13까지의 레벨을 부여한다
래치를 보유한 상태에서 또다른 래치를 획득하려 한다면, 현재 보유한 래치의 레벨보다 높은 레벨의 래치만을 획득할 수 있다.
더 낮은 레벨의 래치를 획득하려 한다면 No-wait모드로 획득하게되며, 그 시도가 실패하게되면 현재의 래치를 해지한뒤, 낮은레벨부터 높은 레벨 순서로 다시 래치를 획득하려 하게 된다

래치 모드
기본적으로 Exclusive. 특정 래치에서 Shared 모드를 사용하기도 한다.

래치 획득
Willing-to-wait 모드의 래치 획득 - 래치를 획득할 수 있을 때까지 대기한다 -> _SPIN_COUNT파라메터값만큼 반복해서 획득시도(기본값 2000)
스핀시도로 래치 획득 실패시엔 프로세스가 슬립상태가 된다.
타임아웃이 발생하면 다시 깨어나 래치 획득 시도를 하거나, 래치 대기 목록에 등록해놓고 다른 프로세스가 깨워주면 동작하거나
CPU가 하나인 시스템에서는 스핀 수행 않는다 _SPIN_COUNT가 1일것이다.
래치 획득 성공과 실패에 대한 통계값은 V$LATCH뷰의 GETS, MISSES, SPIN_GETS, SLEEPS 컬럼을 통해 관찰 가능하다.

No-wait 모드의 래치 획득
데드락 방지를 위해 - 더 높은 레벨의 래치를 획득하여 할 때 No-wait 모드로 획득시도한다.
redo copy와 같은 특수한 래치를 획득 시도할때 No-wait모드로 시도한다. 20개 래치 존재 -> 1 ~ 19번까지는 No-wait로 획득시도.
모두 실패했다면 20번째에 대해서는 Willing-to-wait모드로 획득 시도한다.
No-wait모드로 획득 또는 실패한 래치에 대한 통계는, 래치 관련 뷰의 IMMEDIATE_GETS, IMMEDIATE_MISSES 컬럼 값으로 관찰

래치 Cleanup
래치 획득 시도를 4번 실패하게되면 PMON에 래치를 보유한 프로세스가 살아있는지 체크 요청한다
프로세스가 래치를 보유한 채로 갑자기 종료됨 -> PMON : 각 래치마다 구현되어있는 Cleanup function을 호출 ->
래치 복구 영역에 기록된 정보를 통해 공유 메모리 영역을 원래 상태로 복구 -> PMON : 래치 해지
프로세스가 살아있다면 실제로 경합중인 것임


래치 관련 Dynamic Views
V$LATCH - 모든 래치의 통계에 대한 합계치
V$LATCH_PARENT - 독립 래치에 대한 통계값
V$LATCH_CHILDREN - 개별 자식 래치들에 대한 통계값
주요 컬럼들
GETS - Willint-to-wait 모드에서 슬립하기 전의 래치 "요청" 회수
MISSES - Willint-to-wait 모드에서 슬립하기 전의 래치 획득 실패 회수
SPIN_GETS - Willint-to-wait 모드에서 슬립하기 전의 스핀단계에서의 래치 획득 성공 회수
SLEEPS - Willint-to-wait 모드에서 슬립 회수
IMMEDIATE_GETS - No-wait 모드에서 래치 획득 성공 회수
IMMEDIATE_MISSES - No-wait 모드에서 래치 획득 실패 회수
SLEEP1 ~ SLEEP4 - 1~3회의 슬립회수와 4회 이상의 슬립 회수. 10gR2부터는 V$EVENT_HISTOGRAM뷰로 대체되었다.
WAITER_WOKEN - latch wait posting을 사용할 경우 세션이 깨어난 회수. 10gR2부터는 latch wait posting 알고리즘이 완전히 바뀌어서 사용되지 않음
WAIT_TIME - 래치를 획득하기 위해 대기한 시간 (microsecond 단위)

Willing-to-wait모드일때 MISSES/GETS 값
No-wait모드일때 IMMEDIATE_MISSES / (IMMEDIATE_GETS + IMMEDIATE_MISSES) 값 이 1% 이상이면 래치 경합이 발생한 것으로 보기도 한다.
WAIT_TIME을 이용해 대기시간이 CPU시간에 비해 어느 정도 높은 값을 보일 경우 래치 경합이 발생한 것으로 보기도 한다.

V$LATCH_MISSES뷰 - 래치 미스가 발생한 경우 오라클 커널 코드의 어떤 영역에서 발생했는지에 대한 정보를 담고 있다.

 

일반적인 래치 관련 대기이벤트들 - 아래 외의 경우에는 latch free 대기이벤트를 사용한다.
latch: cache buffers chains -> 버퍼캐시의 특정 블록을 탐색하고자 할때 - cache buffer chains 래치를 획득해야함 - 이 때 경합이 발생하면 latch: cache buffers chains대기 이벤트 발생
latch: cache buffers lru chain -> 버퍼캐시의 프리버퍼와 더티버퍼를 탐색하고자 할때 - cache buffers lru chain획득해야 하는데 못하면 latch: cache buffers lru chain
latch: shared pool -> Shared Pool의 힙 영역에서 새로운 청크를 할당받고자 하는 경우. 이 때 경합 발생하면~
latch: library cache -> Library Cache 영역을 탐색하고자 하는 경우. 이 때 경합 발생하면~
latch: redo copy -> DML에 의한 변동 사항을 리두 버퍼에 기록하고자 하는 프로세스는 작업의 전 과정 동안 redo copy 래치를 획득해야한다. 이 때 경합 발생하면~

래치 이름을 직접 알 수 없는 latch free 대기 이벤트의 경우에는 P2의 값이 latch#이므로 이 값을 V$LATCHNAME.LATCH#과 조인하면 래치 이름을 얻을 수 있다.

 


락의 분류
Enqueue 락 - 일반 락
오라클 매뉴얼상의 락 분류
- DML Lock
Row Locks (TX)
Table Locks (TM)
- DDL Lock
- Latches and Internal Locks
Latches
Internal Locks
Dictionary Cache Locks
File and Log Management Locks
Tablespace and Rollback Segment Locks

Steve Adams라는 사람이 분류한 방식
- Row Cache Enqueues
- Library Cache Locks and Pins
- DML Locks
- Buffer Locks
- Sort Locks

조동욱씨가 분류한 방식
Enqueue 락 - <ResourceType-ID1-ID2> 해쉬 체인 형태로 여러개의 리소스 구조체를 거느린다.
- User Type Lock : TX, TM, UL
- System Type Lock : CF, US, CI, TC, JS . . .
일반 락 : 개별 메모리 영역 자체에 보유 프로세스 목록과 대기 프로세스 목록을 관리한다.
- row cache lock
- library cache lock, library cache pin
- buffer lock

락이 보호하는 리소스
래치가 SGA를 보호한다면, 락은 데이터베이스 전체를 보호한다고 할 수 있다.
Enqueue 락 - V$LOCK or V$SESSION_WAIT
일반 락 - V$SESSION_WAIT
뷰를 통해서 어디에서 대기현상이 발생하는지 볼 수 있다.

락 동작 메커니즘
락모드
락 획득시 사용 가능한 모드
0 : None
1 : Null(N)
2 : Sub-Shared(SS) 또는 Row-Shared(RS)
3 : Sub-Exclusive(SX) 또는 Row-Exclusive(RX)
4 : Shared(S)
5 : Shared-Sub-Exclusive(SSX) 또는 Shared-Row-Exclusive(SRX)
6 : Exclusive(X)

락획득
- Enqueue락 획득에 실패한 프로세스는 자신을 Enqueue 리소스의 대기 목록에 등록한다
현재 락 보유 프로세스는 락 사용 끝나면, 락을 해제하고 대기목록상 다음 프로세스를 깨워준다.
타임아웃 3초 : 아무도 안깨워줘도 3초마다 스스로 깨어난다. 데드락 발생한 것은 아닌지 확인하고 다시 대기한다.
10g 부터는 모든 Enqueue 리소스 유형에 대해 별도의 대기 이벤트를 등록했으며, 같은 리소스라도 상황에 따라 대기이벤트가 세분화 되어있다
- 일반락도 기본적으로 Enqueue락과 같은 방식으로 작동하지만, 락의 종류에 따라 타임아웃 시간이 모두 다르다.


락 관련 Dynamic Views
V$LOCK - Enqueue락과 관련된 뷰
주요 컬럼
SID - 락을 보유중이거나 요청 중인 세션의 아이디. LMODE > 0 이면 락을 보유중인 세션이고, REQUEST > 0 이면 락을 요청 중인 세션이다.
TYPE - Enqueue 락의 리소스 타입 (예: TM, TX, UL, US, CI, TC, . . .)
ID1 - 리소스 아이디1
ID2 - 리소스 아이디2
LMODE - 락을 보유하고 있는 경우의 모드(1~6. 락 모드 참조)
REQUEST - 락을 요청중인 경우의 모드(1~6. 락 모드 참조)
CTIME - 현재의 락 모드가 허용된 이후의 시간(second). 즉, 락을 보유하거나 요청한 이후부터의 시간
BLOCK - 현재의 락이 다른 락을 블로킹하고 있는지의 여부. 1 = 다른 락을 블로킹중, 0 = 다른 락을 블로킹하지 않음

V$LOCKED_OBJECT - 현재 시스템의 모든 트랜잭션에 의해 획득 중인 TM 락에 대한 정보를 제공한다.

락은 래치와 달리 매우 다양한 리소스를 보호하기 때문에 정확한 정보를 얻기 위해서는 많은 정보가 필요하다
-> 리소스 유형에 따라 DBA_OBJECTS, DBA_TABLESPACES, V$SESSION, V$TRANSACTION, V$UNDOSTAT, V$SQL

Enqueue락이 아닌 경우 -> DBA_DDL_LOCKS, DBA_KGLLOCK, X$KGLLK, X$KGLPN, V@ROWCACHE_PARENT . . . . . .

일반적인 락 관련 대기이벤트들
Enqueue락에 의한 대기 현상들은 모두 개별 대기이벤트로 나뉘어서 정의되어있다.

Enqueue락이 아닌 경우
- row cache lock : row cache lock에 의한 경합
- buffer busy waits, read by other session : buffer lock에 의한 경합
- library cache lock : library cache lock에 의한 경합
- library cache pin : library cache pin에 의한 경합
- DFS lock handle : 글로벌 락인 경우에 관찰되는데, 이 책에서는 SV락에 의한 경합을 논의하는 과정에서 다루게 될 것이다.

V$SESSION_WAIT뷰나 V$SESSION뷰의 EVENT 컬럼의 값이 'enq:%' (9i까지는 enqueue)이면 Enqueue 락에 의한 경합이 발생한다는 의미이다.
이경우 P1=name|mode, P2,P3는 V$LOCK뷰의 ID1, ID2의 값과 동일
Enqueue락이 아니면 대기이벤트 종류마다 P1, P2, P3의 의미가 다르다.