<acronym id="s8ci2"><small id="s8ci2"></small></acronym>
<rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
<acronym id="s8ci2"></acronym>
<acronym id="s8ci2"><center id="s8ci2"></center></acronym>
0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

詳解MySQL三大日志的作用

Linux愛好者 ? 來源:CSDN技術社區 ? 作者:佳冪小煜 ? 2022-07-22 14:44 ? 次閱讀

前言

MySQL日志 主要包括錯誤日志、查詢日志、慢查詢日志、事務日志、二進制日志幾大類。其中,比較重要的還要屬二進制日志 binlog(歸檔日志)和事務日志 redo log(重做日志)和 undo log(回滾日志)。9b9b29da-0972-11ed-ba43-dac502259ad0.png

今天就來聊聊 redo log(重做日志)、binlog(歸檔日志)、兩階段提交、undo log (回滾日志)。

redo log

redo log(重做日志)是InnoDB存儲引擎獨有的,它讓MySQL擁有了崩潰恢復能力。

比如 MySQL 實例掛了或宕機了,重啟時,InnoDB存儲引擎會使用redo log恢復數據,保證數據的持久性與完整性。

9baa3fec-0972-11ed-ba43-dac502259ad0.png

MySQL 中數據是以頁為單位,你查詢一條記錄,會從硬盤把一頁的數據加載出來,加載出來的數據叫數據頁,會放入到 Buffer Pool 中。

后續的查詢都是先從 Buffer Pool 中找,沒有命中再去硬盤加載,減少硬盤 IO 開銷,提升性能。

更新表數據的時候,也是如此,發現 Buffer Pool 里存在要更新的數據,就直接在 Buffer Pool 里更新。

然后會把“在某個數據頁上做了什么修改”記錄到重做日志緩存(redo log buffer)里,接著刷盤到 redo log 文件里。

9bbc01f0-0972-11ed-ba43-dac502259ad0.png

理想情況,事務一提交就會進行刷盤操作,但實際上,刷盤的時機是根據策略來進行的。

小貼士:每條 redo 記錄由“表空間號+數據頁號+偏移量+修改數據長度+具體修改的數據”組成

刷盤時機

InnoDB 存儲引擎為 redo log 的刷盤策略提供了 innodb_flush_log_at_trx_commit 參數,它支持三種策略:

  • 0 :設置為 0 的時候,表示每次事務提交時不進行刷盤操作
  • 1 :設置為 1 的時候,表示每次事務提交時都將進行刷盤操作(默認值)
  • 2 :設置為 2 的時候,表示每次事務提交時都只把 redo log buffer 內容寫入 page cache

innodb_flush_log_at_trx_commit 參數默認為 1 ,也就是說當事務提交時會調用 fsync 對 redo log 進行刷盤

另外,InnoDB 存儲引擎有一個后臺線程,每隔1 秒,就會把 redo log buffer 中的內容寫到文件系統緩存(page cache),然后調用 fsync 刷盤。

9bd561f4-0972-11ed-ba43-dac502259ad0.png

也就是說,一個沒有提交事務的 redo log 記錄,也可能會刷盤。

為什么呢?

因為在事務執行過程 redo log 記錄是會寫入redo log buffer 中,這些 redo log 記錄會被后臺線程刷盤。

9bf23a72-0972-11ed-ba43-dac502259ad0.png

除了后臺線程每秒1次的輪詢操作,還有一種情況,當 redo log buffer 占用的空間即將達到 innodb_log_buffer_size 一半的時候,后臺線程會主動刷盤。

下面是不同刷盤策略的流程圖。

innodb_flush_log_at_trx_commit=0

9c12db60-0972-11ed-ba43-dac502259ad0.png

0時,如果MySQL掛了或宕機可能會有1秒數據的丟失。

innodb_flush_log_at_trx_commit=1

9c261ef0-0972-11ed-ba43-dac502259ad0.png

1時, 只要事務提交成功,redo log記錄就一定在硬盤里,不會有任何數據丟失。

