MySQL到底有幾種日志類(lèi)型需要我們記?。?/h1>
本文作者粗略地總結(jié)了 MySQL 三種日志的一些特點(diǎn)和作用,以幫助大家理解 MySQL 中的事物以及事物背后的原理。
MySQL中有七種日志文件,分別是:
- 重做日志(redo log)
- 回滾日志(undo log)
- 二進(jìn)制日志(binlog)
- 錯(cuò)誤日志(errorlog)
- 慢查詢(xún)?nèi)罩荆╯low query log)
- 一般查詢(xún)?nèi)罩荆╣eneral log)
- 中繼日志(relay log)
其中重做日志和回滾日志與事務(wù)操作息息相關(guān),二進(jìn)制日志也與事務(wù)操作有一定的關(guān)系,這三種日志,對(duì)理解 MySQL 中的事務(wù)操作有著重要的意義。這里簡(jiǎn)單總結(jié)一下這三個(gè)具有一定相關(guān)性的日志。
重做日志(redo log)
作用
重做日志(redo log)的作用是確保事務(wù)的持久性,防止在發(fā)生故障的時(shí)間點(diǎn),尚有臟頁(yè)未寫(xiě)入磁盤(pán)。
在重啟 MySQL 服務(wù)的時(shí)候,根據(jù) redo log 進(jìn)行重做,從而達(dá)到事務(wù)的持久性這一特性。
內(nèi)容
物理格式的日志,記錄的是物理數(shù)據(jù)頁(yè)面修改的信息,其 redo log 是順序?qū)懭?redo log file 的物理文件中去的。
什么時(shí)候產(chǎn)生
事務(wù)開(kāi)始之后就產(chǎn)生 redo log,redo log 的落盤(pán)并不是隨著事務(wù)的提交才寫(xiě)入的,而是在事務(wù)的執(zhí)行過(guò)程中,便開(kāi)始寫(xiě)入 redo log 文件中。
什么時(shí)候釋放
當(dāng)對(duì)應(yīng)事務(wù)的臟頁(yè)寫(xiě)入到磁盤(pán)之后,redo log 的使命也就完成了,重做日志占用的空間就可以重用(被覆蓋)。
對(duì)應(yīng)的物理文件
默認(rèn)情況下,對(duì)應(yīng)的物理文件位于數(shù)據(jù)庫(kù)的 data 目錄下的 ib_logfile1&ib_logfile2。
innodb_log_group_home_dir 指定日志文件組所在的路徑,默認(rèn)./ ,表示在數(shù)據(jù)庫(kù)的數(shù)據(jù)目錄下,innodb_log_files_in_group 指定重做日志文件組中文件的數(shù)量,默認(rèn)為 2。
關(guān)于文件的大小和數(shù)量,由以下兩個(gè)參數(shù)配置:
- innodb_log_file_size 重做日志文件的大小。
- innodb_mirrored_log_groups 指定了日志鏡像文件組的數(shù)量,默認(rèn) 1。
其他
很重要一點(diǎn),redo log 是什么時(shí)候?qū)懕P(pán)的?前面說(shuō)了是在事物開(kāi)始之后逐步寫(xiě)盤(pán)的。
之所以說(shuō)重做日志是在事務(wù)開(kāi)始之后逐步寫(xiě)入重做日志文件,而不一定是事務(wù)提交才寫(xiě)入重做日志緩存。
原因就是,重做日志有一個(gè)緩存區(qū) Innodb_log_buffer,Innodb_log_buffer 的默認(rèn)大小為 8M(這里設(shè)置的 16M),Innodb 存儲(chǔ)引擎先將重做日志寫(xiě)入 innodb_log_buffer 中。
然后會(huì)通過(guò)以下三種方式將 Innodb 日志緩沖區(qū)的日志刷新到磁盤(pán):
- Master Thread 每秒一次執(zhí)行刷新 Innodb_log_buffer 到重做日志文件。
- 每個(gè)事務(wù)提交時(shí)會(huì)將重做日志刷新到重做日志文件。
- 當(dāng)重做日志緩存可用空間少于一半時(shí),重做日志緩存被刷新到重做日志文件。
由此可以看出,重做日志通過(guò)不止一種方式寫(xiě)入到磁盤(pán),尤其是對(duì)于***種方式,Innodb_log_buffer 到重做日志文件是 Master Thread 線(xiàn)程的定時(shí)任務(wù)。
因此重做日志的寫(xiě)盤(pán),并不一定是隨著事務(wù)的提交才寫(xiě)入重做日志文件的,而是隨著事務(wù)的開(kāi)始,逐步開(kāi)始的。
另外引用《MySQL技術(shù)內(nèi)幕 Innodb 存儲(chǔ)引擎》(page37)上的原話(huà):
即使某個(gè)事務(wù)還沒(méi)有提交,Innodb 存儲(chǔ)引擎仍然每秒會(huì)將重做日志緩存刷新到重做日志文件。
這一點(diǎn)是必須要知道的,因?yàn)檫@可以很好地解釋再大的事務(wù)提交(commit)的時(shí)間也是很短暫的。
回滾日志(undo log)
作用
保存了事務(wù)發(fā)生之前的數(shù)據(jù)的一個(gè)版本,可以用于回滾,同時(shí)可以提供多版本并發(fā)控制下的讀(MVCC),也即非鎖定讀。
內(nèi)容
邏輯格式的日志,在執(zhí)行 undo 的時(shí)候,僅僅是將數(shù)據(jù)從邏輯上恢復(fù)至事務(wù)之前的狀態(tài),而不是從物理頁(yè)面上操作實(shí)現(xiàn)的,這一點(diǎn)是不同于 redo log 的。
什么時(shí)候產(chǎn)生
事務(wù)開(kāi)始之前,將當(dāng)前時(shí)的版本生成 undo log,undo 也會(huì)產(chǎn)生 redo 來(lái)保證 undo log 的可靠性。
什么時(shí)候釋放
當(dāng)事務(wù)提交之后,undo log 并不能立馬被刪除,而是放入待清理的鏈表,由 purge 線(xiàn)程判斷是否由其他事務(wù)在使用 undo 段中表的上一個(gè)事務(wù)之前的版本信息,決定是否可以清理 undo log 的日志空間。
對(duì)應(yīng)的物理文件
MySQL 5.6 之前,undo 表空間位于共享表空間的回滾段中,共享表空間的默認(rèn)名稱(chēng)是 ibdata,位于數(shù)據(jù)文件目錄中。
MySQL 5.6 之后,undo 表空間可以配置成獨(dú)立的文件,但是提前需要在配置文件中配置,完成數(shù)據(jù)庫(kù)初始化后生效且不可改變 undo log 文件的個(gè)數(shù)。
如果初始化數(shù)據(jù)庫(kù)之前沒(méi)有進(jìn)行相關(guān)配置,那么就無(wú)法配置成獨(dú)立的表空間了。
關(guān)于 MySQL 5.7 之后的獨(dú)立 undo 表空間配置參數(shù)如下:
- innodb_undo_directory = /data/undospace/ –undo 獨(dú)立表空間的存放目錄
- innodb_undo_logs = 128 –回滾段為 128KB
- innodb_undo_tablespaces = 4 –指定有 4 個(gè) undo log 文件
如果 undo 使用的共享表空間,這個(gè)共享表空間中又不僅僅是存儲(chǔ)了 undo 的信息,共享表空間將默認(rèn)位于 MySQL 的數(shù)據(jù)目錄下面,其屬性由參數(shù) innodb_data_file_path 配置。
其他
undo 是在事務(wù)開(kāi)始之前保存的被修改數(shù)據(jù)的一個(gè)版本,產(chǎn)生 undo 日志的時(shí)候,同樣會(huì)伴隨類(lèi)似于保護(hù)事務(wù)持久化機(jī)制的 redolog 的產(chǎn)生。
默認(rèn)情況下 undo 文件是保持在共享表空間的,也即 ibdatafile 文件中,當(dāng)數(shù)據(jù)庫(kù)中發(fā)生一些大的事務(wù)性操作的時(shí)候,要生成大量的 undo 信息,全部保存在共享表空間中的。
因此共享表空間可能會(huì)變的很大,默認(rèn)情況下,也就是 undo 日志使用共享表空間的時(shí)候,被“撐大”的共享表空間是不會(huì)也不能自動(dòng)收縮的。
因此,MySQL 5.7 之后的“獨(dú)立 undo 表空間”的配置就顯得很有必要了。
二進(jìn)制日志(binlog)
作用
用于復(fù)制,在主從復(fù)制中,從庫(kù)利用主庫(kù)上的 binlog 進(jìn)行重播,實(shí)現(xiàn)主從同步;用于數(shù)據(jù)庫(kù)基于時(shí)間點(diǎn)的還原。
內(nèi)容
邏輯格式的日志,可以簡(jiǎn)單認(rèn)為就是執(zhí)行過(guò)的事務(wù)中的 SQL 語(yǔ)句,但又不完全是 SQL 語(yǔ)句這么簡(jiǎn)單。
它包括了執(zhí)行的 SQL 語(yǔ)句(增刪改)反向的信息,也就意味著 delete 對(duì)應(yīng)著 delete 本身和其反向的 insert;update 對(duì)應(yīng)著 update 執(zhí)行前后的版本的信息;insert 對(duì)應(yīng)著 delete 和 insert 本身的信息。
在使用 MySQLbinlog 解析 binlog 之后一些都會(huì)真相大白。因此可以基于 binlog 做到類(lèi)似于 Oracle 的閃回功能,其實(shí)都是依賴(lài)于 binlog 中的日志記錄。
什么時(shí)候產(chǎn)生
事務(wù)提交的時(shí)候,一次性將事務(wù)中的 SQL 語(yǔ)句(一個(gè)事物可能對(duì)應(yīng)多個(gè) SQL 語(yǔ)句)按照一定的格式記錄到 binlog 中。
這里與 redo log 很明顯的差異就是 redo log 并不一定是在事務(wù)提交的時(shí)候刷新到磁盤(pán),redo log 是在事務(wù)開(kāi)始之后就開(kāi)始逐步寫(xiě)入磁盤(pán)。
因此對(duì)于事務(wù)的提交,即便是較大的事務(wù),提交(commit)都是很快的,但是在開(kāi)啟了 bin_log 的情況下,對(duì)于較大事務(wù)的提交,可能會(huì)變得比較慢一些。
這是因?yàn)?binlog 是在事務(wù)提交的時(shí)候一次性寫(xiě)入造成的,這些可以通過(guò)測(cè)試驗(yàn)證。
什么時(shí)候釋放
binlog 默認(rèn)是保持時(shí)間由參數(shù) expire_logs_days 配置,也就是說(shuō)對(duì)于非活動(dòng)的日志文件,在生成時(shí)間超過(guò) expire_logs_days 配置的天數(shù)之后,會(huì)被自動(dòng)刪除。
對(duì)應(yīng)的物理文件
配置文件的路徑為 log_bin_basename,binlog 日志文件按照指定大小,當(dāng)日志文件達(dá)到指定的***的大小之后,進(jìn)行滾動(dòng)更新,生成新的日志文件。
對(duì)于每個(gè) binlog 日志文件,通過(guò)一個(gè)統(tǒng)一的 index 文件來(lái)組織。
其他
二進(jìn)制日志的作用之一是還原數(shù)據(jù)庫(kù),這與 redo log 很類(lèi)似,很多人混淆過(guò),但是兩者有本質(zhì)的不同:
- 作用不同:redo log 是保證事務(wù)的持久性的,是事務(wù)層面的;binlog 作為還原的功能,是數(shù)據(jù)庫(kù)層面的(當(dāng)然也可以精確到事務(wù)層面的)。雖然都有還原的意思,但是其保護(hù)數(shù)據(jù)的層次是不一樣的。
- 內(nèi)容不同:redo log 是物理日志,是數(shù)據(jù)頁(yè)面修改之后的物理記錄,binlog 是邏輯日志,可以簡(jiǎn)單認(rèn)為記錄的就是 SQL 語(yǔ)句。
- 另外,兩者日志產(chǎn)生的時(shí)間、可以釋放的時(shí)間,在可釋放的情況下清理機(jī)制,都是完全不同的。
- 恢復(fù)數(shù)據(jù)時(shí)候的效率,基于物理日志的 redo log 恢復(fù)數(shù)據(jù)的效率要高于語(yǔ)句邏輯日志的 binlog。
關(guān)于事務(wù)提交時(shí),redo log 和 binlog 的寫(xiě)入順序,為了保證主從復(fù)制時(shí)候的主從一致(當(dāng)然也包括使用 binlog 進(jìn)行基于時(shí)間點(diǎn)還原的情況),是要嚴(yán)格一致的。
MySQL 通過(guò)兩階段提交過(guò)程來(lái)完成事務(wù)的一致性的,也即 redo log 和 binlog 的一致性,理論上是先寫(xiě) redo log,再寫(xiě) binlog,兩個(gè)日志都提交成功(刷入磁盤(pán)),事務(wù)才算真正的完成。
總結(jié)
MySQL 中,對(duì)于以上三種日志,每一種細(xì)化起來(lái)都可以夠?qū)懸粋€(gè)章節(jié)的,這里粗略地總結(jié)了一下三種日志的一些特點(diǎn)和作用,以幫助理解 MySQL 中的事物以及事物背后的原理。