LATCH(래치) 와 LOCK(락) 1

래치와 락의 분류
LATCH (래치)
- 순서를 보장 받지 못하는 이유
래치의 분류
래치의 실제 작동 예
래치 레벨
- 데드락에 빠지는 상황
래치 모드
래치 획득
willing-to-wait
주의 사항
상태확인
no-wait 
상태확인
latch Cleanup
동작방식
wake 방식 
타임아웃
래치대기목록 


래치와 락
의 사전적 의미는 비슷하지만 오라클에서 실제 사용 대상이나, 방식에서는 차이가 있다.

현재의 Database 는 Mega User 의 요청을 동시적으로 처리를 한다. 그러기 위해서는 반드시 내부적으로 원자성을 지키기 위한 메카니즘이 필요하다. 실제 래치와 락의 역할은 동시성을 제공하는 Database(논리, 물리)에 대한 atomicity(원자성)을 보장해주는 역할을 한다.


래치와 락의 분류 

 

분류 래치(LATCH) 락(LOCK)
목적 하나의 목정을 수행함 : 메모리 구조에 대한 배타적인 접근을 위함 (오라클 9i부터 cache buffers chains latch 들은 읽기 전용시에 공유가 가능함)
두가지 목적을 수행함 : 락 모드가 호환 가능하면 다수의 프로세스가 동일한 리소스를 공유하는 것을 허용하며, 락 모드가 호환 가능하지 않으면 리소스에 대한 배타적인 접근만 허용함 
사용범위 sga내부의 데이터 구조에만 적용.
메모리 오브젝트를 임시적으로 보호함.
단일 오퍼레이션으로 메모리 구조에 대한 접근 제어. 트랜잭션 단위가 아님.
테이블, 데이터 블록 및 state object와 같은 오브젝트를 보호함.
데이터베이스의 데이터 또는 메타데이터 접근제어. 트랜잭션 단위
획득방식 두가지 모드로 요청이 가능
willing-to-wiat 또는 no-wait
6가지 모드로 요청가능 : null, row share, row exclusive, share, share row exclusive, 또는 exclusive
아래 표 참조.
범위 sga내부에 정보가 존재하며, 로컬 인스턴스에만 볼 수 있음.
- 인스턴트 레벨로 작동-
데이터베이스 내부에 정보가 존재하며, 모든 인스턴스에서 볼 수 있음.
- lock은 데이터 베이스 레벨에서 작동.
복잡도 단순한 명령어를 사용하여 구현됨.
일반적으로 test-and-set, compare-and-swap 또는 단순한 cpu명령어. 구현이 쉬움
문맥 교환(context switch)을 포함한 일련의 명령어들을 사용하여 구현됨. 구현이 복잡하다.
지속기간 짧은 순간만 지속됨
(microsecond단위) = 100만분의 1초
일정시간동안 지속
(트랜잭션 동안)
큐(Queue) 프로세스가 래치 획득을 실패 한 후 슬립(sleep) 상태로 들어갈 때, 해당 요청은 큐(queue)로 관리되지 않으며, 요청한 순서대로 서비스 되지않음
(latch wait list를 이용하여 큐방식으로 사용되는 래치들은 예외)
프로세스가 락 획득을 실패한 후, 해당 요청은 큐(queue)로 관리되며, 요청한 순서대로 서비스됨(nowait 모드는 예외)
데드락(DEADLOCK) 데드락이 발생되지 않도록 구현됨

락은 큐 방식을 사용하며, 데드락이 발생될 가능성이 높다. 데드락이 발생 될 때마다 트레이스 파일이 생성된다.
<<출처 : Advanced OWI (저자 : 조동욱)>>





LATCH (래치)



오라클에서는 Latch 를 Lightweight lock 으로 분류를 하고 있다. 실제로 SGA에서 동작하는 Latch는 아주 빠른속도로 동작하는 경량화된 Lock 이기 때문이다. 하지만 일반적으로 lock 이라고 하면 용어의 혼란이 생기므로 전혀 다른 객체로 분류하여 설명한다.

 "래치의 필요성은 병렬프로그래밍에서 자주 등장한다. 병렬프로그래밍을 작성하면 여러개의 프로세스가 동시적으로 CPU자원을 얻기 위해 경합을 펼치며 특히 Global 메모리 영역을 사용할 때 원자성이 지키지 못한다면 매우 큰 문제가 발생한다. 그래서 프로그래밍에서는 원자성을 보장하기 위해 다양한 디자인패턴이 존재한다."

