天天看點

oracle學習筆記 執行個體崩潰恢複原理剖析oracle學習筆記 執行個體崩潰恢複原理剖析

oracle學習筆記 執行個體崩潰恢複原理剖析

上節講了檢查點隊列的内容和工作方式,

這節課講檢查點隊列有什麼意義。

講的知識叫oralce的執行個體崩潰恢複,

實際核心内容是檢查點隊列的作用。

一)功能

執行個體崩潰恢複是oracle的一個功能。

計算機中功能是實作程式設計目的的基本機關,

由一段或短或長的代碼構成,

功能常常還會需要其它代碼段或其它功能的支援。

人們之是以使用一個軟體就是使用它的功能,

他可以達到使用者的目的,

而要建構一個功能則是程式員的工作。

功能使用時會因為程式的完善程度,造成不同的體驗,

老師經常在課程中提到使用者體驗,都是由程式中功能實作的好壞造成的。

二)髒塊和資料丢失

oracle有buffercache,

資料庫正常運作期間,

buffercache裡有很多的髒塊。

髒塊就是oracle在記憶體裡面修改完了但是沒有寫到磁盤上。

也就是緩存的資料,

如果說伺服器突然掉電了、突然當機了或者非正常關閉,

記憶體裡的資料馬上就沒了。

這時很多的髒塊會出現沒有寫到磁盤上出現資料丢失的情況。

資料丢失又分幾種情況:

第一種情況不能丢失的,

第二種情況可以丢失的。

對oracle來講未送出的事物所修改的資料塊可以丢失,

已送出事務所對應的資料塊所對應的髒塊不能丢失。

這就是講的丢失的兩種情況。

髒塊往回寫的時候是DBWR做的事情。

第一種情況是一個髒塊被修改的行對應的事務已經送出,

但是這個資料還沒有寫到磁盤上,

因為oracle送出的時候隻是日志寫到redolog,髒塊可以不寫回來,

髒塊所對應的事務已經送出,這種髒塊是不能丢失的。

第二種情況這個髒塊所對應的事務還沒有送出,

這種髒塊可以丢失。

資料庫崩潰的瞬間,

這兩種髒塊都會有,

對第一種髒塊的丢失顯然我們不能接受,

第二種髒塊的丢失我們是可以接受的。

是以這裡要明确一個概念,

oracle崩潰以後有些髒塊需要找回來,

要通過日志找回來。

三)髒塊和日志

再看日志,

一部分日志在logbuffer裡面,

一部分日志在redolog裡面。

資料庫崩潰的瞬間buffercache裡面有髒塊。

第一種情況,

這個髒塊所對應的日志已經寫到磁盤上,就是已寫到redolog。

另外一種情況,

這些髒塊所對應的日志在logbuffer裡面。

反過來這麼說,

如果這個髒塊所對應的日志還在logbuffer裡面,

那說明這個日志所對應的事務肯定還沒有送出,

如果這個髒塊所對應的事務已經送出的話,

一定會寫到磁盤上。

一個髒塊被修改了,但是修改所對應的事務還沒有送出,

同時這個髒塊所對應的日志還在logbuffer裡面,

這時資料庫對于這個髒塊是可以丢失的。

資料庫崩潰以後日志丢失了,

這個日志丢失了這個髒塊也丢失了,

可以認為我們對這個髒塊所對應的修改從來沒有發生過。

對另一個髒塊來講,

它修改了,它所對應的事務隻要是送出了,

一定會寫到磁盤上。

既然日志寫到磁盤了,

我可以通過日志再把髒塊再給構造出來 。

四)日志和資料丢失

oracle崩潰以後很多髒塊丢失了。

oracle下次啟動的時候,自動會發現資料庫非正常關閉。

oracle發現非正常關閉以後,oracle會做一件事情,做執行個體崩潰恢複。

就是使用oracle磁盤上的日志redolog,

将資料庫崩潰瞬間所對應的髒塊構造出來。

