程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> Oracle數據庫 >> Oracle數據庫基礎 >> Oracle Redo log並行機制詳解

Oracle Redo log並行機制詳解

編輯:Oracle數據庫基礎

Oracle的數據庫日志稱為Redo log,所有數據改變都記錄Redo log,可以用於修復受損的數據庫。Redo log 是用於恢復和一個高級特性的重要數據,一個redo條目包含了相應操作導致的數據庫變化的所有信息,所有redo條目最終都要被寫入redo文件中去。

Redo log buffer是為了避免Redo文件IO導致性能瓶頸而在sga中分配出的一塊內存。一個redo條目首先在用戶內存(PGA)中產生,然後由Oracle服務進程拷貝到log buffer中,當滿足一定條件時,再由LGWR進程寫入redo文件。由於log buffer是一塊“共享”內存,為了避免沖突,它是受到redo allocation latch保護的,每個服務進程需要先獲取到該latch才能分配redo buffer。因此在高並發且數據修改頻繁的oltp系統中,我們通常可以觀察到redo allocation latch的等待。Redo寫入redo buffer的整個過程如下:

在PGA中生產Redo Enrey -> 服務進程獲取Redo Copy latch(存在多個---CPU_COUNT*2) -> 服務進程獲取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的並行機制。其基本原理就是,將log buffer劃分為多個小的buffer,這些小的buffer被成為strand(為了和之後出現的private strand區別,它們被稱之為shared strand)。每一個strand受到一個單獨redo allocation latch的保護。多個shared strand的出現,使原來序列化的redo buffer分配變成了並行的過程,從而減少了redo allocation latch等待。

shared strand的初始數據量是由參數log_parallelism控制的;在10g中,該參數成為隱含參數,並新增參數_log_parallelism_max控制shared strand的最大數量;_log_parallelism_dynamic則控制是否允許shared strand數量在_log_parallelism和_log_parallelism_max之間動態變化。

  1. HELLODBA.COM>select  nam.ksppinm, val.KSPPSTVL, nam.ksppdesc      
  2.   2  from    sys.x$ksppi nam,      
  3.   3          sys.x$ksPPSv val      
  4.   4  where nam.indx = val.indx      
  5.   5  --AND   nam.ksppinm LIKE '_%'      
  6.   6  AND   upper(nam.ksppinm) LIKE '%LOG_PARALLE%';      
  7.      
  8. KSPPINM                    KSPPSTVL   KSPPDESC      
  9. -------------------------- ---------- ------------------------------------------      
  10. _log_parallelism           1          Number of log buffer strands      
  11. _log_parallelism_max       2          Maximum number of log buffer strands      
  12. _log_parallelism_dynamic   TRUE       Enable dynamic strands  

每一個shared strand的大小 = log_buffer/(shared strand數量)。strand信息可以由表x$kcrfstrand查到(包含shared strand和後面介紹的private strand,10g以後存在)。 

  1. HELLODBA.COM>select indx,strand_size_kcrfa from x$kcrfstrand where last_buf_kcrfa != '00';      
  2.      
  3.       INDX STRAND_SIZE_KCRFA      
  4. ---------- -----------------      
  5.          0           3514368      
  6.          1           3514368      
  7.      
  8. HELLODBA.COM>show parameter log_buffer      
  9.      
  10. NAME                                 TYPE        VALUE      
  11. ------------------------------------ ----------- ------------------------------      
  12. log_buffer                           integer     7028736    

關於shared strand的數量設置,16個cpu之內最大默認為2,當系統中存在redo allocation latch等待時,每增加16個cpu可以考慮增加1個strand,最大不應該超過8。並且_log_parallelism_max不允許大於cpu_count。

注意:在11g中,參數_log_parallelism被取消,shared strand數量由_log_parallelism_max、_log_parallelism_dynamic和cpu_count控制。

Private strand

為了進一步降低redo buffer沖突,在10g中引入了新的strand機制——Private strand。Private strand不是從log buffer中劃分的,而是在shared pool中分配的一塊內存空間。

  1. HELLODBA.COM>select * from V$sgastat where name like '%strand%';  
  2.  
  3. POOL NAME BYTES  
  4.  
  5. ------------ -------------------------- ----------  
  6.  
  7. shared pool private strands 2684928  
  8.  
  9. HELLODBA.COM>select indx,strand_size_kcrfa from x$kcrfstrand where last_buf_kcrfa = '00';  
  10.  
  11. INDX STRAND_SIZE_KCRFA  
  12.  
  13. ---------- -----------------  
  14.  
  15. 2 66560  
  16.  
  17. 3 66560  
  18.  
  19. 4 66560  
  20.  
  21. 5 66560  
  22.  
  23. 6 66560  
  24.  
  25. 7 66560  
  26.  
  27. 8 66560  
  28.  
  29. ... 