래치는 Shared Pool 영역에 존재하는 메모리 구조체이다. 래치를 얻고(get) 해제(release) 하는 작업을 할때 하드웨어 칩셋에서 제공하는 TEST-AND-SET, COMPARE-AND-SWAP과 같은 명령을 사용하기 때문에 원자성을 보장한다.

<<출처 : Advanced OWI (저자 : 조동욱)>>


 래치는 특정 메모리의 영역에 대한 접근을 위해서 필요한 key 와 같은 객체이다. 이 key 를 얻는 작업은 소프트웨어적으로 얻거나 반납하지 않고 하드웨어 칩셋에서 제공하는 명령을 이용하여 얻거나 반납하는 하드웨어적인 원자성을 보장한다. 


래치는 아주 빠른 속도로 동작하고 래치 획득의 순서를 보장하지 않는다.


순서를 보장받지 못하는 이유

- 순서를 보장받기 위한 별도의 알고리즘이 필요하기 때문에 빠른 속도의 래치에서는 맞지 않다.

- 많은 프로세스들이 동시적으로 래치를 얻기 위해 경합을 한다.



래치의 분류

Parent latch : 자식 래치를 가지고 있는 래치
Solitary latch : 전체 인스턴스에 하나만 존재하는 래치
Child Latch  : Parent latch에 속하는 래치



래치의 실제 작동 예 

- 새로운 SQL 문을 실행하고자 하는 프로세스는 SQL을 Shared Pool의 library cache영역에 올려야 한다. 이때 필요한 Heap 메모리를 할당 받기 위해서 shared pool latch를 획득해야 한다. 


- Select 문이 데이터 블록을 읽기 위해서는 데이터블록의 DBA(Data Block Address)와 클래스에 해당하는 해시 체인에 접근하고자 하는 모든 프로세스는 cache buffers chains latch를 획득해야 한다.


- DML으로 데이터가 변경될 때는 PGA영역에 Redo 데이터(Change Vector)를 생성하는데  이 Change Vector를 Redo Buffer 로 복사하기 위해서는 redo copy latch를 획득해야 한다. 


위와 같이 래치를 얻어야만 특정 리소스에 접근하거나 수정이 가능하다. 하지만 동시성을 제공하는 특성상 래치 획득을 실패하는 상황이 발생하는데, 실패한 프로세스는 다시 래치를 get 할 때까지 대기 이벤트를 기다린다.

- 9i 이하 : 래치 획득에 실패한 프로세스는 latch free event  를 대기한다. 
- 10g : 기본적으로 latch free event 를 사용하고 특수한 래치에 대해서는 별도의 대기 이벤트를 사용한다.



래치 레벨
데드락을 방지하기 위해서 0~13 의 레벨을 래치에 부여한다. 
가장 최근에 획득한 래치보다 높은 래치를 얻어야 하며, 낮은 래치를 얻기위해서는 No-wait 방식으로 획득해야 한다. 

데드락에 빠지는 상황

그림 1
1. A process 가 level1 래치를 획득한다.
2. B process 가 level2 래치를 획득한다.

그림2 
3. A process 가 level2 래치 획득을 시도하지만 A process 가 잡고 있어서 대기한다.

그림3
4. 이미 level2를 가지고 있는 A process 가 Level1 래치획득을 시도하여 획득을 위해 대기한다.


둘중 한쪽 작업이 끝나야만 해제가 되는데. 아래같은 상황을 보고 데드락 현상이라고 한다.






래치 모드
래치는 기본적으로 Exclusive 하게 동작한다. 한 순간에는 하나의 프로세스가 래치를 보유한다는 뜻이다. 원자성을 보장하기 위해서 당연하다.
 하지만 Hash chain (해쉬 체인)의 cashe buffers chains latch는 읽기 작업인 경우에는 Shared Mode로 동작한다. 



