天天看點

MySql 事務實作機制 幾種日志undo log、 binlog、redo log

你知道MySQL的原子性是怎麼保證的嗎?

誰都知道在事務裡邊原子性的意思:”一個事務包含多個操作,這些操作要麼全部執行,要麼全都不執行“

事務保證需要用到一下幾個常見 log

  • undo log

  • binlog

  • redo log

一、什麼是binlog

  binlog

其實在日常的開發中是聽得很多的,因為很多時候資料的更新就依賴着

binlog

  舉個很簡單的例子:我們的資料是儲存在資料庫裡邊的嘛,現在我們對某個商品的某個字段的内容改了(資料庫變更),而使用者檢索的出來資料是走搜尋引擎的。為了讓使用者能搜到最新的資料,我們需要把引擎的資料也改掉。

一句話:資料庫的變更,搜尋引擎的資料也需要變更。

于是,我們就會監聽

binlog

的變更,如果

binlog

有變更了,那我們就需要将變更寫到對應的資料源。

什麼是

binlog

binlog

記錄了資料庫表結構和表資料變更,比如

update/delete/insert/truncate/create

。它不會記錄

select

(因為這沒有對表沒有進行變更)

binlog

長什麼樣?

binlog

我們可以簡單了解為:存儲着每條變更的

SQL

語句(當然從下面的圖看來看,不止SQL,還有XID「事務Id」等等)

MySql 事務實作機制 幾種日志undo log、 binlog、redo log

binlog

一般用來做什麼

主要有兩個作用:複制和恢複資料

  • MySQL在公司使用的時候往往都是一主多從結構的,從伺服器需要與主伺服器的資料保持一緻,這就是通過

    binlog

    來實作的
  • 資料庫的資料被幹掉了,我們可以通過

    binlog

    來對資料進行恢複。

因為

binlog

記錄了資料庫表的變更,是以我們可以用

binlog

進行複制(主從複制)和恢複資料。

二、什麼是redo log

假設我們有一條sql語句:

update user_table set name='java3y' where id = '3'      

MySQL執行這條SQL語句,肯定是先把

id=3

的這條記錄查出來,然後将

name

字段給改掉。這沒問題吧?

實際上Mysql的基本存儲結構是頁(記錄都存在頁裡邊),是以MySQL是先把這條記錄所在的頁找到,然後把該頁加載到記憶體中,将對應記錄進行修改。

現在就可能存在一個問題:如果在記憶體中把資料改了,還沒來得及落磁盤,而此時的資料庫挂了怎麼辦?顯然這次更改就丢了。

MySql 事務實作機制 幾種日志undo log、 binlog、redo log

如果每個請求都需要将資料立馬落磁盤之後,那速度會很慢,MySQL可能也頂不住。是以MySQL是怎麼做的呢?

MySQL引入了

redo log

,記憶體寫完了,然後會寫一份

redo log

,這份

redo log

記載着這次在某個頁上做了什麼修改。

MySql 事務實作機制 幾種日志undo log、 binlog、redo log

  其實寫

redo log

的時候,也會有

buffer

,是先寫

buffer

,再真正落到磁盤中的。至于從

buffer

什麼時候落磁盤,會有配置供我們配置。

MySql 事務實作機制 幾種日志undo log、 binlog、redo log

    寫

redo log

也是需要寫磁盤的,但它的好處就是

順序IO

(我們都知道順序IO比随機IO快非常多)。

  是以,

redo log

的存在為了:當我們修改的時候,寫完記憶體了,但資料還沒真正寫到磁盤的時候。此時我們的資料庫挂了,我們可以根據

redo log

來對資料進行恢複。因為

redo log

是順序IO,是以寫入的速度很快,并且

redo log

記載的是實體變化(xxxx頁做了xxx修改),檔案的體積很小,恢複速度很快。

三、binlog和redo log

看到這裡,你可能會想:

binlog

redo log

 這倆也太像了吧,都是用作”恢複“的。

其實他倆除了"恢複"這塊是相似的,很多都不一樣,下面看我列一下。

存儲的内容

binlog

記載的是

update/delete/insert

這樣的SQL語句,而

redo log

記載的是實體修改的内容(xxxx頁修改了xxx)。

是以在搜尋資料的時候會有這樣的說法:

redo log

 記錄的是資料的實體變化,

binlog

 記錄的是資料的邏輯變化

功能

redo log

的作用是為持久化而生的。寫完記憶體,如果資料庫挂了,那我們可以通過

redo log

來恢複記憶體還沒來得及刷到磁盤的資料,将

redo log

加載到記憶體裡邊,那記憶體就能恢複到挂掉之前的資料了。

binlog

