共計 2473 個字符,預(yù)計需要花費 7 分鐘才能閱讀完成。
這篇文章主要介紹 MySQL 中 InnoDB 存儲引擎架構(gòu)的示例分析,文中介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們一定要看完!
InnoDB 組件結(jié)構(gòu):
buffer pool : 緩沖池,緩存磁盤的數(shù)據(jù)
redo log buffer:記錄對緩沖池的操作,根據(jù)策略寫入磁盤防止宕機但事務(wù)已經(jīng)提交而丟失數(shù)據(jù)
undo log:當(dāng)對緩沖池的數(shù)據(jù)進行修改時,在事務(wù)未提交的時候都可以進行回滾,將舊值寫入 undo 日志文件便于回滾,此時緩沖池的數(shù)據(jù)與磁盤中的不一致,是臟數(shù)據(jù)
1. Buffer Pool
假設(shè)現(xiàn)在有一條更新語句:
update users set name = lisi where id = 1
需要更新到數(shù)據(jù)庫,InnoDB 會執(zhí)行哪些操作呢?
首先,InnoDB 會判讀緩沖池里是否存在 id = 1 這條數(shù)據(jù),如果不存在則從磁盤中加載到緩沖池中,而且還會對這行數(shù)據(jù)加獨占鎖,防止多個 sql 同時修改這行數(shù)據(jù)。
2. undo 日志文件
假設(shè) id = 1 這條數(shù)據(jù) name 原來的值 name = zhangsan,現(xiàn)在我們要更新為 name = lisi , 那么我們就需要把舊值 name= zhangsan 和 id= 1 這些信息寫入到 undo 日志文件中。
對于熟悉數(shù)據(jù)庫的同學(xué)來說都了解事務(wù)的概念,在事務(wù)未提交之前,所有操作都有可能進行回滾,即可以把 name = lisi 回滾到 name = zhangsan,所以將更新前的值寫到 undo 日志文件。
3. 更新 buffer pool 數(shù)據(jù)
在 undo 日志文件寫入完畢之后,便開始更新內(nèi)存中的這條數(shù)據(jù)。把 id = 1 的 name = zhangsan 更新為 name = lisi。這時內(nèi)存中的數(shù)據(jù)已經(jīng)更新完畢,但磁盤上的還沒有變化,此時出現(xiàn)了不一致的臟數(shù)據(jù)。
這時可能有一個疑問,萬一事務(wù)提交完成,但 MySQL 服務(wù)宕機了,而內(nèi)存中的數(shù)據(jù)還沒寫入到磁盤,是不是會造成數(shù)據(jù)丟失而造成 sql 執(zhí)行數(shù)據(jù)前后不一致?
4. redo log buffer
在 InnoDB 結(jié)構(gòu)中,有一個 redo log buffer 緩沖區(qū)存放 redo 日志,所謂 redo 日志,例如 把 id=1,name= zhangsan 修改為 name= lisi 便是一條日志。
但這時 redo log buffer 還僅僅存在內(nèi)存中,沒能實現(xiàn) MySQL 宕機后的數(shù)據(jù)恢復(fù)。
5. 事務(wù)沒提交,數(shù)據(jù)庫宕機后有影響嗎?
其實并沒有影響,事務(wù)沒有提交,意味著執(zhí)行沒有成功,就算 MySQL 崩潰或者宕機后,內(nèi)存中的 buffer pool 和 redo log buffer 修改過的數(shù)據(jù)都會丟失,也并不影響數(shù)據(jù)前后的一致性。如果事務(wù)提交失敗,那數(shù)據(jù)庫的數(shù)據(jù)更加不會改變。
6. 提交事務(wù),redo 日志的配置策略
在提交事務(wù)時,redo 日記會根據(jù)策略實現(xiàn)把 redo 日志從 redo log buffer 里寫入磁盤。策略通過 innoDB_flush_log_at_trx_commit 來配置。
innoDB_flush_log_at_trx_commit 的參數(shù)為 0,就算事務(wù)提交后,也不會把 redo 日志寫入磁盤。MySQL 宕機后會內(nèi)存中的數(shù)據(jù)會丟失。
innoDB_flush_log_at_trx_commit 的參數(shù)為 1,事務(wù)提交后,redo 日志會從內(nèi)存刷入磁盤,只要事務(wù)提交成功,redo log 就必然存在磁盤里。
此時就算 buffer pool 的數(shù)據(jù)沒有刷進磁盤,也可以從 redo log 中得知修改過哪些數(shù)據(jù),MySQL 宕機重啟后,可以從 redo 日志中恢復(fù)修改的數(shù)據(jù)。
innoDB_flush_log_at_trx_commit 的參數(shù)為 2,事務(wù)提交后,redo log 僅僅停留在 os cache 中,還沒刷進磁盤,萬一此時服務(wù)宕機了。那么 os cache 中的數(shù)據(jù)也會丟失,即使事務(wù)提交成功,也會造成數(shù)據(jù)丟失。
看完這幾種相信為了保證數(shù)據(jù)安全,參數(shù)為 1 是最佳策略。
7. 事務(wù)的最終提交,binlog
binlog 其實是屬于 MySQL Server 的日志文件,而在這出提出是因為與 redo log 有著很大的關(guān)聯(lián)。
1) biglog 與 redo log 的區(qū)別
redo log: 記錄的是偏物理性質(zhì)重做日志,比如“對哪個數(shù)據(jù)頁中的什么記錄,做了哪些修改”
binlog:偏向于邏輯性的日志,如:“對 users 表中的 id=10 的一行數(shù)據(jù)做了更新操作,更新以后的值是什么”
2) 提交事務(wù)的時候同時寫入 binlog
在執(zhí)行更新的同時,innoDB 與執(zhí)行器一直在交互,包括加載數(shù)據(jù)到緩沖池,寫入 undo 日志文件,更新內(nèi)存數(shù)據(jù),寫 redo 日志和刷入磁盤等。而對 binlog 的寫入也是由執(zhí)行器執(zhí)行。
其中 1、2、3、4 步驟為執(zhí)行更新語句做的事,而 5、6 是提交事務(wù)開始做的事。
3) binlog 日志刷盤策略分析
sync_binlog 參數(shù)控制 binlog 的刷盤策略
sync_ binlog 默認(rèn)值是 0,提交事務(wù)后,會把 binlog 日志存在 os cache 中,MySQL 宕機后會造成 os cache 中數(shù)據(jù)的丟失
sync_binlog 值為 1,提交事務(wù)后,把 binlog 日志直接刷入磁盤中。
4) 基于 binlog 和 redo log 完成事務(wù)的提交
binlog 寫入磁盤后,會把 binlog 日志文件所在的位置和文件名稱都寫入 redo log 日志文件中,同時在 redo log 日志文件里寫入一個 commit 標(biāo)記。
5) commit 標(biāo)記有什么意義?
commit 標(biāo)記意義著保持 redo log 和 binlog 日志一致。如果在步驟 5 或者步驟 6,事務(wù)提交開始,MySQL 宕機了,redo log 中并沒有 commit 標(biāo)記,都算事務(wù)提交失敗。
意味著 commint 標(biāo)記是事務(wù)最終提交成功。
8. buffer pool 臟數(shù)據(jù)刷入磁盤
臟數(shù)據(jù)刷入磁盤是由后臺 IO 線程隨機刷入磁盤的。
這時候考慮到,在刷入磁盤之前,MySQL 宕機怎么辦?這時候,事務(wù)已經(jīng)提交成功,redo log 中也有 commit 標(biāo)記,就算宕機了,重啟后,也會根據(jù) redo 日志文件把數(shù)據(jù)更新到內(nèi)存中,等待 IO 線程的刷盤。
以上是“MySQL 中 InnoDB 存儲引擎架構(gòu)的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對大家有幫助,更多相關(guān)知識,歡迎關(guān)注丸趣 TV 行業(yè)資訊頻道!