共計 2888 個字符,預計需要花費 8 分鐘才能閱讀完成。
如何理解 redo 的內部過程與 lgwr,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面丸趣 TV 小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。
Oracle 采用混合日志記錄模式,以數據塊為單位,即 dba + sql,即避免記錄整個塊,又可快速恢復
the granularity is at the block level (like physical logging), so one operation is stored for each individual block change
一個大事務可由多個 mini-transaction 即 redo record 組成,而每個 record 又可由多個 change vector 組成;commit/rollback 單獨對應 1 個 redo record;
每個 redo record 包含 1 個原子操作,1 個 change vector 僅對應 1 個數據塊,change vector 在實際修改塊之前生成;
事務提交時,將生成的 redo+undo 和 commit record 寫入重做日志文件,同時更新 rollback segment header 的事務表;
注:臨時表只記錄 undo
Redo 有 3 種 latch
1 Copy,可通過_LOG_SIMULTANEOUS_COPIES 設置多個
2 Allocation 只有 1 個
3 Write 只有 1 個
REDO 的生成
Redo 先在 PGA 中生成,依次獲取 copy latch–allocation latch,將 redo 寫入 log buffer 后再修改塊,Lgwr 在刷新 redo buffer 時獲取 write latch,避免同時多次刷新;
具體步驟如下
1 以排他模式 pin 住 buffer block
2 在 PGA 中構建 change vector 并組合成 redo record,由 kconew()/kcoadd() 完成
3 調用 kcrfwr() 將 record 寫入 log buffer:
計算 record 占用的空間大小;
分配 SCN;
獲取 copy latch,驗證 SCN;
獲取 allocation latch,檢驗 log buffer/file 是否有足夠空間,有則釋放 allocation latch 將 redo 寫入 log buffer,否則同時釋放 allocation/copy latch 并通知 LGWR 進行 log flush/switch;
注:為防止多個進程同時通知 LGWR 刷新 redo 或切換日志文件,引入 write latch(只有 1 個),只有獲取此 latch 后才能進行下一步操作;
4 將 redo record 寫至 log buffer 而后釋放 copy latch, 檢查是否達到觸發 LGWR 閾值;
5 更改 buffer block
nologging
此模式下仍記錄 redo record,其下的 change vector 類型均為 INVALID;每個 record 可對應多個數據塊,應用該 redo 時相應數據塊將被標識為 soft-corrupt;
LGWR 觸發閾值
1 由前臺進程觸發:log buffer 空間不足;事務提交
2 log buffer 滿 1 /3
3 redo 超過 1M
4 3 秒超時
5 日志切換
6 redo 線程關閉
LGWR 觸發過程
1 獲取 write/allocation latch,前者防止 LGWR 被多次請求,后者防止為前臺進程繼續分配 redo 空間
2 確定待寫的 log buffer 范圍(從起始處至待刷新的 buffer),分配新 SCN(避免兩次 flush 使用同一個 SCN)
3 釋放 allocation latch
4 計算所需 redo write 次數,因為 log buffer 為環形,故至多寫兩次(分布于頭尾)
5 計算 target RBA,依據 log_checkpoint_interval 增進增量檢查點
6 釋放 write latch
7 確保待寫的 log buffer 都復制完畢,即等待所有 copy latch 釋放
8 LGWR 更新 redo block header 的 SCN 和 checksum(可選)
9 執行磁盤寫,可修改_lgwr_async_io 啟用異步 IO
組提交
Lgwr 在 c1 處接到請求,開始刷新 log buffer 時新增了 c2/g1/c3,此時需等待 c3 寫完(釋放 redo copy latch) 后,連同 c3 一起刷新,
常見的 redo 等待事件
log file parallel write- 由 lgwr 觸發,將 redo record 寫入當前 log 文件,其并行度由物理磁盤數決定
log file sync- 由前臺進程等待,從 commit/rollback 直到 lgwr 將日志寫入磁盤并通知請求進程為止
log buffer space- log buffer 中沒有足夠空間存放新生成的 redo,說明 lgwr 寫出速度較 redo 生成慢
log file switch- 分為 checkpoint incomplete 和 archiving needed
Log file sync 流程
lgwr 會 post 哪些前臺進程?
當 lgwr 刷新完日志后,會 post 相應的前臺進程 (wakeup)繼續工作,那么 lgwr 怎么判斷應該 wakeup 哪些前臺進程呢?
log file sync 等待的 p1 參數的含義為:P1 = buffer# in log buffer that needs to be flushed
當 lgwr 刷新完 buffer 后,會掃描活躍會話列表,查看哪些會話在等待 log file sync,而且會話的 buffer# 小于等于它所刷新的 log buffer 的最大值,這些會話會被 wakeup。
Lgwr file sync 與 buffer busy wait
事務 commit 的 stack call 如下
為 ktcCommitTxn= ktucmt = kcbchg = kcbchg1_main = kcrfw_redo_gen = kcrf_commit_force
kcbchg== block change,為什么要發生 block change 呢?因為 commit 需要對在 Buffer Cache 里的 block 做 immediate block cleanout,期間需要排他模式 pin;
若此時其他會話訪問該塊則會等待 buffer busy wait
http://www.askmaclean.com/archives/why-slow-redo-write-cause-buffer-busy-wait.html
歸檔日志流程
1 ARCH 讀取控制文件以決定待歸檔的日志文件
2 分配歸檔內存_LOG_ARCHIVE_BUFFERS * _LOG_ARCHIVE_BUFFER_SIZE;
3 以只讀方式打開待歸檔日志組的所有成員(以輪循方式依次讀取 log buffer),并驗證 log file header;如果 db_block_checksum=true 每個 log block 還將驗證 checksum
4 創建并打開歸檔日志文件
5 以循環方式將日志從 online log 復制到 archive log,對每個 buffer 都執行 sanity check
執行完畢后關閉 online log 和 archive log
看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注丸趣 TV 行業資訊頻道,感謝您對丸趣 TV 的支持。