Private strand的引入為Oracle的Redo/Undo機制帶來很大的變化。每一個Private strand受到一個單獨的redo allocation latch保護,每個Private strand作為“私有的”strand只會服務於一個活動事務。獲取到了Private strand的用戶事務不是在PGA中而是在Private strand生成Redo,當flush private strand或者commit時,Private strand被批量寫入log文件中。如果新事務申請不到Private strand的redo allocation latch,則會繼續遵循舊的redo buffer機制,申請寫入shared strand中。事務是否使用Private strand,可以由x$ktcxb的字段ktcxbflg的新增的第13位鑒定:

  1. HELLODBA.COM>select decode(bitand(ktcxbflg, 4096),0,1,0) used_private_strand, count(*)  
  2.  
  3. from x$ktcxb  
  4.  
  5. where bitand(ksspaflg, 1) != 0  
  6.  
  7. and bitand(ktcxbflg, 2) != 0  
  8.  
  9. group by bitand(ktcxbflg, 4096);  
  10.  
  11. USED_PRIVATE_STRAND COUNT(*)  
  12.  
  13. ------------------- ----------  
  14.  
  15. 1 10  
  16.  
  17. 0 1 

對於使用Private strand的事務,無需先申請Redo Copy Latch,也無需申請Shared Strand的redo allocation latch,而是flush或commit是批量寫入磁盤,因此減少了Redo Copy Latch和redo allocation latch申請/釋放次數、也減少了這些latch的等待,從而降低了CPU的負荷。過程如下:

事務開始 -> 申請Private strand的redo allocation latch (申請失敗則申請Shared Strand的redo allocation latch) -> 在Private strand中生產Redo Enrey -> Flush/Commit -> 申請Redo Copy Latch -> 服務進程將Redo Entry批量寫入Log File -> 釋放Redo Copy Latch -> 釋放Private strand的redo allocation latch 。

注意:對於未能獲取到Private strand的redo allocation latch的事務,在事務結束前,即使已經有其它事務釋放了Private strand,也不會再申請Private strand了。

每個Private strand的大小為65K。10g中,shared pool中的Private strands的大小就是活躍會話數乘以65K,而11g中,在shared pool中需要為每個Private strand額外分配4k的管理空間,即:數量*69k。

  1. --10g:  
  2.  
  3. SQL> select * from V$sgastat where name like '%strand%';  
  4.  
  5. POOL NAME BYTES  
  6.  
  7. ------------ -------------------------- ----------  
  8.  
  9. shared pool private strands 1198080  
  10.  
  11. HELLODBA.COM>select trunc(value * KSPPSTVL / 100) * 65 * 1024  
  12.  
  13. from (select value from v$parameter where name = 'transactions') a,  
  14.  
  15. 3 (select val.KSPPSTVL  
  16.  
  17. from sys.x$ksppi nam, sys.x$ksPPSv val  
  18.  
  19. where nam.indx = val.indx  
  20.  
  21. AND nam.ksppinm = '_log_private_parallelism_mul') b;  
  22.  
  23. TRUNC(VALUE*KSPPSTVL/100)*65*1024  
  24.  
  25. -------------------------------------  
  26.  
  27. 1198080  
  28.  
  29. --11g:  
  30.  
  31. HELLODBA.COM>select * from V$sgastat where name like '%strand%';  
  32.  
  33. POOL NAME BYTES  
  34.  
  35. ------------ -------------------------- ----------  
  36.  
  37. shared pool private strands 706560  
  38.  
  39. HELLODBA.COM>select trunc(value * KSPPSTVL / 100) * (65 + 4) * 1024  
  40.  
  41. from (select value from v$parameter where name = 'transactions') a,  
  42.  
  43. 3 (select val.KSPPSTVL  
  44.  
  45. from sys.x$ksppi nam, sys.x$ksPPSv val  
  46.  
  47. where nam.indx = val.indx  
  48.  
  49. AND nam.ksppinm = '_log_private_parallelism_mul') b;  
  50.  
  51. TRUNC(VALUE*KSPPSTVL/100)*(65+4)*1024  
  52.  
  53. -------------------------------------  
  54.  
  55. 706560 

Private strand的數量受到2個方面的影響:logfile的大小和活躍事務數量。

