래치

  • 다수의 프로세스가 동시에 공유 메모리를 수정할 때 발생할 수 있는 문제를 제거하기 위해 래치를 사용
# 래치의 유형
  • 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=dashedbgColor=#FFFFFFtitleBGColor=#F0F0F0}!5.jpgvspace=4!{panel}
라이브러리 캐시에 적재되어있는 해시버킷에 속해있는 오브젝트들이 적절한 리스트 내에 연결되어있다.

4)래치확장성

  • 사용자가 SQL문을 실행하면, 서버프로세스는 라이브러리 캐시 내에서 해당 SQL문을 찾는 작업을 수행한다.
  • 이것은 SQL문에 해시함수를 적용하여 버킷번호를 확인 한 후, 버킷에 연결된 링크드리스트(해시체인)을 검색한다는 의미
  • 그리고 해시버킷을 보호하는 래치를 확인하는 작업이 필요하다.
  • 즉, 래치를 획득하고, 링크드리스트를 검색하고, 만일 SQL문을 찾는다면, 필요한 일을 수행한 후에 래치를 릴리즈하는 순서로 동작한다.
# 래치 경합과 관련해서 고래해야 할 사항
  • 얼마나 많은 래치들이 라이브러리 캐시를 보호 할 것인가?
  • 얼마나 자주 래치를 획득하기 위한 절차를 수행할 것인가?
  • 얼마나 길게 래치를 소유할 것인가?
표 4-4. 오라클 버전에 따른 라이브러리 캐시와 연관된 래치 목록
래치명8.1.7.49.2.0.810.2.0.511.2.0.2
Library cache load lockXXXX
Library cacheXXX
Library cache pinXX
Library cache pin allocationXX
Library cache lockX
Library cache lock allocationX
Library cache hash chainX

※ 11g에선 거의다 사라짐

MUTEX, PART1

  • 뮤텍스의 동작 방식은 래치와 매우 유사
  • 뮤텍스는 라이브러리 캐시 오브젝트를 위한 "private mini-latch"이다.
  • 모든 개별 라이브러리 캐시 해시 버킷마다 개별적인 뮤텍스를 할당하고, 모든 부모 및 자식 커서에 두개의 뮤텍스
    (하나는 KGL pin을 대신하고,다른하나는 dependencies를 다루기위한 것)를 사용함으로써, 빈번하게 사용되는
    명령어의 확장성을 향상시킨다는 것을 의미
  • 뮤텍스의 단점은 뮤텍스에 대한 문제가 발생했을 때 분석을 위한 정보가 매우 부족하다.
    뮤텍스 수행을 위한 코드는 매우 짧고, 매우 적은 정보만을 제공한다.