原創(chuàng)|其它|編輯:郝浩|2009-12-24 11:47:35.000|閱讀 449 次
概述:Redo log 是用于恢復(fù)和一個高級特性的重要數(shù)據(jù),一個redo條目包含了相應(yīng)操作導(dǎo)致的數(shù)據(jù)庫變化的所有信息,所有redo條目最終都要被寫入redo文件中去。Redo log buffer是為了避免Redo文件IO導(dǎo)致性能瓶頸而在sga中分配出的一塊內(nèi)存。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
Redo log 是用于恢復(fù)和一個高級特性的重要數(shù)據(jù),一個redo條目包含了相應(yīng)操作導(dǎo)致的數(shù)據(jù)庫變化的所有信息,所有redo條目最終都要被寫入redo文件中去。Redo log buffer是為了避免Redo文件IO導(dǎo)致性能瓶頸而在sga中分配出的一塊內(nèi)存。一個redo條目首先在用戶內(nèi)存(PGA)中產(chǎn)生,然后由oracle服務(wù)進(jìn)程拷貝到log buffer中,當(dāng)滿足一定條件時,再由LGWR進(jìn)程寫入redo文件。由于log buffer是一塊“共享”內(nèi)存,為了避免沖突,它是受到redo allocation latch保護(hù)的,每個服務(wù)進(jìn)程需要先獲取到該latch才能分配redo buffer。因此在高并發(fā)且數(shù)據(jù)修改頻繁的oltp系統(tǒng)中,我們通常可以觀察到redo allocation latch的等待。Redo寫入redo buffer的整個過程如下:
在PGA中生產(chǎn)Redo Enrey -> 服務(wù)進(jìn)程獲取Redo Copy latch(存在多個---CPU_COUNT*2) -> 服務(wù)進(jìn)程獲取redo allocation latch(僅1個) -> 分配log buffer -> 釋放redo allocation latch -> 將Redo Entry寫入Log Buffer -> 釋放Redo Copy latch;
shared strand
為了減少redo allocation latch等待,在oracle 9.2中,引入了log buffer的并行機(jī)制。其基本原理就是,將log buffer劃分為多個小的buffer,這些小的buffer被成為strand(為了和之后出現(xiàn)的private strand區(qū)別,它們被稱之為shared strand)。每一個strand受到一個單獨redo allocation latch的保護(hù)。多個shared strand的出現(xiàn),使原來序列化的redo buffer分配變成了并行的過程,從而減少了redo allocation latch等待。
shared strand的初始數(shù)據(jù)量是由參數(shù)log_parallelism控制的;在10g中,該參數(shù)成為隱含參數(shù),并新增參數(shù)_log_parallelism_max控制shared strand的最大數(shù)量;_log_parallelism_dynamic則控制是否允許shared strand數(shù)量在_log_parallelism和_log_parallelism_max之間動態(tài)變化。
HELLODBA.COM>select nam.ksppinm, val.KSPPSTVL, nam.ksppdesc
2 from sys.x$ksppi nam,
3 sys.x$ksppsv val
4 where nam.indx = val.indx
5 --AND nam.ksppinm LIKE '_%'
6 AND upper(nam.ksppinm) LIKE '%LOG_PARALLE%';
KSPPINM KSPPSTVL KSPPDESC
-------------------------- ---------- ------------------------------------------
_log_parallelism 1 Number of log buffer strands
_log_parallelism_max 2 Maximum number of log buffer strands
_log_parallelism_dynamic TRUE Enable dynamic strands
每一個shared strand的大小 = log_buffer/(shared strand數(shù)量)。strand信息可以由表x$kcrfstrand查到(包含shared strand和后面介紹的private strand,10g以后存在)。
HELLODBA.COM>select indx,strand_size_kcrfa from x$kcrfstrand where last_buf_kcrfa != '00';
INDX STRAND_SIZE_KCRFA
---------- -----------------
0 3514368
1 3514368
HELLODBA.COM>show parameter log_buffer
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
log_buffer integer 7028736
關(guān)于shared strand的數(shù)量設(shè)置,16個cpu之內(nèi)最大默認(rèn)為2,當(dāng)系統(tǒng)中存在redo allocation latch等待時,每增加16個cpu可以考慮增加1個strand,最大不應(yīng)該超過8。并且_log_parallelism_max不允許大于cpu_count。
注意:在11g中,參數(shù)_log_parallelism被取消,shared strand數(shù)量由_log_parallelism_max、_log_parallelism_dynamic和cpu_count控制。
Private strand
為了進(jìn)一步降低redo buffer沖突,在10g中引入了新的strand機(jī)制——Private strand。Private strand不是從log buffer中劃分的,而是在shared pool中分配的一塊內(nèi)存空間。
HELLODBA.COM>select * from V$sgastat where name like '%strand%';
POOL NAME BYTES
------------ -------------------------- ----------
shared pool private strands 2684928
HELLODBA.COM>select indx,strand_size_kcrfa from x$kcrfstrand where last_buf_kcrfa = '00';
INDX STRAND_SIZE_KCRFA
---------- -----------------
2 66560
3 66560
4 66560
5 66560
6 66560
7 66560
8 66560
...
Private strand的引入為Oracle的Redo/Undo機(jī)制帶來很大的變化。每一個Private strand受到一個單獨的redo allocation latch保護(hù),每個Private strand作為“私有的”strand只會服務(wù)于一個活動事務(wù)。獲取到了Private strand的用戶事務(wù)不是在PGA中而是在Private strand生成Redo,當(dāng)flush private strand或者commit時,Private strand被批量寫入log文件中。如果新事務(wù)申請不到Private strand的redo allocation latch,則會繼續(xù)遵循舊的redo buffer機(jī)制,申請寫入shared strand中。事務(wù)是否使用Private strand,可以由x$ktcxb的字段ktcxbflg的新增的第13位鑒定:
HELLODBA.COM>select decode(bitand(ktcxbflg, 4096),0,1,0) used_private_strand, count(*)
2 from x$ktcxb
3 where bitand(ksspaflg, 1) != 0
4 and bitand(ktcxbflg, 2) != 0
5 group by bitand(ktcxbflg, 4096);
USED_PRIVATE_STRAND COUNT(*)
------------------- ----------
1 10
0 1
對于使用Private strand的事務(wù),無需先申請Redo Copy Latch,也無需申請Shared Strand的redo allocation latch,而是flush或commit是批量寫入磁盤,因此減少了Redo Copy Latch和redo allocation latch申請/釋放次數(shù)、也減少了這些latch的等待,從而降低了CPU的負(fù)荷。過程如下:
事務(wù)開始 -> 申請Private strand的redo allocation latch (申請失敗則申請Shared Strand的redo allocation latch) -> 在Private strand中生產(chǎn)Redo Enrey -> Flush/Commit -> 申請Redo Copy Latch -> 服務(wù)進(jìn)程將Redo Entry批量寫入Log File -> 釋放Redo Copy Latch -> 釋放Private strand的redo allocation latch
注意:對于未能獲取到Private strand的redo allocation latch的事務(wù),在事務(wù)結(jié)束前,即使已經(jīng)有其它事務(wù)釋放了Private strand,也不會再申請Private strand了。
每個Private strand的大小為65K。10g中,shared pool中的Private strands的大小就是活躍會話數(shù)乘以65K,而11g中,在shared pool中需要為每個Private strand額外分配4k的管理空間,即:數(shù)量*69k。
--10g:
SQL> select * from V$sgastat where name like '%strand%';
POOL NAME BYTES
------------ -------------------------- ----------
shared pool private strands 1198080
HELLODBA.COM>select trunc(value * KSPPSTVL / 100) * 65 * 1024
2 from (select value from v$parameter where name = 'transactions') a,
3 (select val.KSPPSTVL
4 from sys.x$ksppi nam, sys.x$ksppsv val
5 where nam.indx = val.indx
6 AND nam.ksppinm = '_log_private_parallelism_mul') b;
TRUNC(VALUE*KSPPSTVL/100)*65*1024
-------------------------------------
1198080
--11g:
HELLODBA.COM>select * from V$sgastat where name like '%strand%';
POOL NAME BYTES
------------ -------------------------- ----------
shared pool private strands 706560
HELLODBA.COM>select trunc(value * KSPPSTVL / 100) * (65 + 4) * 1024
2 from (select value from v$parameter where name = 'transactions') a,
3 (select val.KSPPSTVL
4 from sys.x$ksppi nam, sys.x$ksppsv val
5 where nam.indx = val.indx
6 AND nam.ksppinm = '_log_private_parallelism_mul') b;
TRUNC(VALUE*KSPPSTVL/100)*(65+4)*1024
-------------------------------------
706560
Private strand的數(shù)量受到2個方面的影響:logfile的大小和活躍事務(wù)數(shù)量。
參數(shù)_log_private_mul指定了使用多少logfile空間預(yù)分配給Private strand,默認(rèn)為5。我們可以根據(jù)當(dāng)前l(fā)ogfile的大小(要除去預(yù)分配給log buffer的空間)計算出這一約束條件下能夠預(yù)分配多少個Private strand:
HELLODBA.COM>select bytes from v$log where status = 'CURRENT';
BYTES
----------
52428800
HELLODBA.COM>select trunc(((select bytes from v$log where status = 'CURRENT') - (select to_number(value) from v$parameter where name = 'log_buffer'))*
2 (select to_number(val.KSPPSTVL)
3 from sys.x$ksppi nam, sys.x$ksppsv val
4 where nam.indx = val.indx
5 AND nam.ksppinm = '_log_private_mul') / 100 / 66560)
6 as "calculated private strands"
7 from dual;
calculated private strands
--------------------------
5
HELLODBA.COM>select count(1) "actual private strands" from x$kcrfstrand where last_buf_kcrfa = '00';
actual private strands
----------------------
5
當(dāng)logfile切換后(和checkpoint一樣,切換之前必須要將所有Private strand的內(nèi)容flush到logfile中,因此我們在alert log中可能會發(fā)現(xiàn)日志切換信息之前會有這樣的信息:"Private strand flush not complete",這是可以被忽略的),會重新根據(jù)切換后的logfile的大小計算對Private strand的限制:
HELLODBA.COM>alter system switch logfile;
System altered.
HELLODBA.COM>select bytes from v$log where status = 'CURRENT';
BYTES
----------
104857600
HELLODBA.COM>select trunc(((select bytes from v$log where status = 'CURRENT') - (select to_number(value) from v$parameter where name = 'log_buffer'))*
2 (select to_number(val.KSPPSTVL)
3 from sys.x$ksppi nam, sys.x$ksppsv val
4 where nam.indx = val.indx
5 AND nam.ksppinm = '_log_private_mul') / 100 / 66560)
6 as "calculated private strands"
7 from dual;
calculated private strands
--------------------------
13
HELLODBA.COM>select count(1) "actual private strands" from x$kcrfstrand where last_buf_kcrfa = '00';
actual private strands
----------------------
13
參數(shù)_log_private_parallelism_mul用于推算活躍事務(wù)數(shù)量在最大事務(wù)數(shù)量中的百分比,默認(rèn)為10。Private strand的數(shù)量不能大于活躍事務(wù)的數(shù)量。
HELLODBA.COM>show parameter transactions
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
transactions integer 222
transactions_per_rollback_segment integer 5
HELLODBA.COM>select trunc((select to_number(value) from v$parameter where name = 'transactions') *
2 (select to_number(val.KSPPSTVL)
3 from sys.x$ksppi nam, sys.x$ksppsv val
4 where nam.indx = val.indx
5 AND nam.ksppinm = '_log_private_parallelism_mul') / 100 )
6 as "calculated private strands"
7 from dual;
calculated private strands
--------------------------
22
HELLODBA.COM>select count(1) "actual private strands" from x$kcrfstrand where last_buf_kcrfa = '00';
actual private strands
----------------------
22
注:在預(yù)分配Private strand時,會選擇上述2個條件限制下最小一個數(shù)量。但相應(yīng)的shared pool的內(nèi)存分配和redo allocation latch的數(shù)量是按照活躍事務(wù)數(shù)預(yù)分配的。
因此,如果logfile足夠大,_log_private_parallelism_mul與實際活躍進(jìn)程百分比基本相符的話,Private strand的引入基本可以消除redo allocation latch的爭用問題。
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自:網(wǎng)絡(luò)轉(zhuǎn)載