參數_log_private_mul指定了使用多少logfile空間預分配給Private strand,默認為5。我們可以根據當前logfile的大小(要除去預分配給log buffer的空間)計算出這一約束條件下能夠預分配多少個Private strand:

  1. HELLODBA.COM>select bytes from v$log where status = 'CURRENT';  
  2.  
  3. BYTES  
  4.  
  5. ----------  
  6.  
  7. 52428800  
  8.  
  9. HELLODBA.COM>select trunc(((select bytes from v$log where status = 'CURRENT') - (select to_number(value) from v$parameter where name = 'log_buffer'))*  
  10.  
  11. 2 (select to_number(val.KSPPSTVL)  
  12.  
  13. from sys.x$ksppi nam, sys.x$ksPPSv val  
  14.  
  15. where nam.indx = val.indx  
  16.  
  17. AND nam.ksppinm = '_log_private_mul') / 100 / 66560)  
  18.  
  19. as "calculated private strands" 
  20.  
  21. from dual;  
  22.  
  23. calculated private strands  
  24.  
  25. --------------------------  
  26.  
  27. 5  
  28.  
  29. HELLODBA.COM>select count(1) "actual private strands" from x$kcrfstrand where last_buf_kcrfa = '00';  
  30.  
  31. actual private strands  
  32.  
  33. ----------------------  
  34.  

當logfile切換後(和checkpoint一樣,切換之前必須要將所有Private strand的內容flush到logfile中,因此我們在alert log中可能會發現日志切換信息之前會有這樣的信息:"Private strand flush not complete",這是可以被忽略的),會重新根據切換後的logfile的大小計算對Private strand的限制:

  1. HELLODBA.COM>alter system switch logfile;  
  2.  
  3. System altered.  
  4.  
  5. HELLODBA.COM>select bytes from v$log where status = 'CURRENT';  
  6.  
  7. BYTES  
  8.  
  9. ----------  
  10.  
  11. 104857600  
  12.  
  13. HELLODBA.COM>select trunc(((select bytes from v$log where status = 'CURRENT') - (select to_number(value) from v$parameter where name = 'log_buffer'))*  
  14.  
  15. 2 (select to_number(val.KSPPSTVL)  
  16.  
  17. from sys.x$ksppi nam, sys.x$ksPPSv val  
  18.  
  19. where nam.indx = val.indx  
  20.  
  21. AND nam.ksppinm = '_log_private_mul') / 100 / 66560)  
  22.  
  23. as "calculated private strands" 
  24.  
  25. from dual;  
  26.  
  27. calculated private strands  
  28.  
  29. --------------------------  
  30.  
  31. 13  
  32.  
  33. HELLODBA.COM>select count(1) "actual private strands" from x$kcrfstrand where last_buf_kcrfa = '00';  
  34.  
  35. actual private strands  
  36.  
  37. ----------------------  
  38.  
  39. 13 

參數_log_private_parallelism_mul用於推算活躍事務數量在最大事務數量中的百分比,默認為10。Private strand的數量不能大於活躍事務的數量。

  1. HELLODBA.COM>show parameter transactions  
  2.  
  3. NAME TYPE VALUE  
  4.  
  5. ------------------------------------ ----------- ------------------------------  
  6.  
  7. transactions integer 222  
  8.  
  9. transactions_per_rollback_segment integer 5  
  10.  
  11. HELLODBA.COM>select trunc((select to_number(value) from v$parameter where name = 'transactions') *  
  12.  
  13. 2 (select to_number(val.KSPPSTVL)  
  14.  
  15. from sys.x$ksppi nam, sys.x$ksPPSv val  
  16.  
  17. where nam.indx = val.indx  
  18.  
  19. AND nam.ksppinm = '_log_private_parallelism_mul') / 100 )  
  20.  
  21. as "calculated private strands" 
  22.  
  23. from dual;  
  24.  
  25. calculated private strands  
  26.  
  27. --------------------------  
  28.  
  29. 22  
  30.  
  31. HELLODBA.COM>select count(1) "actual private strands" from x$kcrfstrand where last_buf_kcrfa = '00';  
  32.  
  33. actual private strands  
  34.  
  35. ----------------------  
  36.  
  37. 22 

注:在預分配Private strand時,會選擇上述2個條件限制下最小一個數量。但相應的shared pool的內存分配和redo allocation latch的數量是按照活躍事務數預分配的。

因此,如果logfile足夠大,_log_private_parallelism_mul與實際活躍進程百分比基本相符的話,Private strand的引入基本可以消除redo allocation latch的爭用問題。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved