共計 2534 個字符,預計需要花費 7 分鐘才能閱讀完成。
本篇文章為大家展示了我很理解 MySQL 中的 double write,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。
MySQL 里的 double write 是 InnoDB 的三大閃亮特性,另外兩個是 insert buffer
和自適應哈希,其實還有幾個比如異步 IO,Flush neighbour
Page(刷新鄰接頁),這個和系統層面的關聯性較高,所以三大亮點還是更有針對性的。
當然一說到 MySQL 里的 double write, 其實主要是要應對一個很自然的問題,那就是 partial write。
經典的 partial write 問題
這個問題比較經典,很多數據庫設計中都需要考慮到這樣一個臨界點的問題,MySQL 中的頁是 16k, 數據的校驗是按照這個為單位進行的,而操作系統層面的數據單位肯定達不到 16k, 比如是 4k, 那么一旦發生斷電的時候,只保留了部分寫入,如果是 Oracle
DBA 一般對此都會很淡定,說用 redo 來恢復嘛,但是可能我們被屏蔽了一些細節,MySQL 在恢復的過程中一個基準是檢查 page 的 checksum,也就是 page 的最后事務號,發生這種 partial
page write 的問題時,因為 page 已經損壞,所以就無法定位到 page 中的事務號,所以這個時候 redo 就無法直接恢復。
由此引申一點,partial write 的問題在 Oracle 中肯定也會存在,但是只是 Oracle 替我們把這個過程平滑的做好了。其中有設計的差異,還有恢復技術的差別。但是無論如何這個問題都不會繞過去,還得解決。
所以這一類問題,如果討論起來,那可以討論很長時間,可以把體系結構里的方方面面拿出來分析,做對比。
簡單分析 double write 問題
對此我畫了一個相對簡陋的圖,也歡迎大家提出改進建議。
總體來說,double write
buffer 就是一種緩沖緩存技術,主要的設計就是為了防止數據在斷電,異常情況下丟失數據。里面有幾個點需要注意的就是,數據在 buffer
pool 中修改后成了臟頁,這個過程會產生 binglog 記錄和 redo 記錄,當然數據寫入數據文件是一個異步的工作,如果細看,在共享表空間(system
tablespace)中會存在一個 2M 的空間,分為 2 個單元,一共 128 個頁,其中 120 個用于批量刷臟數據,另外 8 個用于 Single Page
Flush。根據阿里同學的分析主要是做區分是因為批量刷臟是后臺線程做的,這樣不影響前臺線程。而 Single page
flush 是用戶線程發起的,需要盡快的刷臟并替換出一個空閑頁出來。所以不是一個嚴格的 64+64 的拆分。
而數據刷新的過程,是先使用 memcopy 把臟數據復制到內存中的 double write
buffer, 分兩次寫完,每次寫 1MB 到共享表空間,然后就是調用 fsync 來同步到磁盤。這里有一點需要注意的是,這個刷新到共享表空間的過程,雖然是兩次,但是是順序寫,所以開銷不會很大,也就不會像大家想象的 double
write 性能可能很差,根據 Percona 的測試,大概也就是 5% 左右的差別,數據重要還是性能更重要,這是一個基本的命題。當然后續會再寫入對應的表空間文件中,這個過程就是隨機寫,性能開銷就會大一些。所以在早些時候是用 SSD 的時候很多人也會帶有如此的顧慮,順序寫還是隨機寫。
當然 double write 這么設計就是全面為了作為恢復而用,要不這么大張旗鼓就不值得了。這個圖來源于 http://blog.csdn.net/renfengjun/article/details/41541809
我覺得已經說得很明白了,就直接引用過來了。
可以看到里面的一個中心詞就是 checksum, 如果出現了 partil
write 的時候,比如斷電,那么兩次寫的過程中,很可能 page 是不一致的,這樣 checksum 校驗就很可能出現問題,而出現問題的時候,因為有了前期寫入共享表空間的頁信息,所以就可以重構出頁的信息重新寫入。
double write 的另外一個作用
double write 其實還有一個特點,就是將數據從 double write buffer 寫到真正的 segment 中的時候, 系統會自動合并連接空間刷新的方式, 這樣一來每次就可以刷新多個 pages,提高效率。
比如下面的環境,我們可以根據 show status 的結果來得到一個基本的合并頁的情況。
show status like %dbl%
| Variable_name | Value |
| Innodb_dblwr_pages_written | 23196544 |
| Innodb_dblwr_writes | 4639373 |
通過 InnoDB_dblwr_pages_written/InnoDB_dblwr_writes 就可以得到,通過指標也可基本看明白。
Percona 中的 double write 改進
當然對于 double write,在 Percona 中也在持續改進,在 Percona 5.7 版本中做了一個改進,你可以看到一個新的參數,innodb_parallel_doublewrite_path
| innodb_parallel_doublewrite_path | xb_doublewrite | 在系統層面,也會存在一個 30 的一個文件對應。
-rw-r—– 1 mysql mysql 31457280 Mar 28 17:54 xb_doublewrite 也就是并行 double
write, 關于這個特性的詳細描述和測試,可以參考。https://www.percona.com/blog/2016/05/09/percona-server-5-7-parallel-doublewrite/?utm_source=tuicool utm_medium=referral
里面提供了很多詳細測試的對比和分析。當然 MariaDB,Facebook,Aurora 也有一些自己的實現方式和考慮,這個限于精力,還沒有細細測試分析。
上述內容就是我很理解 MySQL 中的 double write,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注丸趣 TV 行業資訊頻道。