래치
- 다수의 프로세스가 동시에 공유 메모리를 수정할 때 발생할 수 있는 문제를 제거하기 위해 래치를 사용
# 래치의 유형
- exclusive 래치
- shared read 래치
- sharable 래치 (exclusive모드로 shared read 래치를 획득)
# 래치를 획득하는 방식
- willing to wait방식(대부분의 경우)
- immediate방식
- 래치는 SGA내의 메모리 위치와 해당 위치의 값을 확인하고 변경하기 위해서 사용할 수 있는 atomic CPU연산의 조합이다.
- 안정적으로 래치를 획득하기 위해 단일 CPU가 전체 연산을 수행하는 동안에 방해 받지 않아야 한다.
- 한번에 하나의 CPU만 메모리의 특정 위치를 액세스하도록 메모리 버스에 락킹을 설정하는 atomic CPU연산이 사용된다.
1)래치의 숨겨진 로직
# exclusive 래치 획득 절차
- 레지스터 변수 X는 래치 주소 A를 가리키도록 설정
- 만일 주소 A 의 값이 0이면 0xff로 설정 (atomic)
- 만일 주소 A의 값이 0xff로 설정되어있다면, 래치를 "소유"
- 만일 그렇지 않다면 처음으로 되될아가서 재 시도(수천번)
# exclusive 래치의 단점 : 배타적
- 한번에 단 하나의 세션만이 래치를 소유할 수 있다는 것은, 한 순간에 단 하나의 세션만이 보호된 리소스에 접근할 수 있다는 의미
- 다수의 세션이 보호된 메모리구조를 읽기만하고 변경하지 않는다면 이러한 방식은 확장성을 저해
- 9i에서는 동시성이 높은 영역들에 대한 sharable래치의 사용을 확대
# sharable래치의 기본적인 의사코드
- 플래그 F를 0으로 설정
- 레지스터 변수 X는 래치주소 L을 가리키도록 설정
- 레지스터 변수 Y는 L에 저장된 현재값을 저장하도록 설정
- 레지스터 변수 z는 새로운 값을 설정
- 만일 "Y의 값" = "L의 값"이라면, L을 "z의 값"으로 설정하고 플래그 F를 1로 설정 *(atomic)
- 만일 플래그 F가 1로 설정되었다면, 래치 값은 수정된 것이다.
1. 하나의 reader의 요청시 동작단계
- 수천 번 Loop 수행
- 만일 write bit가 설정되었다면 loop의 처음으로 이동
- 래치 value를 value+1로 설정하기 위해 시도 (읽기 권한을 획득하기 위함)
- 만일 플래그가 설정되면 Loop를 빠져나옴
- 읽기작업을 완료한 프로세스는 래치 값을 1감소 시키기 위해서 위와 유사한 과정을 수행(write bit체크 X)
2. 변경작업을 위한 수행단계
- 수천번 Loop 수행
- 만일 write bit가 설정되었다면 Loop의 처음으로이동
- 래치 value를 "write bit + curent value"로 설정하기 위해 시도(write bit를 획득하기 위함)
- 만일 플래그가 설정되면 Loop를 빠져나옴
- reader value가 0이 될 때까지 대기
3. 위의 두 전략의 효과
- reader가 리소스를 사용하는 동안 writer가 "exclusive"비트를 획득하도록 허용한 후,
reader가 리소스를 "모두사용"할 때까지 대기하도록 하는것 - writer가 write bit를 설정했다면, 새로운 reader는 리소스를 사용할 수 없으며, 한번에 하나의 writer만이 write bit를 설정할 수 있다.
- reader들 사이의 공유는 극대화, writer와관련된 지연은 최소화
표4-1. 래치의 메모리 위치에 기록된 값들의 예
래치 값 | 설명 |
---|
0x00000005 | 현재 다섯개의 프로세스가 shared 방식으로 래치를 획득하고 있다. |
0x40000003 | 현재 세개의 프로세스가 shared 모드로 래치를 획득하고있고, 배타적인 writer가 새로운 reader를 허용하지 않도록 블로킹 비트를 설정하였다. |
0x20000014 | 프로세스 0x14(v$process.id)는 writer이며, 배타적으롤 래치를 획득하고있다. |
# writer가 shareable 래치에 대해 reader와 경쟁한다면, 래치를 수정하기 위해 두단계를 거친다.
1. 1bit를 "blocked"로 표시한다.
2. 모든 reader가 래치를 사용하면, 또 다른 비트를 "write-only"로 표시한 후 프로세스 id를 부여한다.
2)래치활동통계
- v$latch뷰의 주요 통계 (가장 기본적인 래치통계뷰, 자세한내용은 v$latch_parent,v$latch_clidren)
표4-2. 래치와 관련된 동적 성능 뷰의 주요 통계지표
지표 | 설명 |
---|
gets | 프로세스가 willing-to-wait모드로 래치를 획득하려고 시도한 횟수. 이통계는 래치를 획득한 후에만 증가한다. |
misses | 프로세스가 willing-to-wait모드로 래치를 획득하려고 시도한후 첫번째"test and set"/"compare and swap"연산을 실패한 횟수. |
spin_gets | 프로세스가 willing-to-wait모드의 첫번째"test and set"/"compare and swap"연산에서 miss 되었지만, 첫번째 루프 내에서 래치를 획득한 횟수. |
sleeps | 프로세스가 willing-to-wait모드로 래치를 획득하려고 시도한 후 spin 후에도 래치 획득을 실패한 횟수. |
sleep1... sleep11 | 프로세스가 willing-to-wait모드로 래치를 획득하려고 시도한 후 sleep한 횟수. |
immediate_gets | 세션이 immediate모드로 래치를 획득하려고 시도한 후, 첫 번째 "test and set"/"compare and swap"콜에서 래치를 획득한 횟수. |
imediate_misses | 세션이 immediate 모드로 래치를 획득하려고 시도한 후, 첫번째 "test and set"/"compare and swap"콜에서 래치 획득을 실패한 횟수. |
wait_time | 세션이 래치를 대기한 시간 |
3)래치실패
- 첫번째 루프 수행 후에도 래치를 획득하지 못하면, 래치의 유형에 따라 두 가지 방식으로 래치 획득을 시도한다.
1. 스핀(spin)
2. 포스팅(posting): latch wait list를 이용
- 스핀방식 : 오라클의 초기버전에서 많이사용
세션은 짧은 간격 후에 스스로를 깨우도록 알람을 설정하고, 스스로를 운영체제의 런-큐에서 제거한다.
운영체제의 스케줄러에 의해 다시 런-큐에 등록뒬 대는 큐의 상단에 위치하게 되고, 래치를 획득하기 위해 루프를 수행한다.
만일 또 다시 래치 획득을 실패하면, 다시 슬립 상태로 빠지게 된다.
슬립시간은 exponential backoff 알고리즘(세션이 슬립을 하면 할수록,슬립시간이 길어진다는의미)을 사용하며,
이로인해 프로세스가 래치를 획득하기 위해 매우 긴 시간을 대기 할 수도 있다.
- 포스팅방식 : 최근 오라클 버전에서 많이 사용
필요한 래치를 획득하지 못한 프로세스는 스스로를 latch wait list에 등록한 후 (다른프로세스에 의해) 깨워질떄까지 슬립한다.
슬립하기 전에 해당 세션이 수행한 일은, 래치를 획득하려는 모드와 해당 시점의 래치의 상황에 따라 다양한 변형이 존재한다.
표 4-3 다양한 상황에 따른 다양한 래치 획득 방법
획득하려는 래치 모드 및 래치의 상황 | 래치를 획득하기 위해 사용된 방법 |
---|
exclusive 래치 획득 | Immediate get을 시도하고, spin을 시작하고(프로세스는 20,000번 spin을 수행한다), wait list에 등록하고, immediate get을 시도하고, sleep한다. |
다른 프로세스가(shared,exclusive 또는 blocking 모드로) 소유한 shareable 래치를 exclusive모드로 획득 | spin을 시작하고(프로세스는 2000번 spin을 수행한다), wait list에 등록하고,spin을 반복하고, 만일 성공하지 못하면 sleep한다. |
다른프로세스가(exclusive또는 blocking모드로) 소유한 sharedable 래치를 shared모드로 획득 | spin을 수행하지 않고, 바로wait list에 등록한다. |
다른 프로세스가(shared모드로)소유한 shareable 래치를 shared모드로 획득 | sleep전에 cpu_count +2번 spin을 수행한다. |
# latch wait list에 등록된 프로세스가 존재하는 시점에, 다수의 프로세스들이 해당 래치를 획득하려고 시도하는 경우
1. 세션1이 exclusive 래치를 획득
2. 세션2가 exclusive 래치를 획득하려고 시도한 후 sleep
3. 세션1이 래치를 릴리즈하고 세션2를 포스트한다.
4. 세션2가 시작하기 전에 세션3이 래치를 획득한다.
5. 세션2는 깨어나고, spin을 수행하고, 다시 sleep해야만한다.
※ 래치와 관련된 모든 작업은 세션이 아닌 프로세스에 의해 수행된다.
이것은 x$ksuprlat 구조에 기반을둔 v$latchholder 성능뷰에서 확인이 가능하다.
# sharable 래치를 획득할 때의 문제점
- 다른프로세스에 의해 sharable 래치가 exclusive모드로 획득된 상태라고 가정
- 해당 래치를 shared모드로 획득하려는 프로세스는 즉시 큐의 맨 뒤에 등록,
- 해당 래치를 exclusive모드로 획득하려는 프로세스는 2000번의 스핀 후에 큐의 맨 뒤에 등록(표 4-3참조)
- 해당 래치가 release될 때 큐 내의 위치한 대부분의 프로세스들이 shared모드로 해당 래치를 대기했다면, 큐의 길이는 빠르게 줄어든다.
- 해당 래치를 exclusive 모드로 대기하는 프로세스가 큐 내에 등록된다면, shared모드로 해당 래치를 획득하려는 프로세스들에 의해큐의 길이가 길어지게 된다.
- 이같은 경우가 반복된다면, 비교적 적은 수의 exclusive모드 대기프로세스들로인해 큐의 길이는 매우 길어지며, 결과적으로 대기시간이 증가하게 된다.
# 문제점 제한 방법
- 설계자/개발자/코더로써, 대량의 래치 활동성을 유발하지 마라(하나의 job을 매우많은 수의 작은단계로 분리하지 마라)
- DBA로써, 래치의 수를 증가시킬 필요가 있는지 확인하라. 데이터 내의 핫-스팟을 식별한 후 해당 데이터를 더 많은 블록을 분산시킬 방법을 찾아봐라.
- 최신패치를 눈여겨봐라
- 오라클사의 설계자/개발자로써, 래치 활동에 대한 의존을 줄일 수 있는 메커니즘을 생성하라(이를 위해 pin과 mutex가 개발되었다.)
※ 이 장에서 설명한 것은 주로 오라클 10g까지의 방법, 11g의 내용은 7장에서..
- 라이브러리 캐시의 중요성을 나타내기위해 그림 4-1을 확장 한 것
{panel:title=그림 4-3 Library cache 래치를 포함한, 매우 작은 라이브러리 캐시의 구조
| borderStyle=dashed | bgColor=#FFFFFF | titleBGColor=#F0F0F0}!5.jpg | vspace=4!{panel} 라이브러리 캐시에 적재되어있는 해시버킷에 속해있는 오브젝트들이 적절한 리스트 내에 연결되어있다. |
4)래치확장성
- 사용자가 SQL문을 실행하면, 서버프로세스는 라이브러리 캐시 내에서 해당 SQL문을 찾는 작업을 수행한다.
- 이것은 SQL문에 해시함수를 적용하여 버킷번호를 확인 한 후, 버킷에 연결된 링크드리스트(해시체인)을 검색한다는 의미
- 그리고 해시버킷을 보호하는 래치를 확인하는 작업이 필요하다.
- 즉, 래치를 획득하고, 링크드리스트를 검색하고, 만일 SQL문을 찾는다면, 필요한 일을 수행한 후에 래치를 릴리즈하는 순서로 동작한다.
# 래치 경합과 관련해서 고래해야 할 사항
- 얼마나 많은 래치들이 라이브러리 캐시를 보호 할 것인가?
- 얼마나 자주 래치를 획득하기 위한 절차를 수행할 것인가?
- 얼마나 길게 래치를 소유할 것인가?
표 4-4. 오라클 버전에 따른 라이브러리 캐시와 연관된 래치 목록
래치명 | 8.1.7.4 | 9.2.0.8 | 10.2.0.5 | 11.2.0.2 |
---|
Library cache load lock | X | X | X | X |
Library cache | X | X | X | |
Library cache pin | | X | X | |
Library cache pin allocation | | X | X | |
Library cache lock | | | X | |
Library cache lock allocation | | | X | |
Library cache hash chain | | | X | |
※ 11g에선 거의다 사라짐
MUTEX, PART1
- 뮤텍스의 동작 방식은 래치와 매우 유사
- 뮤텍스는 라이브러리 캐시 오브젝트를 위한 "private mini-latch"이다.
- 모든 개별 라이브러리 캐시 해시 버킷마다 개별적인 뮤텍스를 할당하고, 모든 부모 및 자식 커서에 두개의 뮤텍스
(하나는 KGL pin을 대신하고,다른하나는 dependencies를 다루기위한 것)를 사용함으로써, 빈번하게 사용되는
명령어의 확장성을 향상시킨다는 것을 의미 - 뮤텍스의 단점은 뮤텍스에 대한 문제가 발생했을 때 분석을 위한 정보가 매우 부족하다.
뮤텍스 수행을 위한 코드는 매우 짧고, 매우 적은 정보만을 제공한다.