91欧美超碰AV自拍|国产成年人性爱视频免费看|亚洲 日韩 欧美一厂二区入|人人看人人爽人人操aV|丝袜美腿视频一区二区在线看|人人操人人爽人人爱|婷婷五月天超碰|97色色欧美亚州A√|另类A√无码精品一级av|欧美特级日韩特级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

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

3天內(nèi)不再提示

MySQL是如何保證數(shù)據(jù)不會丟的

454398 ? 來源: vivo互聯(lián)網(wǎng)技術(shù) ? 作者:xieweipeng ? 2020-10-10 15:30 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

MySQL作為當下最流行的開源關系型數(shù)據(jù)庫,有一個很關鍵和基本的能力,就是必須能夠保證數(shù)據(jù)不會丟。那么在這個能力背后,MySQL是如何設計才能保證不管在什么時間崩潰,恢復后都能保證數(shù)據(jù)不會丟呢?有哪些關鍵技術(shù)支撐了這個能力?本文將為我們一一揭曉。

一、前言

MySQL 保證數(shù)據(jù)不會丟的能力主要體現(xiàn)在兩方面:

能夠恢復到任何時間點的狀態(tài);

能夠保證MySQL在任何時間段突然奔潰,重啟后之前提交的記錄都不會丟失;

對于第一點將MySQL恢復到任何時間點的狀態(tài),相信很多人都知道,只要保留有足夠的binlog,就能通過重跑binlog來實現(xiàn)。

對于第二點的能力,也就是本文標題所講的crash-safe。即在 InnoDB 存儲引擎中,事務提交過程中任何階段,MySQL突然奔潰,重啟后都能保證事務的完整性,已提交的數(shù)據(jù)不會丟失,未提交完整的數(shù)據(jù)會自動進行回滾。這個能力依賴的就是redo log和unod log兩個日志。

因為crash-safe主要體現(xiàn)在事務執(zhí)行過程中突然奔潰,重啟后能保證事務完整性,所以在講解具體原理之前,先了解下MySQL事務執(zhí)行有哪些關鍵階段,后面才能依據(jù)這幾個階段來進行解析。下面以一條更新語句的執(zhí)行流程為例,話不多說,直接上圖:

從上圖可以清晰地看出一條更新語句在MySQL中是怎么執(zhí)行的,簡單進行總結(jié)一下:

從內(nèi)存中找出這條數(shù)據(jù)記錄,對其進行更新;

將對數(shù)據(jù)頁的更改記錄到redo log中;

將邏輯操作記錄到binlog中;

對于內(nèi)存中的數(shù)據(jù)和日志,都是由后臺線程,當觸發(fā)到落盤規(guī)則后再異步進行刷盤;

上面演示了一條更新語句的詳細執(zhí)行過程,接下來咱們通過解答問題,帶著問題來剖析這個crash-safe的設計原理。

二、WAL機制

問題:為什么不直接更改磁盤中的數(shù)據(jù),而要在內(nèi)存中更改,然后還需要寫日志,最后再落盤這么復雜?

這個問題相信很多同學都能猜出來,MySQL更改數(shù)據(jù)的時候,之所以不直接寫磁盤文件中的數(shù)據(jù),最主要就是性能問題。因為直接寫磁盤文件是隨機寫,開銷大性能低,沒辦法滿足MySQL的性能要求。所以才會設計成先在內(nèi)存中對數(shù)據(jù)進行更改,再異步落盤。但是內(nèi)存總是不可靠,萬一斷電重啟,還沒來得及落盤的內(nèi)存數(shù)據(jù)就會丟失,所以還需要加上寫日志這個步驟,萬一斷電重啟,還能通過日志中的記錄進行恢復。

寫日志雖然也是寫磁盤,但是它是順序?qū)?,相比隨機寫開銷更小,能提升語句執(zhí)行的性能(針對順序?qū)憺槭裁幢入S機寫更快,可以比喻為你有一個本子,按照順序一頁一頁寫肯定比寫一個字都要找到對應頁寫快得多)。