如果事務執行期間MySQL掛了或宕機,這部分日志丟了,但是事務并沒有提交,所以日志丟了也不會有損失。

innodb_flush_log_at_trx_commit=2

9c47c56e-0972-11ed-ba43-dac502259ad0.png

2時, 只要事務提交成功,redo log buffer中的內容只寫入文件系統緩存(page cache)。

如果僅僅只是MySQL掛了不會有任何數據丟失,但是宕機可能會有1秒數據的丟失。

日志文件組

硬盤上存儲的 redo log 日志文件不只一個,而是以一個日志文件組的形式出現的,每個的redo日志文件大小都是一樣的。

比如可以配置為一組4個文件,每個文件的大小是 1GB,整個 redo log 日志文件組可以記錄4G的內容。

它采用的是環形數組形式,從頭開始寫,寫到末尾又回到頭循環寫,如下圖所示。

9c5ac3ee-0972-11ed-ba43-dac502259ad0.png

在個日志文件組中還有兩個重要的屬性,分別是 write pos、checkpoint

  • write pos 是當前記錄的位置,一邊寫一邊后移
  • checkpoint 是當前要擦除的位置,也是往后推移

每次刷盤 redo log 記錄到日志文件組中,write pos 位置就會后移更新。

每次 MySQL 加載日志文件組恢復數據時,會清空加載過的 redo log 記錄,并把 checkpoint 后移更新。

write poscheckpoint 之間的還空著的部分可以用來寫入新的 redo log 記錄。

9c70a5ba-0972-11ed-ba43-dac502259ad0.png

如果 write pos 追上 checkpoint ,表示日志文件組滿了,這時候不能再寫入新的 redo log 記錄,MySQL 得停下來,清空一些記錄,把 checkpoint 推進一下。

9c91a2ce-0972-11ed-ba43-dac502259ad0.png

redo log 小結

相信大家都知道 redo log 的作用和它的刷盤時機、存儲形式。

現在我們來思考一個問題:只要每次把修改后的數據頁直接刷盤不就好了,還有 redo log 什么事?

它們不都是刷盤么?差別在哪里?

1Byte=8bit
1KB=1024Byte
1MB=1024KB
1GB=1024MB
1TB=1024GB

實際上,數據頁大小是16KB,刷盤比較耗時,可能就修改了數據頁里的幾 Byte 數據,有必要把完整的數據頁刷盤嗎?

而且數據頁刷盤是隨機寫,因為一個數據頁對應的位置可能在硬盤文件的隨機位置,所以性能是很差。

如果是寫 redo log,一行記錄可能就占幾十 Byte,只包含表空間號、數據頁號、磁盤文件偏移量、更新值,再加上是順序寫,所以刷盤速度很快。

所以用 redo log 形式記錄修改內容,性能會遠遠超過刷數據頁的方式,這也讓數據庫的并發能力更強。

其實內存的數據頁在一定時機也會刷盤,我們把這稱為頁合并,講 Buffer Pool的時候會對這塊細說

binlog

redo log 它是物理日志,記錄內容是“在某個數據頁上做了什么修改”,屬于 InnoDB 存儲引擎。

binlog 是邏輯日志,記錄內容是語句的原始邏輯,類似于“給 ID=2 這一行的 c 字段加 1”,屬于MySQL Server 層。

不管用什么存儲引擎,只要發生了表數據更新,都會產生 binlog 日志。

binlog 到底是用來干嘛的?

可以說MySQL數據庫的數據備份、主備、主主、主從都離不開binlog,需要依靠binlog來同步數據,保證數據一致性。

9ca0cff6-0972-11ed-ba43-dac502259ad0.png

binlog會記錄所有涉及更新數據的邏輯操作,并且是順序寫。

記錄格式

binlog 日志有三種格式,可以通過binlog_format參數指定。

  • statement
  • row
  • mixed

