MySQL日志:binlog、事务日志(redo、undo)
事務的隔離性是通過鎖實現,而事務的原子性、一致性和持久性則是通過日志實現。Mysql的日志可以分為:
- binlog:server層實現
- 事務日志:包括redo log、undo log,引擎層(innodb)實現
redo log
redo log是用于備份事務中操作得到的最新數據的地方,記錄數據頁的物理修改。
redo log通常是物理日志,記錄的是數據頁的物理修改,而不是記錄某一行或某幾行的修改,它用來恢復提交后的物理數據頁(恢復數據頁,且只能恢復到最后一次提交的位置)。
在innoDB的存儲引擎中,事務日志通過重做日志(redo log)和innoDB存儲引擎的日志緩沖(redo Log Buffer)實現。事務開啟時,事務中的操作,都會先寫入存儲引擎的日志緩沖中,在事務提交之前,這些緩沖的日志都需要提前刷新到磁盤上持久化,這就是DBA們口中常說的“日志先行”(Write-Ahead Logging)。當事務提交之后,在Buffer Pool中映射的數據文件才會慢慢刷新到磁盤。此時如果數據庫崩潰或者宕機,那么當系統重啟進行恢復時,就可以根據redo log中記錄的日志,把數據庫恢復到崩潰前的一個狀態。未完成的事務,可以繼續提交,也可以選擇回滾,這基于恢復的策略而定。
即事務在修改數據時,innodb只修改數據的內存拷貝,然后把修改行為記錄到持久在磁盤的事務日志(redo log)中,在事務日志持久化后,內存中被修改的數據在后臺慢慢刷回磁盤。
即修改數據時需要寫兩次磁盤:
- 先將操作記錄到redo log buffer,然后持久化redo log到磁盤
- 將redo log中記錄的數據持久化到磁盤
為什么需要redo log(為什么采用兩次寫磁盤,而不直接持久化新數據?)
既然redo log是將數據持久化到磁盤上,那么必然也對應一次IO操作,那么每次修改數據直接將其刷新到磁盤的話,也是一次IO操作,按道理說效率應該一樣,那么為什么還要引入redo log?
事實上,redo log寫入文件尾是順序寫過程,雖然也是一次IO操作但磁頭不需要移動(即事務日志采用追加的方式,因此是順序IO)。而每次都將數據更新到磁盤其實是將 buffer pool中的數據緩存頁寫入磁盤的數據也中,其中涉及到要尋找數據頁在哪的操作,這是一個隨機寫過程,需要移動磁頭,磁盤的隨機寫過程更耗時,耗資源,因此引入redo log是很有必要的。
undo log
undo log是用于事務中,在操作數據之前,備份需操作的數據的地方,undo log 記錄數據的邏輯修改。
undo log用來實現事務的原子性,在innodb引擎中還用來實現事務的多版本并發控制。
undo log記錄了數據在每個操作前的狀態,如果事務執行過程中需要回滾,就可以根據undo log進行回滾操作。單個事務的回滾,只會回滾當前事務做的操作,并不會影響到其他的事務做的操作。
即在操作數據庫之前先將數據備份到一個地方,這個存儲數據備份的地方就是undo log。然后再進行數據的修改,如果中途發生錯誤或者用戶執行的rollback語句,系統就可以利用undo log中的備份將數據回復到事務開始前的狀態。
undo log 是邏輯日志,可以理解為每次操作之前都會記錄相反反操作:
- 當delect一條語句時,undo log 中會記錄一條對應的insert語句
- 當insert一條語句時,undo log 中會記錄一條對應的delect語句
- 當update一條語句時,undo log 中會記錄一條相反的update語句
undo+redo事務的簡化過程
假設有2個數值,分別為A和B,值為1,2
1. start transaction;2. 記錄 A=1 到undo log;3. update A = 3;4. 記錄 A=3 到redo log buffer;5. 記錄 B=2 到undo log;6. update B = 4;7. 記錄B = 4 到redo log buffer;8. 將redo log buffer 刷新到磁盤9. 執行器(Server層)生成寫操作的binlog日志,并將binlog寫入磁盤(通過XA事務保證redo log 和 binlog的一致性)10. commit在1-8的任意一步系統宕機,事務未提交,該事務就不會對磁盤上的數據做任何影響。如果在8-10之間宕機,恢復之后可以選擇回滾,也可以選擇繼續完成事務提交,因為此時redo log已經持久化。若在10之后系統宕機,內存映射中變更的數據還來不及刷回磁盤,那么系統恢復之后,可以根據redo log把數據刷回磁盤。
所以,redo log其實保障的是事務的持久性和一致性,而undo log則保障了事務的原子性。
binlog
binlog是server層的日志,記錄所有數據庫表結構變更(例如CREATE、ALTER TABLE…)以及表數據修改(INSERT、UPDATE、DELETE…)的二進制日志。
當執行寫操作的SQL(INSERT、UPDATE、DELETE…)時,會把相應的SQL寫入到對應的binlog,可以簡單理解為binlog是記錄數據庫增刪改,不記錄查詢的二進制日志,可以利用binlog進行備份、數據恢復。
binlog的三種模式
(1)Row Level 行模式
日志中會記錄每一行數據被修改的形式,然后在slave端再對相同的數據進行修改
- 優點:在row level模式下,bin-log中可以不記錄執行的sql語句的上下文相關的信息,僅僅只需要記錄那一條被修改。所以rowlevel的日志內容會非常清楚的記錄下每一行數據修改的細節。不會出現某些特定的情況下的存儲過程或function,以及trigger的調用和觸發無法被正確復制的問題
- 缺點:row level,所有的執行的語句當記錄到日志中的時候,都將以每行記錄的修改來記錄,會產生大量的日志內容。
(2)Statement Level(默認)
每一條會修改數據的sql都會記錄到master的bin-log中。slave在復制的時候sql進程會解析成和原來master端執行過的相同的sql來再次執行
- 優點:statement level下的優點首先就是解決了row level下的缺點,不需要記錄每一行數據的變化,減少bin-log日志量,節約IO,提高性能,因為它只需要在Master上鎖執行的語句的細節,以及執行語句的上下文的信息。
- 缺點:由于只記錄語句,所以,在statement level下 已經發現了有不少情況會造成Mysql的復制出現問題,主要是修改數據的時候使用了某些定的函數或者功能的時候會出現。
(3) Mixed 自動模式
在Mixed模式下,MySQL會根據執行的每一條具體的sql語句來區分對待記錄的日志格式,也就是在Statement和Row之間選擇一種。如果sql語句確實就是update或者delete等修改數據的語句,那么還是會記錄所有行的變更。
binlog與redolog 的區別
- binlog主要用于備份、主從同步;redo log用于實現事務的一致性和持久性,防止數據丟失。
- redo log 是innodb引擎特有的,而binlog由服務層實現是所有存儲引擎都可以使用的
- redo log是物理日志,記錄的是某頁上具體的做的修改。binlog是邏輯日志,記錄的是這個語句的原始邏輯。
- redo log是循環寫過程,空間有限,空間不夠時會覆蓋之前的信息。binlog是追加寫過程不會覆蓋之前的信息。
執行器(Server)和InnoDB引擎在執行update內部流程
1、執行器先找到ID=2這一行,ID是主鍵,引擎用樹搜索找到這一行,如果ID=2這一行所在的數據頁本來就在內存中,就直接返回給執行器。否則需要從磁盤中讀入磁盤中,然后再返回。
2、執行器拿到引擎給的行數據,把這個值加上1,得到一行新的數據,再調用引擎接口,寫入這行數據。
3、引擎將這行新的數據寫入到內存中,同時將這個更新操作記錄到redo log里面,此時redo log處于prepare狀態,然后告知執行器執行完成了,隨時可以提交事務。
4、執行器生成這個操作的binlog日志,并將binlog寫入磁盤。
5、執行器調用引擎的提交事務的接口,引擎把剛剛寫入的redo log改成提交(commit)狀態,更新完成。
binlog 和 redo log一致性
此部分為引用,詳細請閱讀:MySQL中binlog和redo log的一致性問題
在MySQL內部,在事務提交時利用兩階段提交(內部XA的兩階段提交)很好地解決了binlog和redo log的一致性問題:
- 第一階段: InnoDB Prepare階段。此時SQL已經成功執行,并生成事務ID(xid)信息及redo和undo的內存日志。此階段InnoDB會寫事務的redo log,但要注意的是,此時redo log只是記錄了事務的所有操作日志,并沒有記錄提交(commit)日志,因此事務此時的狀態為Prepare。此階段對binlog不會有任何操作。
- 第二階段:commit 階段,這個階段又分成兩個步驟。第一步寫binlog(先調用write()將binlog內存日志數據寫入文件系統緩存,再調用fsync()將binlog文件系統緩存日志數據永久寫入磁盤);第二步完成事務的提交(commit),此時在redo log中記錄此事務的提交日志(增加commit 標簽)。
可以看出,此過程中是先寫redo log再寫binlog的。但需要注意的是,在第一階段并沒有記錄完整的redo log(不包含事務的commit標簽),而是在第二階段記錄完binlog后再寫入redo log的commit 標簽。還要注意的是,在這個過程中是以第二階段中binlog的寫入與否作為事務是否成功提交的標志。
通過上述MySQL內部XA的兩階段提交就可以解決binlog和redo log的一致性問題。數據庫在上述任何階段crash,主從庫都不會產生不一致的錯誤。
參考
- 推薦閱讀:MYSQL中的事務日志
- 推薦閱讀:日志系統:redo log和binlog
- 好文:MySQL中的事務日志
- 詳細分析MySQL事務日志(redo log和undo log)
- MySQL binlog三種模式
- 深入理解MySQL之redo日志
總結
以上是生活随笔為你收集整理的MySQL日志:binlog、事务日志(redo、undo)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 简单分析KafKa工作原理
- 下一篇: pw域名怎么免费注册(pw域名不能注册了