這個技術(shù)就是大多數(shù)存儲系統(tǒng)基本都會用的WAL(Write Ahead Log)技術(shù),也稱為日志先行的技術(shù),指的是對數(shù)據(jù)文件進行修改前,必須將修改先記錄日志。保證了數(shù)據(jù)一致性和持久性,并且提升語句執(zhí)行性能。

三、核心日志模塊

問題:更新SQL語句執(zhí)行流程中,總共需要寫3個日志,這3個是不是都需要,能不能進行簡化?

更新SQL執(zhí)行過程中,總共涉及MySQL日志模塊其中的三個核心日志,分別是redo log(重做日志)、undo log(回滾日志)、binlog(歸檔日志)。這里提前預告,crash-safe的能力主要依賴的就是這三大日志。

接下來,針對每個日志將單獨介紹各自的作用,然后再來評估是否能簡化掉。

1、重做日志 redo log

redo log也稱為事務日志,由InnoDB存儲引擎層產(chǎn)生。記錄的是數(shù)據(jù)庫中每個頁的修改,而不是某一行或某幾行修改成怎樣,可以用來恢復提交后的物理數(shù)據(jù)頁(恢復數(shù)據(jù)頁,且只能恢復到最后一次提交的位置,因為修改會覆蓋之前的)。

前面提到的WAL技術(shù),redo log就是WAL的典型應用,MySQL在有事務提交對數(shù)據(jù)進行更改時,只會在內(nèi)存中修改對應的數(shù)據(jù)頁和記錄redo log日志,完成后即表示事務提交成功,至于磁盤數(shù)據(jù)文件的更新則由后臺線程異步處理。由于redo log的加入,保證了MySQL數(shù)據(jù)一致性和持久性(即使數(shù)據(jù)刷盤之前MySQL奔潰了,重啟后仍然能通過redo log里的更改記錄進行重放,重新刷盤),此外還能提升語句的執(zhí)行性能(寫redo log是順序?qū)?,相比于更新?shù)據(jù)文件的隨機寫,日志的寫入開銷更小,能顯著提升語句的執(zhí)行性能,提高并發(fā)量),由此可見redo log是必不可少的。

redo log是固定大小的,所以只能循環(huán)寫,從頭開始寫,寫到末尾就又回到開頭,相當于一個環(huán)形。當日志寫滿了,就需要對舊的記錄進行擦除,但在擦除之前,需要確保這些要被擦除記錄對應在內(nèi)存中的數(shù)據(jù)頁都已經(jīng)刷到磁盤中了。在redo log滿了到擦除舊記錄騰出新空間這段期間,是不能再接收新的更新請求,所以有可能會導致MySQL卡頓。(所以針對并發(fā)量大的系統(tǒng),適當設置redo log的文件大小非常重要!?。。?/p>

2、回滾日志 undo log

undo log顧名思義,主要就是提供了回滾的作用,但其還有另一個主要作用,就是多個行版本控制(MVCC),保證事務的原子性。在數(shù)據(jù)修改的流程中,會記錄一條與當前操作相反的邏輯日志到undo log中(可以認為當delete一條記錄時,undo log中會記錄一條對應的insert記錄,反之亦然,當update一條記錄時,它記錄一條對應相反的update記錄),如果因為某些原因?qū)е率聞债惓J×?,可以借助該undo log進行回滾,保證事務的完整性,所以undo log也必不可少。

3、歸檔日志 binlog

binlog在MySQL的server層產(chǎn)生,不屬于任何引擎,主要記錄用戶對數(shù)據(jù)庫操作的SQL語句(除了查詢語句)。之所以將binlog稱為歸檔日志,是因為binlog不會像redo log一樣擦掉之前的記錄循環(huán)寫,而是一直記錄(超過有效期才會被清理),如果超過單日志的最大值(默認1G,可以通過變量 max_binlog_size 設置),則會新起一個文件繼續(xù)記錄。但由于日志可能是基于事務來記錄的(如InnoDB表類型),而事務是絕對不可能也不應該跨文件記錄的,如果正好binlog日志文件達到了最大值但事務還沒有提交則不會切換新的文件記錄,而是繼續(xù)增大日志,所以 max_binlog_size 指定的值和實際的binlog日志大小不一定相等。