指定statement,記錄的內容是SQL語句原文,比如執行一條update T set update_time=now() where id=1,記錄的內容如下。

9caf3500-0972-11ed-ba43-dac502259ad0.png

同步數據時,會執行記錄的SQL語句,但是有個問題,update_time=now()這里會獲取當前系統時間,直接執行會導致與原庫的數據不一致。

為了解決這種問題,我們需要指定為row,記錄的內容不再是簡單的SQL語句了,還包含操作的具體數據,記錄內容如下。

9cbcc86e-0972-11ed-ba43-dac502259ad0.png

row格式記錄的內容看不到詳細信息,要通過mysqlbinlog工具解析出來。

update_time=now()變成了具體的時間update_time=1627112756247,條件后面的@1、@2、@3 都是該行數據第 1 個~3 個字段的原始值(假設這張表只有 3 個字段)。

這樣就能保證同步數據的一致性,通常情況下都是指定為row,這樣可以為數據庫的恢復與同步帶來更好的可靠性。

但是這種格式,需要更大的容量來記錄,比較占用空間,恢復與同步時會更消耗IO資源,影響執行速度。

所以就有了一種折中的方案,指定為mixed,記錄的內容是前兩者的混合。

MySQL會判斷這條SQL語句是否可能引起數據不一致,如果是,就用row格式,否則就用statement格式。

寫入機制

binlog的寫入時機也非常簡單,事務執行過程中,先把日志寫到binlog cache,事務提交的時候,再把binlog cache寫到binlog文件中。

因為一個事務的binlog不能被拆開,無論這個事務多大,也要確保一次性寫入,所以系統會給每個線程分配一個塊內存作為binlog cache。

我們可以通過binlog_cache_size參數控制單個線程 binlog cache 大小,如果存儲內容超過了這個參數,就要暫存到磁盤(Swap)。

binlog日志刷盤流程如下

9ccc51e4-0972-11ed-ba43-dac502259ad0.png
  • 上圖的 write,是指把日志寫入到文件系統的 page cache,并沒有把數據持久化到磁盤,所以速度比較快
  • 上圖的 fsync,才是將數據持久化到磁盤的操作

writefsync的時機,可以由參數sync_binlog控制,默認是0。

0的時候,表示每次提交事務都只write,由系統自行判斷什么時候執行fsync。

9d29c98c-0972-11ed-ba43-dac502259ad0.png

雖然性能得到提升,但是機器宕機,page cache里面的 binglog 會丟失。

為了安全起見,可以設置為1,表示每次提交事務都會執行fsync,就如同binlog 日志刷盤流程一樣。

最后還有一種折中方式,可以設置為N(N>1),表示每次提交事務都write,但累積N個事務后才fsync。

9d3dfb00-0972-11ed-ba43-dac502259ad0.png

在出現IO瓶頸的場景里,將sync_binlog設置成一個比較大的值,可以提升性能。

同樣的,如果機器宕機,會丟失最近N個事務的binlog日志。

兩階段提交

redo log(重做日志)讓InnoDB存儲引擎擁有了崩潰恢復能力。

binlog(歸檔日志)保證了MySQL集群架構的數據一致性。

雖然它們都屬于持久化的保證,但是則重點不同。

在執行更新語句過程,會記錄redo logbinlog兩塊日志,以基本的事務為單位,redo log在事務執行過程中可以不斷寫入,而binlog只有在提交事務時才寫入,所以redo logbinlog的寫入時機不一樣。

9d51646a-0972-11ed-ba43-dac502259ad0.png

回到正題,redo logbinlog兩份日志之間的邏輯不一致,會出現什么問題?

我們以update語句為例,假設id=2的記錄,字段c值是0,把字段c值更新成1,SQL語句為update T set c=1 where id=2。

假設執行過程中寫完redo log日志后,binlog日志寫期間發生了異常,會出現什么情況呢?

9d69807c-0972-11ed-ba43-dac502259ad0.png