래치 획득 

래치를 획득하는 모드는 두가지가 있고 관련된 기술로는 Latch Cleanup 이 있다.
래치 획득 모드

- willing-to-wait
- no-wait





willing-to-wait



래치를 획득하고자 하는 프로세스는 기본적으로 willing-to-wait 모드로 동작한다. 이 방식은 원하는 래치를 획득실패 했을경우 래치를 획득할 수 있을 때까지 대기한다. 

1. 먼저 A process 가 래치를 잡고 있다. 
2. B process가 A process가 잡고 있는 래치를 획득 시도한다.
3, 4 . A process 가 이미 잡고 있으므로 _SPIN_COUNT 만큼 Loop를 돌면서 재시도(4) 한다.
5. _SPIN_COUNT 만큼 재시도 했음에도 불구하고 획득하지 못하는경우 Sleep 상태가 된다. (_SPIN_COUNT 기본값 2000)

6. 타임아웃이나 래치대기목록에 의해 깨어난다.
2번 순서로 돌아간다.



5, 6 의 과정으로 진행되기 전에 3, 4 번의 과정을 거치는 이유는 Sleep 상태는 CPU에서 해당 작업 내용이 다른곳으로 옮겨지는 Context Switching 이 발생하여 CPU 자원을 다른 프로세스에게 양보하는 과정인데. 이 과정에서 다른 프로세스도 똑같이 다른곳에 옮겨져 있는 작업내용을 CPU 로 올리는 작업을 하게 된다. 이 같은 일련의 과정을 Context Switching 이라고 하는데 이 Context Switching 이 비용이 크기 때문이다.
 만약 래치의 해제와 획득이 오래걸린다면 Context Switching 하는것이 나은 방법이지만, 래치는 아주 빠른속도로 해지된다. 그렇기 때문에 위와 같은 알고리즘을 동작하게 된다.

- SPIN 은 점유하고 있는 CPU 를 다른 프로세스에게 양보하지 않기 위한 작업이다. 그래서 다른말로 Active Wait 라고 부르기도 한다.


주의사항
- 많은 프로세스들이 래치 경합을 펼치는 경우 동시에 spin 을 많이 하게 되면 cpu 사용률을 올린다. 이 같은 상황에서 CPU 를 추가하는것은 무의미하다. 오히려 모든 CPU 에서 높은 사용률을 보일 것이다. 
- CPU 가 하나밖에 없는 시스템에서는 스핀을 하지 않는다. 

상태 확인
V$LATCH 

GETS : 2번에 해당한다. 최초 시도 값 1 증가한다.
MISSES : 최초 시도에서 실패한 경우 1  증가
SPIN_GETS : 3, 4 과정에서 획득하게 되면 1 증가
SLEEPS : 슬립 상태에 빠질때마다 증가





No-wait   


위에서 한번 Dead Lock 에 빠지는 상황에 대해서 나왔다. 그래서 데드락을 피하기 위해 아래와 같은 방식으로 동작하는데 이 방식이 바로 No-wait 모드이다. 

그림 1
1. A process 가 level1 래치를 획득한다.
2. B process 가 level2 래치를 획득한다.

그림2 
3. A process 가 level2 래치 획득을 시도하지만 A process 가 잡고 있어서 대기한다.

그림3
4. 이미 level2를 가지고 있는 A process 가 Level1 래치획득을 시도하지만 실패한다.

그림4
4. 획득하려는 래치보다 낮은 래치를 보유중이므로 데드락 방지를 위해 해제한다.
3. A process 는 해제된 Level2 process 를 획득하여 작업을 진행한다.

이후
B process 는 A process 가 Lv1 래치를 해제하면 그제서야 Lv1 , Lv2 순서로 획득을 재시도하여 작업을 진행한다.




상태 확인 
V$LATCH 

GETS : 최초 시도시 값 1 증가한다.
IMMEDIATE_GETS : No-wait 모드로 래치 획득에 성공하면 1증가
IMMEDIATE_MISSES : 실패시 1 증가 