正是由于binlog有歸檔的作用,所以binlog主要用作主從同步和數(shù)據(jù)庫基于時間點的還原。

那么回到剛才的問題,binlog可以簡化掉嗎?這里需要分場景來看:

如果是主從模式下,binlog是必須的,因為從庫的數(shù)據(jù)同步依賴的就是binlog;

如果是單機模式,并且不考慮數(shù)據(jù)庫基于時間點的還原,binlog就不是必須,因為有redo log就可以保證crash-safe能力了;但如果萬一需要回滾到某個時間點的狀態(tài),這時候就無能為力,所以建議binlog還是一直開啟;

根據(jù)上面對三個日志的詳解,我們可以對這個問題進行解答:在主從模式下,三個日志都是必須的;在單機模式下,binlog可以視情況而定,保險起見最好開啟。

四、兩階段提交

問題:為什么redo log要分兩步寫,中間再穿插寫binlog呢?

從上面可以看出,因為redo log影響主庫的數(shù)據(jù),binlog影響從庫的數(shù)據(jù),所以redo log和binlog必須保持一致才能保證主從數(shù)據(jù)一致,這是前提。

相信很多有過開發(fā)經(jīng)驗的同學都知道分布式事務,這里的redo log和binlog其實就是很典型的分布式事務場景,因為兩者本身就是兩個獨立的個體,要想保持一致,就必須使用分布式事務的解決方案來處理。而將redo log分成了兩步,其實就是使用了兩階段提交協(xié)議(Two-phase Commit,2PC)。

下面對更新語句的執(zhí)行流程進行簡化,看一下MySQL的兩階段提交是如何實現(xiàn)的:

從圖中可看出,事務的提交過程有兩個階段,就是將redo log的寫入拆成了兩個步驟:prepare和commit,中間再穿插寫入binlog。

如果這時候你很疑惑,為什么一定要用兩階段提交呢,如果不用兩階段提交會出現(xiàn)什么情況,比如先寫redo log,再寫binlog或者先寫binlog,再寫redo log不行嗎?下面我們用反證法來進行論證。

我們繼續(xù)用update T set c=c+1 where id=2這個例子,假設id=2這一條數(shù)據(jù)的c初始值為0。那么在redo log寫完,binlog還沒有寫完的時候,MySQL進程異常重啟。由于redo log已經(jīng)寫完了,系統(tǒng)重啟后會通過redo log將數(shù)據(jù)恢復回來,所以恢復后這一?c的值是1。但是由于binlog沒寫完就crash?,這時候binlog?面就沒有記錄這個語?。因此,不管是現(xiàn)在的從庫還是之后通過這份binlog還原臨時庫都沒有這一次更新,c的值還是0,與原庫的值不同。

同理,如果先寫binlog,再寫redo log,中途系統(tǒng)crash了,也會導致主從不一致,這里就不再詳述。

所以將redo log分成兩步寫,即兩階段提交,才能保證redo log和binlog內(nèi)容一致,從而保證主從數(shù)據(jù)一致。

兩階段提交雖然能夠保證單事務兩個日志的內(nèi)容一致,但在多事務的情況下,卻不能保證兩者的提交順序一致,比如下面這個例子,假設現(xiàn)在有3個事務同時提交:

T1 (--prepare--binlog---------------------commit) T2 (-----prepare-----binlog----commit) T3 (--------prepare-------binlog------commit) 解析: redo log prepare的順序:T1 --》T2 --》T3 binlog的寫入順序:T1 --》 T2 --》T3 redo log commit的順序:T2 --》 T3 --》T1

結(jié)論:由于binlog寫入的順序和redo log提交結(jié)束的順序不一致,導致binlog和redo log所記錄的事務提交結(jié)束的順序不一樣,最終導致的結(jié)果就是主從數(shù)據(jù)不一致。

