Latch: redo writing

EXEM Knowledge Base

Jump to: navigation, 찾기

목차

[편집] Basic Info

리두 버퍼내의 공간을 확보하기 위해 LGWR에게 쓰기 요청을 하려는 프로세스는 redo writing 래치를 획득해야 한다. LGWR에 의한 쓰기 작업은 동시에 수행될 수 없으므로, 자연스럽게 이 래치는 전체 인스턴스에 하나만 존재한다. redo writing 래치는 독립 래치(solitary latch)이기 때문에 V$LATCH_PARENT 뷰를 통해서 활동성을 관찰할 수 있다.

SQL> select name, gets, misses, immediate_gets, immediate_misses,
   wait_time
from v$latch_parent
where name = 'redo writing';

NAME             GETS     MISSES IMMEDIATE_GETS IMMEDIATE_MISSES  WAIT_TIME
---------- ---------- ---------- -------------- ---------------- --------
redo writing    829715         20              0                0          0

redo writing 래치는 Willing-to-wait 모드로 획득된다. redo writing 래치를 획득하는 과정에서 경합이 발생하면 latch: redo writing 이벤트를 대기하게 된다.

[편집] Parameter & Wait Time

[편집] Wait Parameters

latch free 이벤트와 동일하다.

[편집] Wait Time

latch free 이벤트와 동일하다.

[편집] Check Point & Solution

[편집] Redo 관련 경합

일반적인 환경에서는 리두 관련 래치 경합은 잘 발생하지 않는다. 만일 시스템 전체 대기이벤트 목록중 리두 래치 관련 대기가 상위를 차지한다면 이는 리두와 관련해 극심한 경합이 발생하는 것으로 해석할 수 있다. 메타링크 문서번호 14747.1에 의하면 misses / gets가 1% 이상이거나 immediate_misses / ( immediate_gets + immediate_misses)가 1% 이상이면 리두 래치를 획득하는 과정에서 경합이 발생한 것으로 간주된다. 하지만, 회수보다는 래치 경합에 따른 대기시간을 경합의 발생 증거로 활용하는 것이 바람직하다고 생각된다.

리두 버퍼의 크기가 리두 래치 경합을 일으키는 요인이 될 수 있다. 리두 버퍼의 크기가 지나치게 작은 경우 LGWR의 백그라운드 기록(Background write)작업이 빈번하게 발생하게 된다. 특히 긴 시간동안 많은 리두 데이터를 생성하는 트랜잭션이 많은 경우에는 LGWR이 매우 빈번하게 백그라운드 기록을 수행해야한다. LGWR은 기록 작업을 수행하기 위해 리두 관련 래치들을 획득해야 하기 때문에 이로 인해 래치 경합이 증가할 수 있다. 따라서 리두 래치 경합이 자주 발생하는 경우 리두 버퍼 크기가 너무 작지 않은지 검증할 필요가 있다.

시스템 전체적으로 불필요하게 많은 리두 데이터가 생성된다면 Nologging 기능을 활용함으로써 리두 데이터를 줄이는 것도 래치 경합을 줄이는 방법이 될 수 있다. 하지만, Nologging 작업은 기본적으로 복구가 되지 않는다는 점을 유의해야 한다.

다행히 리두와 관련된 대부분의 성능문제가 래치 경합보다는 어플리케이션의 작동 방식이나 I/O 성능과 관련이 있다. "다행히"라는 표현을 쓴 이유는 리두 래치에서 발생하는 경합에 대해서는 뚜렷한 해결책이 없는 경우가 많기 때문이다. 오라클 9i, 10g로 올라가면서 리두 버퍼와 관련된 오라클 내부 알고리즘이 크게 개선되었기 때문에 대부분의 경우 래치 경합은 더 이상 문제가 되지 않을 것으로 보인다.

실제로, 많은 리두 데이터가 생성될 때 리두 래치에서의 경합이 얼마나 발생하는지 시뮬레이션 해보자. 테스트 시나리오는 다음과 같다.

동시에 30개의 세션에서 DML을 수행하면서 많은 리두 데이터를 생성한다.

이 과정에서 리두 래치에서의 경합이 발생하는지 확인한다.

SQL> ed redo_test.sql
-- 아래와 같이 수백 번의 update와 commit을 수행하면서 리두 영역의 부하를 증가시키는 SQL 문을 만든다.
update redo_test set id = id, name = name where id = &1;
commit;
update redo_test set id = id, name = name where id = &1;
commit;
update redo_test set id = id, name = name where id = &1;
....

SQL> ed redo_test.bat
-- 아래와 같이 동시에 30개의 세션에서 redo_test.sql을 수행시킨다.
start sqlplus maxgauge/maxgauge@ora10gr2 @redo_test 1
start sqlplus maxgauge/maxgauge@ora10gr2 @redo_test 2
...
start sqlplus maxgauge/maxgauge@ora10gr2 @redo_test 30

cmd> redo_test.bat

위의 스크립트를 수행시킨 후 세션들의 대기현황을 캡쳐해보면 다음과 같은 결과를 얻을 수 있다.

SQL> select event, total_waits, time_waited
from v$session_event
where sid = (select sid from v$mystat where rownum = 1)
order by 3 desc;

EVENT                          TOTAL_WAITS TIME_WAITED
------------------------------ ----------- -----------
SQL*Net message from client            515        5458
buffer busy waits                              106         503
log file sync                                     129         231
latch: cache buffers chains                  86          84
latch: In memory undo latch               27          17
events in waitclass Other                    18          15
latch: library cache                            22          14
SQL*Net message to client                516           3
latch: redo copy                                             2               3
latch: library cache pin                         4           1
SQL*Net break/reset to client               2           0
cursor: mutex S                               193           0

log file sync 대기와 함께 latch: redo copy 대기가 목격된다. 하지만 전체 대기에서 차지하는 비중은 낮은 것을 확인할 수 있다.

[편집] Event Tip

[편집] Analysis Case