1. 程式人生 > >Oracle RedoLog-基本概念和組成

Oracle RedoLog-基本概念和組成

Oracle 資料庫恢復操作最關鍵的依據就是 `redo log`,它記錄了對資料庫所有的更改操作。在研究如何提取 redolog 中 DML 操作的過程可謂一波三折,因為介紹 redolog 結構細節的資料實在太少了,不過好在最後大致理清了它的結構,並開發了一個基於日誌的同步軟體。 本系列文章就記錄下研究過程中遇到的問題和使用的分析命令、工具。 ## 1. 什麼是 Redo Log Redo Log 就是一組檔案,它們記錄了對資料庫的所有操作,主要包括: - 所有 `DML` 操作,`INSERT\UPDATE\DELETE\SELECT FOR UPDATE` - 所有 `DDL` 操作,`CREATE TABLE\ALTER TABLE` 等 - 所有因 `Recursive SQL` 引起的變化,比如執行 DDL 語句時,Oracle 會隱式的執行其他 SQL 修改資料字典 在資料庫事務 `COMMIT` 之前,Oracle 既會把變化資訊寫入 Rodo Log 檔案,也會把原始資料-即 `UNDO Segments` 寫入。因此,Redo Log 不僅用於恢復資料,還能保護資料回滾。 ## 2. Oracle 如何寫入 Redo Log Oracle 資料庫每個例項都有一個 `redo thread` 負責日誌的寫入,稱為 `LGWR`,LoG WRiter 的簡寫。Redo Log 檔案至少有兩個,LGWR 採用迴圈覆蓋的方式寫入:當一個檔案寫滿後,開始寫入下一個,當最後一個檔案寫滿後,返回第一個開始寫入,如此迴圈。 ![](https://img2020.cnblogs.com/blog/1424165/202101/1424165-20210104133653989-791493772.gif) 這樣寫入會導致資料丟失嗎?預設情況下**會**。 資料庫日誌有兩種模式:`歸檔` 和 `非歸檔`,非歸檔模式就會有覆蓋寫入的問題。在歸檔模式下,當一組 ReodLog 檔案寫滿,發生切換時,Oracle 會保證歸檔完成前此組檔案不被覆蓋。 ![](https://img2020.cnblogs.com/blog/1424165/202101/1424165-20210104133707757-1736742184.png) 可以使用以下命令手動觸發日誌切換: ``` SQL> alter system switch logfile ``` ## 3. Redo Log 基本結構 Redo Log 是由一系列的 `redo record` 組成,每個 `redo record` 又是由一組 `change vector` 組成,每個 `change vector` 都記錄了對單個數據塊的更改操作。 Redo Log 檔案在儲存結構上,是按**塊**儲存的,預設情況下**塊大小**是磁碟扇區的大小,通常是 `512 位元組`,它的格式取決於作業系統和資料庫版本,這裡的分析都是在 `Windows Server 2008 R2` 和 `Oracle 11g` 的基礎上進行的。 Redo Log 是按順序寫入的,基本格式如下: ![](https://img2020.cnblogs.com/blog/1424165/202101/1424165-20210104133719499-1559997983.png) 前兩個塊記錄的是**元資訊**,分別是: - 第1個塊記錄檔案本身的資訊,比如檔案型別,塊大小和塊數,這部分稱為 `File Header` - **檔案頭** - 第2個塊記錄資料庫例項相關資訊,比如資料庫SID,資料庫版本,這部分稱為 `Redo Log Header` - **重做日誌頭** 結合日誌寫入方式,從整體上看,讀取這一組 Redo Log 檔案,在記憶體中可以把它們看成按塊為儲存單元的**環形緩衝區**來處理,解析的過程就是讀取一個個 `Record`。 ### 3.1 Redo Record 一個 Redo Record 可能佔用一個 block,也可能佔用多個 block,也可能只佔用 block 的一部分,這取決於它的**長度**,長度欄位就儲存在 `Record Header` 頭部,結構如下: ![](https://img2020.cnblogs.com/blog/1424165/202101/1424165-20210104133731500-918109260.png) 值得注意的是,Record 的**頭**長度是動態的,計算方法以及二進位制檔案位元組分析後續文章會詳細介紹,這裡簡單看下使用 `system dump` 命令匯出的頭資訊: ``` REDO RECORD - Thread:1 RBA: 0x000009.0000029e.0010 LEN: 0x02ac VLD: 0x0d SCN: 0x0000.0010c5e6 SUBSCN: 1 01/02/2021 21:09:41 ``` 其中主要欄位的含義: - **RBA**: Redo Byte Address, 由三部分組成:日誌序號(0x9),塊編號(0x29e),塊中位元組偏移量(0x10) - **LEN**: Record 長度,包含頭部長度 - **VLD**: 頭部長度標識,按照一定的邏輯計算頭的長度,`0x0d` 就表示頭部長度為 `68 位元組` - **SCN**: System Change Number,也可稱為 System Commit Number。當一個事務提交時,LOWR 將緩衝區內容寫入檔案,併為每個已提交的事務,分配一個標識,就是 SCN。也就是說,可以通過 SCN 跟蹤資料庫變化,也可以根據它決定從哪開始恢復資料。 此外,藉助 SCN 還可以有針對的 dump 執行的 DML 語句,本文最後有相關的命令。 ### 3.2 Change Vector Record 頭後面就跟著,一個或多個 `Change Vector`,每個 `Change` 都代表一個數據庫操作,比如增刪改,事務開始,事務回滾,事務提交等等,它的格式如下: ![](https://img2020.cnblogs.com/blog/1424165/202101/1424165-20210104133744696-1938202271.png) 其中: - `Change Header` 固定 `24 位元組` 長度 - `Length Vector` 表示後面有多少個 `Change Record`,每 `2 位元組` 表示一個長度,計算長度時,需要進行 `4 位元組對齊` - `Change Record` 就是具體的變化內容了,不同的操作有不同的格式。 使用 `system dump` 看下 `Change Header` 的資訊: ``` CHANGE #1 TYP:0 CLS:1 AFN:4 DBA:0x01000085 OBJ:73194 SCN:0x0000.000e606a SEQ:1 OP:11.2 ENC:0 RBL:0 ``` 其中主要欄位的含義: - **TYP**: Change Type - **CLS**: Class 等於 X$BH.CLASS 暫時不知用途 - **DBA**: Database Block Address,4位元組長度,`高10位`表示相對檔案號,`低22位`表示塊號 - **OP**: 操作碼,區分操作型別,每個操作碼都由兩部分組成:`Layer Code` 和 `Sub Code`,比如 `11.2` 下圖是一些常用的操作 ![](https://img2020.cnblogs.com/blog/1424165/202101/1424165-20210104133758430-1439441832.png) ### 3.3 Transactions 事務 開始執行一個 `DML` 操作時,會建立一個 `OP:5.2` 的 Change,標識事務開始: ``` CHANGE #2 TYP:0 CLS:19 AFN:3 DBA:0x00c00090 OBJ:4294967295 SCN:0x0000.0010c5bb SEQ:3 OP:5.2 ENC:0 RBL:0 ktudh redo: slt: 0x0018 sqn: 0x0000033a flg: 0x0012 siz: 108 fbi: 0 uba: 0x00c007a0.009b.40 pxid: 0x0000.000.00000000 ``` 當**事務提交**或者**回滾**時,會建立一個 `OP:5.4` 的 Change,標識事務結束: ``` CHANGE #4 TYP:0 CLS:19 AFN:3 DBA:0x00c00090 OBJ:4294967295 SCN:0x0000.0010c5e6 SEQ:1 OP:5.4 ENC:0 RBL:0 ktucm redo: slt: 0x0018 sqn: 0x0000033a srt: 0 sta: 9 flg: 0x2 ktucf redo: uba: 0x00c007a0.009b.41 ext: 2 spc: 640 fbi: 0 ``` 一個完整的事務都有一個唯一標識,日誌中的體現就是 `XID` : ``` xid: 0x0002.018.0000033a ``` `XID` 長度是 `8 位元組`,由三部分組成: - **USN**: Undo segment number (0x0002),目前不知如何獲取此值 - **slt**: Undo segment header transaction table slot (0x018),對應 `ktudh/ktucm` 中的 `slt` - **sqn**: 0x0000033a,對應 `ktudh/ktucm` 中的 `sqn` 在 `ktudh/ktucm` 中有一個 `uba` 欄位,內容是 `uba: 0x00c007a0.009b.41`,它表示此 `Change` 在 `undo block` 中的地址,長度是 `7位元組`,也由三部分組成: - undo block 的 **DBA** (0x00c007a0) - 序號 (0x009b) - 在 block 中的 Record 編號 (0x41) 下圖是一個完整事務的示例: ![](https://img2020.cnblogs.com/blog/1424165/202101/1424165-20210104133810264-949672856.png) 執行了兩個 `update`,其中 `c1=1` 的 c2 原先等於 100,更新成了 101;`c1=2` 的 c2 原先等於 200,更新成了 201; ## 4. 相關命令 ### 4.1 日誌歸檔和非歸檔 查詢資料庫當前的日誌模式: ``` SQL> archive log list; or SQL> select log_mode from v$database; ``` 檢視線上日誌: ``` SQL> select l.STATUS, lf.MEMBER from v$log l, v$logfile lf where l.GROUP# = lf.GROUP#; ``` 檢視已歸檔日誌: ``` SQL> select recid, stamp, thread#, sequence#, name from v$archived_log; ``` 檢視預設歸檔路徑 ``` SQL> show parameter db_recovery_file_dest; ``` 日誌開啟歸檔模式: ``` SQL> shutdown immediate; SQL> startup mount SQL> alter database archivelog; SQL> alter database open; SQL> archive log list; ``` 日誌關閉歸檔模式: ``` SQL> shutdown immediate; SQL> startup mount SQL> alter database noarchivelog; SQL> alter database open; ``` ### 4.2 Redo Log Dump 使用 `ALTER SYSTEM` 命令可以把二進位制的 Redo Log 檔案轉儲為任何文字編輯器可讀的 ASCII 編碼檔案,有助於我們理解分析二進位制結構,該命令的語法如下: ``` alter system dump logfile 'FileName' scn min MinimumSCN scn max MaximumSCN time min MinimumTime (s) time max MaximumTime (s) layer Layer opcode Opcode dba min FileNumber BlockNumber dba max FileNumber BlockNumber rba min LogFileSequenceNumber BlockNumber rba max LogFileSequenceNumber BlockNumber objno ObjectNumber xid UndoSegmentNumber UndoSlotNumber UndoSequenceNumber; ``` 使用 **SCN** : ``` SQL> alter system dump logfile '/u01/app/oradata/orcl/redo03.log' scn min 1099234 scn max 1099246; ``` 使用 **RBA** : ``` SQL> select cpodr_seq,cpodr_bno from x$kcccp where rownum=1; CPODR_SEQ CPODR_BNO ---------- ---------- 9 1514 SQL> DML (insert/update/delete) SQL> select cpodr_seq,cpodr_bno from x$kcccp where rownum=1; CPODR_SEQ CPODR_BNO ---------- ---------- 9 1518 SQL> alter system dump logfile '/u01/app/oradata/orcl/redo03.log' rba min 9 1514 rba max 9 1518; ``` **注意**:每次 dump 後都需要退出此次會話,重新登入後再 dump,否則結果只會儲存到一個檔案內。 ### 4.3 查詢 dump 路徑 有兩種辦法查詢 dump 路徑。 **第一**,使用以下命令檢視預設路徑: ``` SQL> show parameter user_dump_dest; NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ user_dump_dest string c:\database\oracle\administrat or\diag\rdbms\orcl\orcl\trace ``` **第二**,在執行 dump 命令前後使用以下命令,可以顯示: ``` SQL> oradebug setmypid; SQL> alter system dump logfile xxxxxxx SQL> oradebug tracefile_name; c:\database\oracle\xxxxxxx\xxxxxxx.trc ``` ### 4.4 dump 一個 insert 操作 首先,檢視當前使用的線上日誌是哪一個,即狀態為 `CURRENT` 的檔案: ``` SQL> select l.STATUS, lf.MEMBER from v$log l, v$logfile lf where l.GROUP# = lf.GROUP#; ``` 然後,往 `scott` 使用者的 `dept` 表插入一條資料,檢視 dump 的結果,命令如下: ``` SQL> select current_scn from v$database; CURRENT_SCN ----------- 1099234 SQL> insert into scott.dept values(50, 'a', 'a'); SQL> commit; SQL> select current_scn from v$database; CURRENT_SCN ----------- 1099246 SQL> alter system dump logfile '/u01/app/oradata/orcl/redo03.log' scn min 1099234 scn max 1099246; ``` 最後,二進位制 Redo log dump 的結果,這裡只摘出了 insert 部分,太長了,相信也沒人看~~: ``` CHANGE #1 TYP:0 CLS:1 AFN:4 DBA:0x01000085 OBJ:73194 SCN:0x0000.000e606a SEQ:1 OP:11.2 ENC:0 RBL:0 KTB Redo op: 0x01 ver: 0x01 compat bit: 4 (post-11) padding: 0 op: F xid: 0x0002.018.0000033a uba: 0x00c007a0.009b.40 KDO Op code: IRP row dependencies Disabled xtype: XA flags: 0x00000000 bdba: 0x01000085 hdba: 0x01000082 itli: 1 ispac: 0 maxfr: 4858 tabn: 0 slot: 0(0x0) size/delt: 10 fb: --H-FL-- lb: 0x1 cc: 3 null: --- col 0: [ 2] c1 33 col 1: [ 1] 61 col 2: [ 1] 61 ``` 簡單解釋下,`OP:11.2` 表示這是一個 `insert` 操作;`OBJ:73194` 表示操作的表是 `scott.dept`;最後三行的 `col` 表示操作的欄位資料,顯示的數值都是 16 進位制,其中 `c1 33` 按照一定的運算邏輯會轉成 `50`,`61` 就是字元 `a` 的 ASCII 編碼。 ## 5. 總結 建議上面的命令都手動執行下,別人總結的終究沒有自己經歷下,來的印象深刻。 本系列文章主要參考的有: - **Julian Dyke** 對 RedoLog 分析的 PPT - **David Litchfield** 對 Redo Logs 二進位制檔案剖析的 PDF - **zhoubihui** 釋出在 GitHub 上的 redo_log_calculate_analysis 研究文章 以上資料網上均能搜尋到,當然了,您也可以關注下wx公眾號,「小創程式設計」回覆關鍵字「redolog」