2. 리두와 언두

  • 기본적인 데이터 변경
  • 트랜젝션 요구사항(ACID)
  • 리두 단순성
  • 언두 복잡성
  • 요약

2. 리두와 언두

복구와 읽기 일관성에 대한 거의 모든 것에 대한 대답 :

필자는 오라클의 가장 중요한 기술요소로 체인지 백터(Change vector)를 꼽는다.
체인지 백터는 리두와 언두의 핵심이며, 데이터 블록에 대한 변경을 설명하기 위한 메커니즘이다.
또한 사용자의 데이터를 안전하게 유지하고, 읽기와 쓰기간의 경합을 최소화하고, 인스턴스 복구, 미디어복구, 모든 Standby 아키텍쳐, flashback 메커니즘, change data capture(CDC) 및 스트림을 위한 기술요소로 가장 먼저 다루어야 할 기술요소이다.

A. 기본적인 데이터 변경

오라클 데이터베이스의 특징 중 하나는 데이터를 두번 기록한다는 것이다.
데이터의 한본은 데이터파일 내에 존재한다.
데이터의 또다른 한본은 리두로그파일에 존재한다.

접근방식

실재로는 위의 접근방식이 아니라 다음과 같이 동작한다.

변경 전 후 의 데이터블록 덤프
변경 전변경 후
{code}tab 0, row 4, @0x1d3f
tl: 117 fb: --H-FL-- lb: 0x0 cc: 4
col 0: 2 c1 0a
col 1: 2 c1 06
col 2: 6 78 78 78 78 78 78
col 3: 100
30 30 30 30 30 30 30 30 30 30 30 ...
{code}
{code}tab 0, row 4, @0x2a7
tl: 121 fb: --H-FL-- lb: 0x2 cc: 4
col 0: 2 c1 0a
col 1: 2 c1 06
col 2: 10 59 59 59 59 59 59 59 59 59 59
col 3: 100
30 30 30 30 30 30 30 30 30 30 30 ...
{code}

세번 째 컬럼의 사이즈가 증가하여 블록의 프리블록으로 해당 로우의 위치가 이동함
ITL의 두번째 슬롯을 사용함

언두 블록 덤프를 통해 언두레코드를 확인

*-----------------------------
* Rec #0xf  slt: 0x1a  objn: 45810(0x0000b2f2)  objd: 45810  tblspc: 12(0x0000000c)
*       Layer:  11 (Row)   opc: 1   rci 0x0e   
Undo type:  Regular undo   Last buffer split:  No 
Temp Object:  No 
Tablespace Undo:  No 
rdba: 0x00000000
*-----------------------------
KDO undo record:
KTB Redo 
op: 0x02  ver: 0x01  
op: C  uba: 0x0080009a.09d4.0d
KDO Op code: URP row dependencies Disabled
  xtype: XA  bdba: 0x02c0018a  hdba: 0x02c00189
itli: 2  ispac: 0  maxfr: 4863
tabn: 0 slot: 4(0x4) flag: 0x2c lock: 0 ckix: 16
ncol: 4 nnew: 1 size: -4
col  2: [ 6]  78 78 78 78 78 78

언두 블록 내의 언두 레코드에 변경 이전의 데이터가 기록된다.

리두로그 덤프 내의 체인지 백터 확인.

REDO RECORD - Thread:1 RBA: 0x00036f.00000005.008c LEN: 0x00f8 VLD: 0x01
SCN: 0x0000.03ee485a SUBSCN:  1 03/13/2011 17:43:01
CHANGE #1 TYP:0 CLS:36 AFN:2 DBA:0x0080009a SCN:0x0000.03ee485a SEQ:  4 OP:5.1
ktudb redo: siz: 92 spc: 6786 flg: 0x0022 seq: 0x09d4 rec: 0x0f
            xid:  0x000a.01a.0000255b  
ktubu redo: slt: 26 rci: 14 opc: 11.1 objn: 45810 objd: 45810 tsn: 12
Undo type:  Regular undo       Undo type:  Last buffer split:  No 
Tablespace Undo:  No 
             0x00000000
KDO undo record:
KTB Redo 
op: 0x02  ver: 0x01  
op: C  uba: 0x0080009a.09d4.0d
KDO Op code: URP row dependencies Disabled
  xtype: XA  bdba: 0x02c0018a  hdba: 0x02c00189
itli: 2  ispac: 0  maxfr: 4863
tabn: 0 slot: 4(0x4) flag: 0x2c lock: 0 ckix: 16
ncol: 4 nnew: 1 size: -4
col  2: [ 6]  78 78 78 78 78 78

