本人小菜鳥一枚,最近在學習MySQL(邊學MySQL邊對比Oracle)時遇到一個問題
MySQL通過double write避免了partial page write.這個partial page write感覺就相當于Oracle的split block.那么Oracle如何保證寫臟塊時不會產生split block呢?
我知道rman可以避免split block是因為它以oracle block size作為最小IO單位,如果發現checksum不一致,就會重讀,通過反復讀避免split block. 當執行手工begin backup命令時,each time a block is changed the datbase writes the before-image of the entire block to the redo stream before modifying the block. Then, the database also records the changes to the block in the redo log,通過將oracle block的前鏡像寫入redo,使得在恢復是能夠獲取oracle block的整個before-image,以此為基礎,在通過redo中的記錄進行恢復.所以如果想要恢復split block,是要有該split block的整個前鏡像的吧.
但是在正常的dbwr寫臟塊時,是不會記錄befor-image到redo的吧.那么Oracle怎么解決這個問題啊
uj5u.com熱心網友回復:
恢復.所以如果想要恢復split block,是要有該split block的整個前鏡像的吧.不懂 MySQL的原理,你說的這個,應該是 Oracle 的 UNDO ,你先百度了解一下;
uj5u.com熱心網友回復:
split block是指:一個 Oracle block 由多個 OS block 組成,寫入必定有先后。那么外部工具備份是以 OS block 為單位備份,就可能發生一個 Oracle block 下的多個 OS block 版本不一致的情況。而rman是把這一組 OS block 作為一個整體單位來處理的,全部讀進來,如果版本一致可以寫入備份,如果不一致全部重讀。
所以讀臟塊沒關系,只要有辦法檢測出不一致,直接把不一致的資料丟棄重讀就行。
uj5u.com熱心網友回復:
跟undo沒關系吧
參考一段<<MySQL技術內幕:InnoDB存盤引擎>>書中對double write的描述內容:
如果說Insert Buffer帶給InnoDB存盤引擎的是性能上的提升,那么doublewrite(兩次寫)帶給InnoDB存盤引擎的是資料頁的可靠性。
當發生資料庫宕機時,可能InnoDB存盤引擎正在寫入某個頁到表中,而這個頁只寫了一部分,比如16KB的頁,只寫了前4KB,之后就發生了宕機,這種情況被稱為部分寫失效(partial page write)。在InnoDB存盤引擎未使用doublewrite技術前,曾經出現過因為部分寫失效而導致資料丟失的情況。
有經驗的DBA也許會想,如果發生寫失效,可以通過重做日志進行恢復。這是一個辦法。但是必須清楚地認識到,重做日志中記錄的是對頁的物理操作,如偏移量800,寫'aaaa'記錄。如果這個頁本身已經發生了損壞,再對其進行重做是沒有意義的。這就是說,在應用(apply)重做日志前,用戶需要一個頁的副本,當寫入失效發生時,先通過頁的副本來還原該頁,再進行重做,這就是doublewrite。
uj5u.com熱心網友回復:
令我產生疑問的不是臟讀,是Oracle block和OS block大小不一樣.Oracle寫一個oracle block到磁盤,加設8K,而一個OS block可能是4K,那么有可能產生這兩個4K的塊不一致,oracle如何保證不會產生這種不一致?
uj5u.com熱心網友回復:
嗯。
uj5u.com熱心網友回復:
恢復.所以如果想要恢復split block,是要有該split block的整個前鏡像的吧.
不懂 MySQL的原理,你說的這個,應該是 Oracle 的 UNDO ,你先百度了解一下;
您說的對,我也感覺需要split block的前鏡像,但是正常dbwr寫臟塊到磁盤時.
加上oracle block 大小為8K, OS block大小為4K,那么此時一個oracle blokc= 2* OS block
加入dbwr在寫臟塊,寫了前4K,此時發生crash,比如電源掛了,那么這個oracle block的前4k和后4k就不一致了,對于這種不一致的oracle block,通過redo沒法恢復吧. 那么oracle如果保證不會產生我假設的這種情況呢?
MySQL通過double write避免這種問題
在對緩沖池的臟頁進行重繪時,并不直接寫磁盤,而是會通過memcpy函式將臟頁先復制到記憶體中的doublewrite buffer,之后通過doublewrite buffer再分兩次,每次1MB順序地寫入共享表空間的物理磁盤上,然后馬上呼叫fsync函式,將更改真正的寫入目標對應得資料檔案中
在資料寫失敗時會有一下2種情況。
-如果是寫doublewrite buffer本身失敗,那么這些資料不會被寫到磁盤,也就是真正的page沒有損壞,innodb此時會從磁盤載入原始的資料,然后通過innodb的事務日志來計算出正確的資料,重新 寫入到doublewrite buffer
-如果 doublewrite buffer寫成功的話,但是寫磁盤失敗(通過對比checksum判斷),innodb就不用通過事務日志來計算了,而是直接用double write buffer的資料再寫一遍.
uj5u.com熱心網友回復:
令我產生疑問的不是臟讀,是Oracle block和OS block大小不一樣.Oracle寫一個oracle block到磁盤,加設8K,而一個OS block可能是4K,那么有可能產生這兩個4K的塊不一致,oracle如何保證不會產生這種不一致?
這2個4k本身就在Oracle的快取中,要取資料直接從快取中取,總是一致的。
只有Oracle之外的程式才從硬碟讀,從而發生讀到4k舊、4k新資料的可能。
uj5u.com熱心網友回復:
[Quote=參考 4 樓 ashic 的回復:]令我產生疑問的不是臟讀,是Oracle block和OS block大小不一樣.Oracle寫一個oracle block到磁盤,加設8K,而一個OS block可能是4K,那么有可能產生這兩個4K的塊不一致,oracle如何保證不會產生這種不一致?
這2個4k本身就在Oracle的快取中,要取資料直接從快取中取,總是一致的。
只有Oracle之外的程式才從硬碟讀,從而發生讀到4k舊、4k新資料的可能。
這兩個4K的os block對應一個Oracle block,寫入程序中寫了第一個4K,然后服務器斷電了.現在就很有可能前4K和后4K checksum不一致. 和在快取中有啥關系?服務器都掛了,硬碟中的oracle block已經被修改了一部分了,后面那4K沒改成功
uj5u.com熱心網友回復:
這兩個4K的os block對應一個Oracle block,寫入程序中寫了第一個4K,然后服務器斷電了.現在就很有可能前4K和后4K checksum不一致. 和在快取中有啥關系?服務器都掛了,硬碟中的oracle block已經被修改了一部分了,后面那4K沒改成功
中間斷電,日志中該操作沒完成,重啟后會回滾(恢復上個版本資料)。
總之資料庫是以8k作為一個原子來操作的,對資料庫而言,并不存在(需要)4k成功4k不成功的這樣的狀態,只有(只需要)8k不成功狀態就行。
uj5u.com熱心網友回復:
[Quote=參考 8 樓 ashic 的回復:]這兩個4K的os block對應一個Oracle block,寫入程序中寫了第一個4K,然后服務器斷電了.現在就很有可能前4K和后4K checksum不一致. 和在快取中有啥關系?服務器都掛了,硬碟中的oracle block已經被修改了一部分了,后面那4K沒改成功
中間斷電,日志中該操作沒完成,重啟后會回滾(恢復上個版本資料)。
總之資料庫是以8k作為一個原子來操作的,對資料庫而言,并不存在(需要)4k成功4k不成功的這樣的狀態,只有(只需要)8k不成功狀態就行。
redo肯定是在dbwr寫臟塊前就把日志寫入磁盤了,而dbwr寫臟塊是在之后發生,如果出現寫資料塊不一致,redo中也不會記錄該操作是否完成吧
第二句還靠譜,我再ITPUB上也看有人這么說,你們的意思就是Oracle寫臟塊時以Oracle block為最小IO單位嗎?oracle直接去寫資料檔案,不經過作業系統?如果Oracle可以控制以自身Oracle block為原子進行寫資料,那么到時可以避免partial write.但是我又產生了疑問,如果oracle可以做到為什么mysql不這么做呢,有沒有能證實您說法的檔案?
uj5u.com熱心網友回復:
[Quote=參考 8 樓 ashic 的回復:]這兩個4K的os block對應一個Oracle block,寫入程序中寫了第一個4K,然后服務器斷電了.現在就很有可能前4K和后4K checksum不一致. 和在快取中有啥關系?服務器都掛了,硬碟中的oracle block已經被修改了一部分了,后面那4K沒改成功
中間斷電,日志中該操作沒完成,重啟后會回滾(恢復上個版本資料)。
總之資料庫是以8k作為一個原子來操作的,對資料庫而言,并不存在(需要)4k成功4k不成功的這樣的狀態,只有(只需要)8k不成功狀態就行。
您說的"資料庫是以8k作為一個原子來操作的"有沒有官方檔案,或者其他文獻資料可以證實?或者您通過實驗證實?我覺得MySQL通過double write也只是避免了自身crash導致的資料損壞,沒法保證作業系統再寫page的程序中斷電是否會造成os block損壞,至于OS有什么機制避免,我還不清楚
但是假設oracle以oracle block為最小IO單位寫資料,它怎么保證自己再寫了8K中的一部分時,資料庫崩潰不會造成partial write,除非他先寫到一個臨時檔案,寫成功了在去寫真正的資料塊
"中間斷電,日志中該操作沒完成,重啟后會回滾(恢復上個版本資料)。" 您的意思是說,dbwr寫臟塊的程序還要記錄在redo中?,寫完了在redo中標記寫成功?恐怕不是這樣吧
uj5u.com熱心網友回復:
寫臟塊會記錄在控制檔案中原子操作的概念是事務層面的吧?
uj5u.com熱心網友回復:
[http://blog.163.com/bihonggang_anshan/blog/static/13171564320118143472780/]oracle 寫入資料的程序[/url]Oracle中SGA與PGA的異同點是什么
對于任何一個完善的資料庫,這是封裝好的底層基本功能,屬于無需關心的部分。
想了解自己找檔案看,遠比你想象的/平時簡要描述的要復雜的多。
uj5u.com熱心網友回復:
[http://blog.163.com/bihonggang_anshan/blog/static/13171564320118143472780/]oracle 寫入資料的程序[/url]
Oracle中SGA與PGA的異同點是什么
對于任何一個完善的資料庫,這是封裝好的底層基本功能,屬于無需關心的部分。
想了解自己找檔案看,遠比你想象的/平時簡要描述的要復雜的多。
我現在覺得你根本不知道我再問什么,而你對體系結構也很混亂
uj5u.com熱心網友回復:
[http://blog.163.com/bihonggang_anshan/blog/static/13171564320118143472780/]oracle 寫入資料的程序[/url]
Oracle中SGA與PGA的異同點是什么
對于任何一個完善的資料庫,這是封裝好的底層基本功能,屬于無需關心的部分。
想了解自己找檔案看,遠比你想象的/平時簡要描述的要復雜的多。
我在這里要討論的就是你說的底層,我發文也是翻過oracle官方檔案,MOS,ITPUB得不到答案才來提問的.從你一開始說什么"在Oracle的快取中","中間斷電,日志中該操作沒完成,重啟后會回滾".這都不是我要討論的問題.
不管什么資料庫,對作業系統來說都是是一個軟體,是軟體就要協同作業系統完成任務.MySQL知道以自己的page進行寫,要呼叫系統方法實作,而系統塊大小與MySQL page不符,所以才有了double write.而Oracle如果解決官方檔案中并沒有體現.
我要再次參考<<MySQL技術內幕:InnoDB存盤引擎>>中的描述
當發生資料庫宕機時,可能InnoDB存盤引擎正在寫入某個頁到表中,而這個頁只寫了一部分,比如16KB的頁,只寫了前4KB,之后就發生了宕機,這種情況被稱為部分寫失效(partial page write)。在InnoDB存盤引擎未使用doublewrite技術前,曾經出現過因為部分寫失效而導致資料丟失的情況。
有經驗的DBA也許會想,如果發生寫失效,可以通過重做日志進行恢復。這是一個辦法。但是必須清楚地認識到,重做日志中記錄的是對頁的物理操作,如偏移量800,寫'aaaa'記錄。如果這個頁本身已經發生了損壞,再對其進行重做是沒有意義的。這就是說,在應用(apply)重做日志前,用戶需要一個頁的副本,當寫入失效發生時,先通過頁的副本來還原該頁,再進行重做,這就是doublewrite。
實體恢復是以健康的資料塊為基礎,應用日志,前滾回滾,完成實體恢復,構造buffer中的資料塊.而如果塊本身已經corrupt,是不能以此作為基礎再通過日志進行恢復的,至少MySQL不能,所以有了double write.而我在這里問的就是Oracle如何解決,這是對比學習的方法
恕我直言,沒有檔案,文獻,實驗支持的結論都是耍流氓.不能說"任何一個完善的資料庫,這是封裝好的底層基本功能,屬于無需關心的部分"就相當然的認為別人是這樣的做的,這不是做技術的學習方法.
網上涉及的文章,都沒有詳細說明.
http://www.vmcd.org/2014/09/1748/comment-page-1/#comment-343836
https://community.oracle.com/thread/1087650?start=0&tstart=0
http://www.ixora.com.au/tips/use_raw_log_files.htm
uj5u.com熱心網友回復:
你問: Oracle 避免 split block 的方式。其實一句話就可以回答:把屬于同一個 oracle block 的 OS block 作為一個原子進行控制就行。
其余的就是你在不停地追加細節問題了。
如果僅僅是學會使用資料庫,你把它看成一個黑箱功能,反正資料庫保證做到,能用就行。
如果你想學著撰寫一個資料庫系統,先從大概原理來,可以看看我的回復。
如果你就追究Oracle是怎么做的,請忽略我的回復,去看檔案。
uj5u.com熱心網友回復:
寫臟塊會記錄在控制檔案中
原子操作的概念是事務層面的吧?
寫臟塊完成后會記錄檢查點.以便實體恢復時能夠找到開始恢復的"點"
我覺得也是事物層
你問: Oracle 避免 split block 的方式。
其實一句話就可以回答:把屬于同一個 oracle block 的 OS block 作為一個原子進行控制就行。
其余的就是你在不停地追加細節問題了。
如果僅僅是學會使用資料庫,你把它看成一個黑箱功能,反正資料庫保證做到,能用就行。
如果你想學著撰寫一個資料庫系統,先從大概原理來,可以看看我的回復。
如果你就追究Oracle是怎么做的,請忽略我的回復,去看檔案。
無論如何還是謝謝您了
uj5u.com熱心網友回復:
繼續求答案!轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/107664.html
標籤:基礎和管理