由于binlog沒寫完就異常,這時候binlog里面沒有對應的修改記錄。因此,之后用binlog日志恢復數據時,就會少這一次更新,恢復出來的這一行c值是0,而原庫因為redo log日志恢復,這一行c值是1,最終數據不一致。

9d7a780a-0972-11ed-ba43-dac502259ad0.png

為了解決兩份日志之間的邏輯一致問題,InnoDB存儲引擎使用兩階段提交方案。

原理很簡單,將redo log的寫入拆成了兩個步驟preparecommit,這就是兩階段提交。

9d9a86e0-0972-11ed-ba43-dac502259ad0.png

使用兩階段提交后,寫入binlog時發生異常也不會有影響,因為MySQL根據redo log日志恢復數據時,發現redo log還處于prepare階段,并且沒有對應binlog日志,就會回滾該事務。

9db45a20-0972-11ed-ba43-dac502259ad0.png

再看一個場景,redo log設置commit階段發生異常,那會不會回滾事務呢?

9dd12f92-0972-11ed-ba43-dac502259ad0.png

并不會回滾事務,它會執行上圖框住的邏輯,雖然redo log是處于prepare階段,但是能通過事務id找到對應的binlog日志,所以MySQL認為是完整的,就會提交事務恢復數據。

undo log

數據庫事務四大特性中有一個是原子性,具體來說就是原子性是指對數據庫的一系列操作,要么全部成功,要么全部失敗,不可能出現部分成功的情況。

我們知道如果想要保證事務的原子性,就需要在異常發生時,對已經執行的操作進行回滾,在 MySQL 中,恢復機制是通過 回滾日志(undo log) 實現的,所有事務進行的修改都會先先記錄到這個回滾日志中,然后再執行相關的操作。

如果執行過程中遇到異常的話,我們直接利用 回滾日志 中的信息將數據回滾到修改之前的樣子即可!并且,回滾日志會先于數據持久化到磁盤上。這樣就保證了即使遇到數據庫突然宕機等情況,當用戶再次啟動數據庫的時候,數據庫還能夠通過查詢回滾日志來回滾將之前未完成的事務。

另外,MVCC 的實現依賴于:隱藏字段、Read View、undo log。在內部實現中,InnoDB 通過數據行的 DB_TRX_IDRead View 來判斷數據的可見性,如不可見,則通過數據行的 DB_ROLL_PTR 找到 undo log 中的歷史版本。

每個事務讀到的數據版本可能是不一樣的,在同一個事務中,用戶只能看到該事務創建 Read View 之前已經提交的修改和該事務本身做的修改。

總結

MySQL InnoDB 引擎使用 redo log(重做日志) 保證事務的持久性,使用 undo log(回滾日志) 來保證事務的原子性。

MySQL數據庫的數據備份、主備、主主、主從都離不開binlog,需要依靠binlog來同步數據,保證數據一致性。

審核編輯:湯梓紅


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • MySQL
    +關注

    關注

    1

    文章

    776

    瀏覽量

    26050
  • 日志
    +關注

    關注

    0

    文章

    126

    瀏覽量

    10537
  • binlog
    +關注

    關注

    0

    文章

    6

    瀏覽量

    1220

原文標題:大廠基本功 | MySQL 三大日志 ( binlog、redo log 和 undo log ) 的作用?