CHANGE #2 TYP:0 CLS: 1 AFN:11 DBA:0x02c0018a SCN:0x0000.03ee485a SEQ:  2 OP:11.5
KTB Redo 
op: 0x02  ver: 0x01  
op: C  uba: 0x0080009a.09d4.0f
KDO Op code: URP row dependencies Disabled
  xtype: XA  bdba: 0x02c0018a  hdba: 0x02c00189
itli: 2  ispac: 0  maxfr: 4863
tabn: 0 slot: 4(0x4) flag: 0x2c lock: 2 ckix: 16
ncol: 4 nnew: 1 size: 4
col  2: [10]  59 59 59 59 59 59 59 59 59 59

데이터에 대한 변경 사항(change vector)과 언두에 대한 변경사항(change vector)이 쌍(pair)을 이루어 리두 레코드로 기록된 것이 확인됨

디브리핑

B. 트랜잭션 요구사항(ACID)

언두와 리두를 위한 메커니즘은 ACID의 기본적인 요구사항을 구현하는데 충분할 뿐 아니라 성능과 복구 측면에서도 장점을 제공한다.

C. 리두 단순성

연속된 리두가 온라인 리두로구 파일에 기록되면, 일반적인 상황에서는 인스턴스에 의해서 다시 읽혀지지 않으므로 한 번 기록된 내용에 대해서 신경 쓸 필요가 없다. (Write and forget)

Point

오라클은 하나의 Redo allocation 래치를 exclusive모드로 획득하여야 로그 버퍼에 기록할 수있게 된다. 이는 다수의 프로세스가 로그버퍼 내의 동일한 공간에 동시에 기록하는 문제를 방지해 주지만 경합에 의한 리소스 소비와 대기 시간 증가를 일으킬 수 있다.
그러므로 리두를 가능한 빨리 온라인 리두로그로 저장하는 메커니즘이 필요.
10g에서는 private redo와 in-memory undo를 결합한 새로운 매커니즘이 소개됨.