如果資料庫啟動起來以後,

使用日志再把這個髒塊構造出來,

也就是我把資料庫buffercache恢複到出事的瞬間,

這樣對資料庫來講沒有丢失資料,是可以的。

當然oracle跑日志,使用日志恢複的時候,

隻能恢複到磁盤上的最後一條日志,

對于logbuffer裡面的日志它也丢了。

但是我們講過,

logbuffer對應的這些髒塊肯定沒有送出,

丢了就丢了。

oracle資料庫非正常關閉或者伺服器當機等等原因,

導緻oracle執行個體崩潰導緻髒塊丢失。

oralce資料庫下次啟動的時候,

oracle就可以使用redolog裡面的日志将髒塊構造出來。

将我們所需要的所有髒塊構造出來,

不需要的髒塊可以不構造出來。

五)執行個體崩潰恢複和日志

執行個體崩潰恢複的時候需要使用redolog裡面的日志。

1)恢複的終點

redolog裡有最新的日志,

使用日志使用到redolog裡面的最後一條,

跑日志的時候把所有的日志跑完,把所有的日志都用完,

終點是最後寫入的最新的一條。

比如資料庫中有三組日志裡面有好多日志,

可能有人有5組有10組日志。

我要把這些髒塊給構造出來,

終點知道了,

是current日志的最後一條日志。

2)LRBA的位置

我們需要知道起點,

起點肯定在redolog裡面。

回顧一下,

oracle崩潰的一瞬間有很多髒塊,

使用檢查點鍊起來。

我們看一下目前我們資料庫的情況

SQL> select CPDRT,CPLRBA_SEQ||'.'||CPLRBA_BNO||'.'||CPLRBA_BOF "Low RBA",
CPODR_SEQ||'.'||CPODR_BNO||'.'||CPODR_BOF "On disk RBA",CPODS,CPODT,CPHBT
from x$kcccp;  2    3

     CPDRT Low RBA         On disk RBA     CPODS            CPODT                     CPHBT
---------- --------------- --------------- ---------------- -------------------- ----------
       355 5.31404.0       5.33937.0       534061           04/19/2017 08:33:25   911688533
         0 0.0.0           0.0.0           0                                              0
         0 0.0.0           0.0.0           0                                              0
         0 0.0.0           0.0.0           0                                              0
         0 0.0.0           0.0.0           0                                              0
         0 0.0.0           0.0.0           0                                              0
         0 0.0.0           0.0.0           0                                              0
         0 0.0.0           0.0.0           0                                              0

8 rows selected.           

有Low RBA 和On disk RBA。

檢查點隊列裡最早髒的塊對應的位址,

在redolog中的一個位置。

redolog都在磁盤上,

redolog中的最後一條日志是最新的日志on disk RBA 。

對應LRBA的日志記錄對應檢查點隊列中的第一個髒塊的第一條日志。

redolog中LRBA位址的此前的所有的日志所對應的塊,

都已經寫到磁盤了。

因為LRBA是最早髒所對應的日志,

在它之前的所有的日志它們對應的髒塊對應的塊,

已經寫到磁盤了。

在LRBA位址後面的日志記錄,

對應着目前系統中的髒塊。

3)起點

比如現在要把原buffercache裡面的幾個髒塊構造出來。

如前數個髒塊對應着redolog中的LRBA位址後面的一段redo記錄的位址,

而檢查點隊列中最後面的髒塊的redo記錄對應在logbuffer中的一部分位址。

比如前三個髒塊,

對應着redolog中的LRBA位址後面的一段redo記錄的位址或幾條redolog記錄位址,

而檢查點隊列中最後面的髒塊如第四個髒塊的redo日志redo記錄對應在logbuffer中的一部分位址,

資料庫在這個瞬間是這個情況。

CKPT這個程序運作的時候,

把起點就是LRBA記錄到控制檔案中了。

資料庫突然崩了,