文章出處:【微信號:LinuxHub,微信公眾號:Linux愛好者】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    干貨分享:MySQL零基礎入門視頻教程!

    零基礎入門視頻教程,希望能幫助到大家!課程目錄:一、 MySQL課程介紹和MySQL的基礎概念(1)二、 MySQL基礎概念之存儲引擎(2)、 M
    發表于 06-22 14:22

    0基礎學Mysql:mysql入門視頻教程!

    0基礎學Mysql:mysql入門視頻教程!目前MySQL技術雖然在國內發展了許多年,但是一直都沒有形成一個專門的學科,MySQL的數據庫,在很多中小企業的流行做法就是讓程序員來管。但
    發表于 07-08 10:51

    干貨分享:MySQL零基礎入門視頻教程

    ! 課程目錄: 一、 MySQL課程介紹和MySQL的基礎概念(1)二、 MySQL基礎概念之存儲引擎(2)、 MySQL基本安裝使用四、
    發表于 07-27 13:57

    MySQL零基礎入門視頻教程!

    教程,MySQL零基礎入門視頻教程,希望能幫助到大家!課程目錄:一、 MySQL課程介紹和MySQL的基礎概念(1)二、 MySQL基礎概念之存儲引擎(2)
    發表于 08-13 11:39

    MySQL的六個日志類型

    MySQL日志管理
    發表于 04-24 16:57

    概述Mysql的分區

    Mysql的分區詳解
    發表于 07-15 17:10

    日志系統在應用中的重要作用

    日志系統在應用中的重要作用  日志系統管理的意義     在一個完整的信息系統里面,日志系統是一個非常重要的
    發表于 01-29 14:01 ?9089次閱讀

    詳談MySQL數據庫的不同日志和源碼

    任何一種數據庫,都會擁有各種各樣的日志,mysql也不例外。
    的頭像 發表于 07-02 16:52 ?2410次閱讀

    MySQL事務日志

    大家都清楚,日志MySQL 數據庫的重要組成部分,記錄著數據庫運行期間各種狀態信息。MySQL 日志主要包括「錯誤日志」、「查詢
    的頭像 發表于 11-14 09:58 ?1569次閱讀
    <b class='flag-5'>MySQL</b>事務<b class='flag-5'>日志</b>

    MySQL中的redo log是什么

    前言 說到MySQL,有兩塊日志一定繞不開,一個是InnoDB存儲引擎的redo log(重做日志),另一個是MySQL Servce層的 binlog(歸檔
    的頭像 發表于 09-14 09:40 ?1806次閱讀

    關于Mysql的20道問題詳解

    1.什么Mysql的事務?事務的四大特性?事務帶來的什么問題? Mysql中事務的隔離級別分為四大等級:讀未提交(READ UNCOMMITTED)、讀提交 (READ COMMITTED)、可重復
    的頭像 發表于 10-26 09:56 ?1294次閱讀
    關于<b class='flag-5'>Mysql</b>的20道問題<b class='flag-5'>詳解</b>

    基于mysql自有方式采集獲取監控數據

    我們常聽 MySQL 中有二進制日志 binlog、中繼日志 relaylog、重做回滾日志 redolog、undolog 等。針對慢查詢,還有一種慢查詢
    發表于 12-30 10:56 ?301次閱讀

    MySQL三種日志講解

    MySQL 日志包含了錯誤日志、查詢日志、慢查詢日志、事務日志、二進制
    的頭像 發表于 07-25 11:15 ?476次閱讀
    <b class='flag-5'>MySQL</b>三種<b class='flag-5'>日志</b>講解

    MYSQL事務的底層原理詳解

    在事務的實現機制上,MySQL 采用的是 WAL:Write-ahead logging,預寫式日志,機制來實現的。
    的頭像 發表于 11-15 10:10 ?251次閱讀
    <b class='flag-5'>MYSQL</b>事務的底層原理<b class='flag-5'>詳解</b>

    oracle數據庫alert日志作用

    Oracle數據庫的alert日志是數據庫引擎和實例的核心組件之一,它記錄著數據庫的運行狀況和事件。該日志對于數據庫的性能調優、問題排查和安全管理起著重要作用。本文將詳盡、詳實、細致地介紹
    的頭像 發表于 12-06 10:08 ?393次閱讀
    亚洲欧美日韩精品久久_久久精品AⅤ无码中文_日本中文字幕有码在线播放_亚洲视频高清不卡在线观看
    <acronym id="s8ci2"><small id="s8ci2"></small></acronym>
    <rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
    <acronym id="s8ci2"></acronym>
    <acronym id="s8ci2"><center id="s8ci2"></center></acronym>