새로운 메모리 구조
private redo strand (x$kcrfstrand 구조)in-memory undo pool (x$ktifp 구조)
x$kcrfstrand구조내에는 private redo뿐만아니라 public 로그버퍼를 포함한다.
Public로그버퍼의 개수는 cpu_count파라미터에 의해 결정된다. (추정 ceil(1+cpu_count)
X$kcrfstrand구조내의 각 항목은 각각의 redo allocation래치에 의해 관리되며
각 public 로그 버퍼는 cpu 당 하나의 redo copy래치에 의해 추가적으로 관리된다.
_log_parallelism_dynamic = true
_log_private_parallelism=true
pool개수가 transactions파라미터에 의해 결정된다.( default transactions/10)
각 pool은 in memory undo latch에 의해 관리된다.
_in_memory_undo=true
_imu_pools

<public redo/private redo 버퍼의 크기>

<9i vs 10g 수행비교>

10g의 새로운 리두 로그 메커니즘

1. 트랜잭션이 수행하는 동안 생성된 체인지 백터를 Private리두로그버퍼에 저장하고,
2. 트랜잭션이 완료되면, 해당 프로세스는 private리두로그버퍼를 public리두로그버퍼에 복사
3. 이후 기존의 로그버퍼 처리방식으로 수행되며, 트랜잭션 시 최소 1번의 public redo allocation 래치를 획득하게 된다는 것을 의미

동작방식

새로운 메커니즘으로 인한 이득
  • 두 개의 래치(redo copy, redo allocation) 대신 하나의 래치(in memory undo)만을 획득하므로 래치 활동성은 절반으로 감소
  • in memory undo pool당 별도의 in memory undo래치를 할당하므로 액세스를 분산하여 경합완화
  • 결국 두 종류의 로그 버퍼를 사용하여 실제 커밋 시와 커밋 이전의 래치를 분산하여 public 리두버퍼의 활동량은 감소하고 private리두버퍼의 액세스는 분산하는 점이 이득이다.
새로운 메커니즘이 제약되는 상황
  • private로그 버퍼 및 in-memory undo pool이 꽉 찾을 경우 싱글리두레코드를 생성하여이전의 리두버퍼사용방식을 따른다
  • 다음과 같은 경우

SQL> select ktiffcat, ktiffflc from x$ktiff;

KTIFFCAT                                     KTIFFFLC  
-------------------------------------------- --------- 
Undo pool overflow flushes                           1
Stack cv flushes                                    49
Multi-block undo flushes                             0
Max. chgs flushes                                   26
NTP flushes                                          0
Contention flushes                                   4
Redo pool overflow flushes                          16
Logfile space flushes                                0
Multiple persistent buffer flushes                   0
Bind time flushes                                    0
Rollback flushes                                  4569
Commit flushes                                    8850
Recursive txn flushes                               10
Redo only CR flushes                                 1
Ditributed txn flushes                               0
Set txn use rbs flushes                              0
Bitmap state change flushes                        143
Presumed commit violation                            0
Securefile direct-write lob update flushes           0

19 rows selected.

D. 언두 복잡성

모든 프로세스는 커밋 전 데이터를 확인하기 위하여 언제든지 언두 레코드를 액세스 할 수 있어야 한다

언두 레코드의 용도

  • 일기 일관성
  • 롤백
  • delayed block cleanout으로 읽어버린 commit SCN을 유추하기 위해 필요

읽기 일관성을 위해서 데이터블록의 복사본을 생성한 후 해당 복사본에 언두 레코드를 적용한다.



*-----------------------------
* Rec #0xf  slt: 0x1a  objn: 45810(0x0000b2f2)  objd: 45810  tblspc: 12(0x0000000c)
*       Layer:  11 (Row)   opc: 1   rci 0x0e   
Undo type:  Regular undo   Last buffer split:  No 
Temp Object:  No 
Tablespace Undo:  No 
rdba: 0x00000000
*-----------------------------
KDO undo record:
KTB Redo 
op: 0x02  ver: 0x01  
op: C  uba: 0x0080009a.09d4.0d
KDO Op code: URP row dependencies Disabled
  xtype: XA  bdba: 0x02c0018a  hdba: 0x02c00189
itli: 2  ispac: 0  maxfr: 4863
tabn: 0 slot: 4(0x4) flag: 0x2c lock: 0 ckix: 16
ncol: 4 nnew: 1 size: -4
col  2: [ 6]  78 78 78 78 78 78

Op : C는 동일 트랜젝션에 의해 이전에 변경된 것이 있다는 것을 의미한다.
rci 0x0e : 이전 언두 레코드 번호를 가르킨다.

롤백

언두의 중요한 용도는 변경에 대한 롤백이다.
록백 시에는 current블록을 확득한 후 current블록에 언두 레코드를 적용한다.
롤백은 트랜잭션의 이력에 대한 것으로 역순으로 트랜잭션에 대한 모든 언두 레코드를 검색할 필요가 있다.
이 때 이전 언두 레코드를 찾을 수 있는 Linked list 항목은 rci이며, 이전 언두레코드가 다른 블록에 있다면 rci 0x0, rdba: 언두블록주소로 표기된다.

롤백이 읽기 일관성과 차이나는 측면 :

  • 해당 데이터블록은 current 블록이므로 반드시 디스크로 기록되는 블록의 버전이다.
  • Current블록이기 때문에 해당 블록을 변경할 때 리두가 생성된다.
  • 롤백에 사용되었다면 'undo applied'라고 표시되어야 하므로 약간의 리두가 더 생성된다.

롤백 시 추가적인 오버헤드 :

  • 대량 변경의 long-running 트랜잭션 시 변경된 블록이 디스크에 기록될 수 있으며 롤백을 위해 다시 버퍼캐시에 올리기 위해 Disk I/O가 발생할 수 있다.
  • 개별 언두 레코드를 Currnet블록에 적용시키기 위해 current블록에 대한 더 많은 액세스가 발생한다.
  • 언두 레코드를 획득할 때 마다 적용횔 데이터블록이 저장된 테이블스페이스가 온라인상태인지 체크하기 위해 Dictiionary cache를 획득해야한다.

E. 요약

  • 리두는 데이터 블록의 모든 변경에 대해 redo change vector를 생성하며 로그버퍼에 기록되고 최종적으로는 리두로그 파일에 기록된다.
  • 데이터(블록 및 메타데이터)에 대한 변경을 수행하면, 이를 원복하는 언두레코드를 생성하여 언두블록에 저장한다. 언두블록도 데이터블록이므로 이 변경사항에 대해 redo change vector를 생성한다.
  • 10g 전에는 데이터변경과 언두변경에 대한 redo change vector 한쌍으로 된 리두레코드를 기록하였지만 로그버퍼를 할당하는 부분이 중요한 병목지점으로 대두되며 private redo 및 in-memory undo 매커니즘이 추가 되어 public 리두버퍼의 활동량은 감소하고 private리두의 액세스는 분산할 수 있게 되었다
  • 언두 블록은 데이터베이스 운영 중 자주 다시 읽혀질 수 있으므로, 언두 레코드에 대한 효율적인 액세스를 위해 다양한 방법의 linked list가 제공된다.