沒想到MySQL還會問這些…

  • 2020 年 3 月 10 日
  • 筆記

前言

文本已收錄至我的GitHub精選文章,歡迎Starhttps://github.com/ZhongFuCheng3y/3y

在前一陣子,大哥問過我:」你知道MySQL的原子性是怎麼保證的嗎「。我懵逼了,MySQL怎麼保證原子性?我不會啊。

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

於是大哥就給我講:」用的就是 undo log 啊「。

我:」卧槽,又是知識盲區「

後來在網上翻了一下,MySQL裡邊還有幾種常見的log,分別為:

  • undo log
  • binlog
  • redo log

如果你也未曾關注過這些log,麻煩在評論區給我留個言,讓我覺得不是只有我一個人這麼菜,行不行

後來我又去搜了一下,其實這幾種log在面試的時候也經常會問到,這篇文章以最簡單的方式來講講,希望對大家有幫助。

一、什麼是binlog

binlog其實在日常的開發中是聽得很多的,因為很多時候數據的更新就依賴著binlog

舉個很簡單的例子:我們的數據是保存在資料庫裡邊的嘛,現在我們對某個商品的某個欄位的內容改了(資料庫變更),而用戶檢索的出來數據是走搜索引擎的。為了讓用戶能搜到最新的數據,我們需要把引擎的數據也改掉。

一句話:資料庫的變更,搜索引擎的數據也需要變更

於是,我們就會監聽binlog的變更,如果binlog有變更了,那我們就需要將變更寫到對應的數據源。

什麼是binlog

binlog記錄了資料庫表結構和表數據變更,比如update/delete/insert/truncate/create。它不會記錄select(因為這沒有對錶沒有進行變更)

binlog長什麼樣?

binlog我們可以簡單理解為:存儲著每條變更的SQL語句(當然從下面的圖看來看,不止SQL,還有XID「事務Id」等等)

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可能也頂不住。所以MySQL是怎麼做的呢?

MySQL引入了redo log,記憶體寫完了,然後會寫一份redo log,這份redo log記載著這次在某個頁上做了什麼修改

其實寫redo log的時候,也會有buffer,是先寫buffer,再真正落到磁碟中的。至於從buffer什麼時候落磁碟,會有配置供我們配置。

redo log也是需要寫磁碟的,但它的好處就是順序IO(我們都知道順序IO比隨機IO快非常多)。

所以,redo log的存在為了:當我們修改的時候,寫完記憶體了,但數據還沒真正寫到磁碟的時候。此時我們的資料庫掛了,我們可以根據redo log來對數據進行恢復。因為redo log是順序IO,所以寫入的速度很快,並且redo log記載的是物理變化(xxxx頁做了xxx修改),文件的體積很小,恢復速度很快

三、binlog和redo log

看到這裡,你可能會想:binlogredo 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 logbinlog都成功了,那這次算是事務才會真正成功。

簡單來說:MySQL需要保證redo logbinlog數據是一致的,如果不一致,那就亂套了。

  • 如果redo log寫失敗了,而binlog寫成功了。那假設記憶體的數據還沒來得及落磁碟,機器就掛掉了。那主從伺服器的數據就不一致了。(從伺服器通過binlog得到最新的數據,而主伺服器由於redo log沒有記載,沒法恢複數據)
  • 如果redo log寫成功了,而binlog寫失敗了。那從伺服器就拿不到最新的數據了。

MySQL通過兩階段提交來保證redo logbinlog的數據是一致的。

過程:

  • 階段1:InnoDBredo log 寫盤,InnoDB 事務進入 prepare 狀態
  • 階段2:binlog 寫盤,InooDB 事務進入 commit 狀態

  • 每個事務binlog的末尾,會記錄一個 XID event,標誌著事務是否提交成功,也就是說,恢復過程中,binlog 最後一個 XID event 之後的內容都應該被 purge。

四、什麼是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有幾種的模式,以及文章提到的刷盤策略等等)

如果覺得學到了,請給我個贊行不行。

參考資料:

如果大家想要實時關注我更新的文章以及分享的乾貨的話,可以關注我的公眾號「Java3y」。

  • ?Java精美腦圖
  • ?Java學習路線
  • ?開發常用工具

在公眾號下回復「888」即可獲取!!

本已收錄至我的GitHub精選文章,歡迎Starhttps://github.com/ZhongFuCheng3y/3y

求點贊 求關注️ 求分享? 求留言? 對我來說真的 非常有用!!!