崩了以後logbuffer丢了,

四個髒塊也丢了。

oracle下次啟動起來以後,

在控制檔案中找到LRBA位址,

因為redolog中LRBA後的redo log記錄還在日志裡面。

根據控制檔案記錄的LRBA位址可以找到redolog中的起點,

然後使用日志、應用日志,

就可以把原檢查點隊列的前三個塊構造出來。

第四個塊構造不出來,

一定說明一個問題,第四個塊所對應的事務一定沒有送出。

我們就認為從來沒有發生過,

就是第四個塊不需要構造出來。

我們把前三個塊構造出來了,

這時候oracle沒有出現資料丢失,

我們隻要保證所有已送出事務所對應的修改能夠構造出來就OK了。

所有已送出事務所對應的日志一定寫到redolog裡面去了,

而且用redolog一定可以把需要的髒塊構造出來。

4)復原

但是同時也有可能把沒有必要構造出來的髒塊也構造出來,

而且一定會出現。

比如一個塊它所對應的事務沒有送出,

後面有個塊對應的事務已經送出了。

但是構造的時候,

日志是按照順序跑的,

為了構造後面已送出事務的塊,

把前面未送出事務的塊也構造出來了。

也就是說oracle執行個體崩潰恢複的時候,

确定起點确定終點以後跑日志,

結果把已送出的事務肯定都構造出來了,

同時未送出事務也有部分被構造出來了,

但是保證了沒有資料丢失。

對于未送出事務構造出來了,

oracle都會對所有未送出事務復原。

哪些事務未送出需要復原這是以後講undo時要講的内容。

5)前滾和復原

首先oracle發現資料庫非正常關閉需要做執行個體恢複。

第二oracle在控制檔案中找到檢查點隊列的LRBA位址,根據LRBA找到日志中的起點,

然後從日志起點跑一直跑到日志的終點。

終點就是redolog裡面的current中的最後一條日志,

跑到最後以後我們保證oracle所有已送出事務所對應的髒塊都被構造出來了。

但同時一些沒有送出事務的所對應的髒塊也被構造出來了,

沒關系,那些未送出事務oracle在undo裡面已經記錄了,

oracle在此後的操作中會自動的将崩潰前未送出事務自動進行復原。

這件事oracle會自動去做。

前滾就是我講的執行個體崩潰恢複,

找起點确定終點跑日志,

跑日志這個過程叫前滾,把髒塊構造出來了。

構造出來以後還有一些塊是髒塊被構造出來了但是它的事務沒有送出,

沒關系oracle此後會慢慢去復原。

是以說有前滾有復原,

這就是oracle執行個體崩潰恢複。

六)檢查點隊列和恢複的關系

檢查點隊列這個技術其實就是來确定日志的起點,

就這麼個作用。

oracle8以前它是沒有檢查點隊列的,

它根本不把這些髒塊使用檢查點隊列串起來。

那個時候oracle崩潰以後要執行個體恢複的時候,

也就是确定不了起點。

他就應用redolog裡面所有的日志,

當然這個所有可以打引号,

并不是所有但幾乎是所有。

應用日志多了沒關系,

就怕它應用的少了,

應用的多了可以復原。

在沒有檢查點隊列以前,

就是在oracle8以前,

oracle崩潰恢複的時候要跑非常多的日志。

oracle啟動的時候速度就會變慢,

是以檢查點隊列加快了oracle執行個體崩潰恢複。

沒有檢查點隊列oralce執行個體崩潰恢複的時候跑的日志會很多,

打開速度會慢。

如果有檢查點隊列,

oracle啟動的時候,

oracle執行個體崩潰恢複的時候啟動速度會變快。

就這麼一個作用。

執行個體崩潰恢複知識點後面還會慢慢的往裡深入加一些量,

我們不可能一次性到位的把所有東西都講的很細很明白,

要一步步去深入一步步去講。

2017年5月5日

文字:韻筝