Latch Cleanup


 래치를 획득하려는 프로세스는 이미 다른 프로세스가 원하는 래치를 잡고 있으면 재시도를 하게 된다는 것을 위에서 보았다. 하지만 무작정 재시도 하지 않고 4번째 시도에서도 실패하면 PMON 에게 래치를 잡고 있는 프로세스가 정상작동중인지 체크를 요청한다. 만약에 래치를 잡고 있는 프로세스가 죽어있으면 PMON 은 Latch Cleanup 과정을 수행한다.
 

동작방식
래치를 획득한 프로세스는 공유 메모리 영역을 변경하기 전에 latch recovery area(래치 복구 영역) 에 작업 내용을 기록하고 변경한다. 이때 프로세스에 문제가 발생하여 갑자기 종료되는 경우에 PMON 은 해당 래치의 Cleanup function 을 호출하여 수정 전 상태로 돌리고 래치를 풀어준다. (즉 모든 래치는 Cleanup function 이 구현되어 있다는 것을 의미) 


wake 방식



타임아웃 ( = 대기시간)
Sleep 상태의 프로세스가 Wake 하는 방식중 타입아웃 방식은 Exponential backoff sleep 라는 알고리즘으로 동작한다. 즉 sleep 상태가 될 때마다 sleep 시간이 두배씩 증가한다는 의미인데, 최초 sleep 상태는 1/100 초간 sleep 상태가 되고 또 획득에서 실패하여 다음 sleep 상태에는 시간이 두배로 늘어난다. 이렇게 사용하는 이유는 과도한 SPIN 을 방지하기 위함이다.


래치 대기목록( latch wait posting)
5번과정에서 sleep 상태가 되면 래치대기목록으로 관리된다.  6번의 과정( wake ) 이 되기 위해서는 A process가 작업을 끝내고 래치를 해제할때 B process 를 깨운다. 일반적으로 이 방법을 사용하게 되면 대기상태의 프로세스의 순서는 보장되지만 래치대기목록에 포함되지 않은 신규의 process 가 래치를 획득할 가능성이 있으므로 완벽하게 순서가 보장되지 않는다. 

(위 설명은 Wake List가 큐형태로 관리 되었을 경우의 일이다. 아래 그림에 대입하여 생각해보면 7 번 순서가 끝난후 8번 작업은 Wake List 중 가장 처음에 등록된 process 를 wake 하게 된다고 이해하면 되겠다. 어떤 방식인지는 정확히 모르겠음.....ㅠㅠ)

* 그림은 위 설명과 약간 다르다.

1. A process 가 래치를 획득한다.
5. 이후 B,C,D process 가 획득을 시도하고 실패하여 모두 sleep 모드가 된다 (생략)
6. sleep 상태가 된 process 들은 Wait List 에 등록되어 관리된다.
7. A process 가 작업을 마치고 Wait List에 알린다.
8. B,C,D process가 wake 하여 래치 획득을 시도하여 그중 하나의 process가 획득하고 나머지는 다시 Wait List에 남는다. 




이 경우는 한번 sleep 상태가 된 후에 A process가 작업이 끝나기 전까진 wake 되지 않기 때문에 불필요하게 wake 되어 SPIN 과정을 하지 않는다는 장점이 있다. Oracle8i 까지는 shared pool latch 와 library cache latch 에 대해서만 이 기법을 사용했지만 버전이 올라갈 수록 많은 수의 래치가 이 방식을 사용한다. 
단, 래치 대기목록 자체도 객체이기 때문에 latch 로 보호된다. 9i 까지는 latch wait list latch 을 사용했지만 10g 에서부터는 존재하지 않는다.(아직 알 수 없음)





참조

http://blog.naver.com/PostView.nhn?blogId=dangtong76&logNo=140064903533
Advanced OWI in Oracle 10g : 저자 조동욱


'Oracle > OWI' 카테고리의 다른 글

1 CPU에서는 _SPIN_COUNT 값이 1 인 이유  (2) 2012.03.25
래치 관련 대기 이벤트  (0) 2012.03.21
OWI ( Oracle Wait Interface )  (0) 2012.03.19