因此,在兩階段提交的流程基礎上,還需要加一個鎖來保證提交的原子性,從而保證多事務的情況下,兩個日志的提交順序一致。所以在早期的MySQL版本中,通過使用prepare_commit_mutex鎖來保證事務提交的順序,在一個事務獲取到鎖時才能進入prepare,一直到commit結(jié)束才能釋放鎖,下個事務才可以繼續(xù)進行prepare操作。通過加鎖雖然完美地解決了順序一致性的問題,但在并發(fā)量較大的時候,就會導致對鎖的爭用,性能不佳。除了鎖的爭用會影響到性能之外,還有一個對性能影響更大的點,就是每個事務提交都會進行兩次fsync(寫磁盤),一次是redo log落盤,另一次是binlog落盤。大家都知道,寫磁盤是昂貴的操作,對于普通磁盤,每秒的QPS大概也就是幾百。

五、組提交

問題:針對通過在兩階段提交中加鎖控制事務提交順序這種實現(xiàn)方式遇到的性能瓶頸問題,有沒有更好的解決方案呢?

答案自然是有的,在MySQL 5.6 就引入了binlog組提交,即BLGC(Binary Log Group Commit)。binlog組提交的基本思想是,引入隊列機制保證InnoDB commit順序與binlog落盤順序一致,并將事務分組,組內(nèi)的binlog刷盤動作交給一個事務進行,實現(xiàn)組提交目的。具體如圖:

第一階段(prepare階段):

持有prepare_commit_mutex,并且write/fsync redo log到磁盤,設置為prepared狀態(tài),完成后就釋放prepare_commit_mutex,binlog不作任何操作。

第二個階段(commit階段):這里拆分成了三步,每一步的任務分配給一個專門的線程處理:

Flush Stage(寫入binlog緩存)

① 持有Lock_log mutex [leader持有,follower等待]

② 獲取隊列中的一組binlog(隊列中的所有事務)

③ 寫入binlog緩存

Sync Stage(將binlog落盤)

①釋放Lock_log mutex,持有Lock_sync mutex[leader持有,follower等待]

②將一組binlog落盤(fsync動作,最耗時,假設sync_binlog為1)。

Commit Stage(InnoDB commit,清楚undo信息)

①釋放Lock_sync mutex,持有Lock_commit mutex[leader持有,follower等待]

② 遍歷隊列中的事務,逐一進行InnoDB commit

③ 釋放Lock_commit mutex

每個Stage都有自己的隊列,隊列中的第一個事務稱為leader,其他事務稱為follower,leader控制著follower的行為。每個隊列各自有mutex保護,隊列之間是順序的。只有flush完成后,才能進入到sync階段的隊列中;sync完成后,才能進入到commit階段的隊列中。但是這三個階段的作業(yè)是可以同時并發(fā)執(zhí)行的,即當一組事務在進行commit階段時,其他新事務可以進行flush階段,實現(xiàn)了真正意義上的組提交,大幅度降低磁盤的IOPS消耗。

針對組提交為什么比兩階段提交加鎖性能更好,簡單做個總結(jié):組提交雖然在每個隊列中仍然保留了prepare_commit_mutex鎖,但是鎖的粒度變小了,變成了原來兩階段提交的1/4,所以鎖的爭用性也會大大降低;另外,組提交是批量刷盤,相比之前的單條記錄都要刷盤,能大幅度降低磁盤的IO消耗。

六、數(shù)據(jù)恢復流程

問題:假設事務提交過程中,MySQL進程突然奔潰,重啟后是怎么保證數(shù)據(jù)不丟失的?

下圖就是MySQL重啟后,提供服務前會先做的事 -- 恢復數(shù)據(jù)的流程:

對上圖進行簡單描述就是:奔潰重啟后會檢查redo log中是完整并且處于prepare狀態(tài)的事務,然后根據(jù)XID(事務ID),從binlog中找到對應的事務,如果找不到,則回滾;找到并且事務完整則重新commit redo log,完成事務的提交。

