MySQL 特性:Double Write
- 2019 年 10 月 12 日
- 筆記
1.什麼是double write
首先要明白double write這個特性是針對誰的,日誌or臟數據?
明白的是臟數據,是記憶體中修改後的數據頁,這些數據頁修改後和磁碟上存儲的原數據不一致了,稱為臟數據。為了數據的持久性,這些臟數據需要刷新到磁碟上,使修改永久的保存,而double write就產生在將臟數據刷盤的過程中。刷盤是一份臟數據寫到共享表空間,一份寫到真正的數據文件永久的保存。寫了兩次臟數據,就叫double wriete。
2.為什麼要有double write
很多人疑問,為啥寫兩次,刷一次數據文件保存數據不就行了,寫共享表空間是啥意思嘛。共享表空間是在ibdbata文件中划出2M連續的空間,專門給double write刷臟頁用的,說白了就是磁碟上2M連續空間。
MySQL的數據頁默認是16k,對數據頁的校驗也是按16k計算的。而作業系統的數據頁默認是2k或者4k,IO操作是按系統頁為單位就行讀寫的。這就可能出現一種情況,資料庫對一個16k的數據頁修改後,作業系統開始進行寫磁碟,每次寫4k,結果剛寫完第一個4k,資料庫掛了。這時候系統一臉懵逼的看著掛掉的資料庫,獃獃的說了句‘這事不怨我’。這時候資料庫重啟時,校驗數據頁,發現有數據頁不完整,就起不來了,即使通過歪門邪道使資料庫起來,也會有一頁的數據丟失。
為了解決這個問題,double write就應運而生了,為安全而來。簡單來說,修改後的臟頁放到double write buffer區,這個區佔用2M記憶體空間,buffer空間滿或其他條件觸發,使double write buffer存的臟頁先寫到共享表空間,之後在寫入數據文件。這個時候如果寫了不完整的頁,可以用共享表空間中完整的頁加以覆蓋,數據頁完整了,資料庫也就可以拉起了,之後的各種恢復就看redo log的了。提到redo log了,有人可能又會懵逼,不完整的數據頁用redo log恢復唄,搞個double write多此一舉嗎。這時候不得不介紹一下redo log的記錄日誌格式了——redo log是按數據塊的方式記錄日誌的,差不多類似於臟頁直接放到redo log中,但又不完全相同,不然redo log得多佔空間啊。它是根據偏移量來記錄修改了,比如test數據文件的第1025個數據塊的100位元組的偏移位置,數據修改為了‘new data’。一個16k的數據塊不可能哪兒哪兒都修改,有可能僅僅修改裡面的一個位元組,而redo log的工作作風就是:修改哪兒記錄哪兒。這樣,數據頁不完整了,找redo log沒用。



3.double write工作流程
論double write的工作流程,廢話不多說,請直接看圖:先產生臟頁,產生臟頁的過程中會寫redo log,這是第一步。臟頁有了,也就按部就班了。


4.如何利用double write進行恢復
數據恢復有三種情況:
4.1 臟數據寫磁碟成功
這種情況是最常見的,臟頁刷磁碟99.9%都會成功,但是即使有0.1失敗可能也要做處理,不然數據丟了,資料庫就不安全了,沒有公司願意天天提心弔膽的抱著個定時炸彈。刷盤成功,找檢查點,redo log前滾、回滾就行了。
4.2 共享表空間寫失敗
如果是寫共享表空間失敗,那麼這些數據不會被寫到數據文件,資料庫會認為這次刷盤從沒發生過,MySQL此時會從磁碟載入原始的數據,然後找檢查點,redo log前滾、回滾就行了。
4.3 臟數據刷數據文件失敗
寫共享表空間成功,但是寫數據文件失敗,在恢復的時候,MySQL直接比較頁面的checksum,如果不對的話,直接從共享表空間的double write中找到該頁的一個最近的副本,將其複製到表空間文件,再應用redo log,就完成了恢復過程。因為有副本所以也不擔心表空間中數據頁是否損壞。
5.double write缺陷及改進過程
太長了,以後再說。