的作用是複制和恢複而生的。

  • 主從伺服器需要保持資料的一緻性,通過

    binlog

    來同步資料。
  • 如果整個資料庫的資料都被删除了,

    binlog

    存儲着所有的資料變更情況,那麼可以通過

    binlog

又看到這裡,你會想:”如果整個資料庫的資料都被删除了,那我可以用

redo log

的記錄來恢複嗎?“不能

因為功能的不同,

redo log

 存儲的是實體資料的變更,如果我們記憶體的資料已經刷到了磁盤了,那

redo log

的資料就無效了。是以

redo log

不會存儲着曆史所有資料的變更,檔案的内容會被覆寫的。

binlog和redo log 寫入的細節

redo log

是MySQL的InnoDB引擎所産生的。

binlog

無論MySQL用什麼引擎,都會有的。

InnoDB是有事務的,事務的四大特性之一:持久性就是靠

redo log

來實作的(如果寫入記憶體成功,但資料還沒真正刷到磁盤,如果此時的資料庫挂了,我們可以靠

redo log

來恢複記憶體的資料,這就實作了持久性)。

上面也提到,在修改的資料的時候,

binlog

會記載着變更的類容,

redo log

也會記載着變更的内容。(隻不過一個存儲的是實體變化,一個存儲的是邏輯變化)。那他們的寫入順序是什麼樣的呢?

redo log

事務開始的時候,就開始記錄每次的變更資訊,而

binlog

是在事務送出的時候才記錄。

于是新有的問題又出現了:我寫其中的某一個

log

,失敗了,那會怎麼辦?現在我們的前提是先寫

redo log

,再寫

binlog

,我們來看看:

  • 如果寫

    redo log

    失敗了,那我們就認為這次事務有問題,復原,不再寫

    binlog

  • redo log

    成功了,寫

    binlog

    ,寫

    binlog

    寫一半了,但失敗了怎麼辦?我們還是會對這次的事務復原,将無效的

    binlog

    給删除(因為

    binlog

    會影響從庫的資料,是以需要做删除操作)
  • redo log

    binlog

    都成功了,那這次算是事務才會真正成功。

簡單來說:MySQL需要保證

redo log

binlog

的資料是一緻的,如果不一緻,那就亂套了。

  • 如果

    redo log

    寫失敗了,而

    binlog

    寫成功了。那假設記憶體的資料還沒來得及落磁盤,機器就挂掉了。那主從伺服器的資料就不一緻了。(從伺服器通過

    binlog

    得到最新的資料,而主伺服器由于

    redo log

    沒有記載,沒法恢複資料)
  • redo log

    寫成功了,而

    binlog

    寫失敗了。那從伺服器就拿不到最新的資料了。

MySQL通過兩階段送出來保證

redo log

binlog

的資料是一緻的。

MySql 事務實作機制 幾種日志undo log、 binlog、redo log

  過程:

  • 階段1:InnoDB

    redo log

     寫盤,InnoDB 事務進入 

    prepare

     狀态
  • 階段2:

    binlog

     寫盤,InooDB 事務進入 

    commit

  • 每個事務

    binlog

    的末尾,會記錄一個 

    XID event

    ,标志着事務是否送出成功,也就是說,恢複過程中,

    binlog

     最後一個 XID event 之後的内容都應該被 purge。
MySql 事務實作機制 幾種日志undo log、 binlog、redo log

四、什麼是undo log

undo log

有什麼用?

undo log

主要有兩個作用:復原和多版本控制(MVCC)

在資料修改的時候,不僅記錄了

redo log

,還記錄

undo log

,如果因為某些原因導緻事務失敗或復原了,可以用

undo log

進行復原

undo log

主要存儲的也是邏輯日志,比如我們要

insert

一條資料了,那

undo log

會記錄的一條對應的

delete

日志。我們要

update

一條記錄時,它會記錄一條對應相反的update記錄。

這也應該容易了解,畢竟復原嘛,跟需要修改的操作相反就好,這樣就能達到復原的目的。因為支援復原操作,是以我們就能保證:“一個事務包含多個操作,這些操作要麼全部執行,要麼全都不執行”。【原子性】

undo log

存儲着修改之前的資料,相當于一個前版本,MVCC實作的是讀寫不阻塞,讀的時候隻要傳回前一個版本的資料就行了。

最後

  這篇文章把

binlog

 /

redo log

/

undo log

最核心的知識給講了,還有一些細節性的東西可以自行去補充(比如

binlog

有幾種的模式,以及文章提到的刷盤政策等等)

參考資料:

  • https://www.jianshu.com/p/4bcfffb27ed5
  • https://yq.aliyun.com/articles/617335
  • MySQL的ACID原理!
  • MySQL 是如何實作 ACID 中的 D 的?
  • https://www.cnblogs.com/myseries/p/10728533.html