下面我們根據(jù)事務提交流程,在不同的階段時刻,看看MySQL突然奔潰后,按照上述流程是如何恢復數(shù)據(jù)的。

時刻A(剛在內(nèi)存中更改完數(shù)據(jù)頁,還沒有開始寫redo log的時候奔潰):

因為內(nèi)存中的臟頁還沒刷盤,也沒有寫redo log和binlog,即這個事務還沒有開始提交,所以奔潰恢復跟該事務沒有關系;

時刻B(正在寫redo log或者已經(jīng)寫完redo log并且落盤后,處于prepare狀態(tài),還沒有開始寫binlog的時候奔潰):

恢復后會判斷redo log的事務是不是完整的,如果不是則根據(jù)undo log回滾;如果是完整的并且是prepare狀態(tài),則進一步判斷對應的事務binlog是不是完整的,如果不完整則一樣根據(jù)undo log進行回滾;

時刻C(正在寫binlog或者已經(jīng)寫完binlog并且落盤了,還沒有開始commit redo log的時候奔潰):

恢復后會跟時刻B一樣,先檢查redo log中是完整并且處于prepare狀態(tài)的事務,然后判斷對應的事務binlog是不是完整的,如果不完整則一樣根據(jù)undo log回滾,完整則重新commit redo log;

時刻D(正在commit redo log或者事務已經(jīng)提交完的時候,還沒有反饋成功給客戶端的時候奔潰):

恢復后跟時刻C基本一樣,都會對照redo log和binlog的事務完整性,來確認是回滾還是重新提交。

七、總結(jié)

至此對MySQL 的crash-safe原理細節(jié)就基本講完了,簡單回顧一下:

首先簡單介紹了WAL日志先行技術(shù),包括它的定義、流程和作用。WAL是大部分數(shù)據(jù)庫系統(tǒng)實現(xiàn)一致性和持久性的通用設計模式。;

接著對MySQL的日志模塊,redo log、undo log、binlog、兩階段提交和組提交都進行了詳細介紹;

最后講解了數(shù)據(jù)恢復流程,并從不同時刻加以驗證。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    使用內(nèi)置晶振的話,串口波特率最大可以設置多少,不會包嗎?

    之前我用ST的某芯片,采用內(nèi)置晶振,將波特率設置115200,100ms收發(fā)一次數(shù)據(jù)發(fā)現(xiàn)就有包的情況了,想知道,芯源的MCU效果如何?有大佬試過使用內(nèi)置晶振的話,串口波特率最大可以設置多少,不會
    發(fā)表于 01-19 06:48

    labview有調(diào)用mysql數(shù)據(jù)庫問題????

    labview有調(diào)用mysql數(shù)據(jù)庫,請問labview打包成exe安裝檔,怎么把mysql數(shù)據(jù)庫打包進來,是mysql
    發(fā)表于 05-19 16:17

    【EVB-335X-II試用體驗】之QT遠程訪問MySql數(shù)據(jù)庫(交叉編譯MySql QT客戶端驅(qū)動程序及功能測試)

    【EVB-335X-II試用體驗】之QT遠程訪問MySql數(shù)據(jù)庫(交叉編譯MySql QT客戶端驅(qū)動程序及功能測試)MySQL是一款非常優(yōu)秀的、開源、免費的
    發(fā)表于 07-04 00:28

    mysql數(shù)據(jù)庫設計步驟

    mysql數(shù)據(jù)庫設計和優(yōu)化
    發(fā)表于 05-13 11:00

    MySQL數(shù)據(jù)庫使用

    關于MySQL數(shù)據(jù)庫的簡單操作
    發(fā)表于 10-24 14:32

    labview插入數(shù)據(jù)MySQL數(shù)據(jù)

    最近在用labview寫入數(shù)據(jù)MySQL數(shù)據(jù)庫,遇到一個問題:(如圖片所示)利用insert指令插入數(shù)據(jù),為什么每次插入單個值都會新起一行,而不會
    發(fā)表于 12-26 16:52

    TFT畫點數(shù)據(jù),所謂的數(shù)據(jù)怎么

    TFT畫點數(shù)據(jù),所謂的數(shù)據(jù)怎么? 是寫什么呢?
    發(fā)表于 08-07 08:00

    對 Flash 操作導致 USART 接收數(shù)據(jù)

    對 Flash 操作導致 USART 接收數(shù)據(jù)
    發(fā)表于 11-25 14:49 ?0次下載

    網(wǎng)絡數(shù)據(jù)包的原因及攝像機包的原因

    不少人在使用網(wǎng)絡和監(jiān)控攝像系統(tǒng)的時候都有遇到過數(shù)據(jù)包的情況,數(shù)據(jù)包的原因是多種多樣的,以下就為大家介紹一下網(wǎng)絡數(shù)據(jù)
    的頭像 發(fā)表于 01-11 09:27 ?1.4w次閱讀

    MySQL數(shù)據(jù)庫:理解MySQL的性能優(yōu)化、優(yōu)化查詢

    最近一直在為大家更新MySQL相關學習內(nèi)容,可能有朋友不懂MySQL的重要性。在程序,語言,架構(gòu)更新?lián)Q代頻繁的今天,MySQL 恐怕是大家使用最多的存儲數(shù)據(jù)庫了。由于
    的頭像 發(fā)表于 07-02 17:18 ?3681次閱讀
    <b class='flag-5'>MySQL</b><b class='flag-5'>數(shù)據(jù)</b>庫:理解<b class='flag-5'>MySQL</b>的性能優(yōu)化、優(yōu)化查詢

    MySQL 5.7與MySQL 8.0 性能對比

    前先重啟mysql服務,并清除os的緩存(避免多次測試時命中緩存) 每次進行測試都是新生成測試數(shù)據(jù)后再進行mysql5.7和mysql8.0的測試 每次測試時
    的頭像 發(fā)表于 11-03 09:26 ?2.3w次閱讀
    <b class='flag-5'>MySQL</b> 5.7與<b class='flag-5'>MySQL</b> 8.0 性能對比

    如何使用WINDAQ MySQL存儲數(shù)據(jù)

    MySQL數(shù)據(jù)庫可以存儲比Microsoft Excel電子表格多30,000倍的數(shù)據(jù)。用于 結(jié)合WinDaq/Lite,Pro或Pro+,WinDaq / MySQL對于那些需要存儲
    的頭像 發(fā)表于 12-02 16:29 ?1527次閱讀
    如何使用WINDAQ <b class='flag-5'>MySQL</b>存儲<b class='flag-5'>數(shù)據(jù)</b>

    MySQL數(shù)據(jù)庫管理與應用

    MySQL數(shù)據(jù)庫管理與應用 MySQL是一種廣泛使用的關系型數(shù)據(jù)庫管理系統(tǒng),被認為是最流行和最常見的開源數(shù)據(jù)庫之一。它可以被用于多種不同的應
    的頭像 發(fā)表于 08-28 17:15 ?1798次閱讀

    mysql數(shù)據(jù)庫基礎命令

    MySQL是一個流行的關系型數(shù)據(jù)庫管理系統(tǒng),經(jīng)常用于存儲、管理和操作數(shù)據(jù)。在本文中,我們將詳細介紹MySQL的基礎命令,并提供與每個命令相關的詳細解釋。 登錄
    的頭像 發(fā)表于 12-06 10:56 ?1413次閱讀

    MySQL數(shù)據(jù)庫的安裝

    MySQL數(shù)據(jù)庫的安裝 【一】各種數(shù)據(jù)庫的端口 MySQL :3306 Redis :6379 MongoDB :27017 Django :8000 flask :5000 【二】
    的頭像 發(fā)表于 01-14 11:25 ?1078次閱讀
    <b class='flag-5'>MySQL</b><b class='flag-5'>數(shù)據(jù)</b>庫的安裝