溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

MongoDB與MySQL關(guān)于寫確認(rèn)的異同

發(fā)布時(shí)間:2020-08-10 19:35:45 來源:ITPUB博客 閱讀:172 作者:京東云技術(shù)新知 欄目:MySQL數(shù)據(jù)庫

MongoDB與MySQL關(guān)于寫確認(rèn)的異同

云妹導(dǎo)讀:
所謂寫確認(rèn),是指用戶將數(shù)據(jù)寫入數(shù)據(jù)庫之后,數(shù)據(jù)庫告知用戶寫入成功的一個(gè)概念。根據(jù)數(shù)據(jù)庫的特點(diǎn)和配置,可以在不同的寫入程度上,返回給用戶,而這其中,就涉及到了不同的性能、數(shù)據(jù)安全等級以及數(shù)據(jù)一致性的內(nèi)容。

不同的寫入確認(rèn)級別或配置,是數(shù)據(jù)庫提供給用戶的一種自我控制的能力,用戶可以針對自身業(yè)務(wù)的特點(diǎn)、數(shù)據(jù)管理的需要、性能的考慮、數(shù)據(jù)一致性以及服務(wù)可用性各種因素進(jìn)行考慮,選擇適合的數(shù)據(jù)庫配置,來實(shí)現(xiàn)自身的需要。

首先介紹幾個(gè)重要的概念,這些概念也是數(shù)據(jù)庫中常識性的知識了,不過是在不同數(shù)據(jù)庫的不同表述。

這些概念主要涉及到寫確認(rèn)的兩個(gè)重要考量點(diǎn), 一個(gè)是本地?cái)?shù)據(jù)庫寫操作的不丟失,一個(gè)是分布式環(huán)境下,數(shù)據(jù)冗余的一致性。

本地?cái)?shù)據(jù)庫寫操作是指數(shù)據(jù)庫在處理用戶的寫操作后,能夠持續(xù)化,防止因?yàn)橐馔鈱?dǎo)致的數(shù)據(jù)丟失,這個(gè)主要涉及到日志,比如MySQL中的redo log和MongoDB中的journal日志。

數(shù)據(jù)冗余的一致性是指多副本的環(huán)境下,比如主從或復(fù)制集架構(gòu)下,數(shù)據(jù)寫入主節(jié)點(diǎn)后,如何實(shí)現(xiàn)從節(jié)點(diǎn)與主節(jié)點(diǎn)的數(shù)據(jù)一致,而主從之間是以另外一個(gè)日志實(shí)現(xiàn)數(shù)據(jù)同步的,比如MySQL的binlog和MongoDB中的oplog日志。

另外防止主節(jié)點(diǎn)崩潰,數(shù)據(jù)未能同步到從節(jié)點(diǎn),導(dǎo)致從節(jié)點(diǎn)成為新的主節(jié)點(diǎn)后,未同步數(shù)據(jù)丟失,也是寫確認(rèn)中重要的內(nèi)容,即不但同步數(shù)據(jù),而且要讓數(shù)據(jù)安全快速的同步。

redo/journal

MySQL的redo log和MongoDB的journal日志都是數(shù)據(jù)庫存儲(chǔ)引擎層面的WAL(Write-Ahead Logging)預(yù)寫式日志,記錄的是數(shù)據(jù)的物理修改,是提高數(shù)據(jù)系統(tǒng)持久性的一種技術(shù)。

redo log

redo log是MySQL的默認(rèn)存儲(chǔ)引擎innodb事務(wù)日志中的核心日志文件之一,俗稱重做日志,主要用作前滾的數(shù)據(jù)恢復(fù)。

當(dāng)我們想要修改MySQL數(shù)據(jù)庫中某一行數(shù)據(jù)的時(shí)候,innodb是把數(shù)據(jù)從磁盤讀取到內(nèi)存的緩沖池上進(jìn)行修改。這個(gè)時(shí)候數(shù)據(jù)在內(nèi)存中被修改,與磁盤中相比就存在了差異,我們稱這種有差異的數(shù)據(jù)為臟頁。innodb對臟頁的處理不是每次生成臟頁就將臟頁刷新回磁盤,這樣會(huì)產(chǎn)生海量的io操作,嚴(yán)重影響innodb的處理性能,因此并不是每次有了臟頁都立刻刷新到磁盤中。既然臟頁與磁盤中的數(shù)據(jù)存在差異,那么如果在這期間數(shù)據(jù)庫出現(xiàn)故障就會(huì)造成數(shù)據(jù)的丟失。

而redo log就是為了解決這個(gè)問題。由于redo log的存在,可以延遲刷新臟頁到磁盤的時(shí)間,保障了數(shù)據(jù)庫性能的情況下提高了數(shù)據(jù)的安全。雖然增加了redo log刷新的開銷,但是由于redo log采用的順序io,比數(shù)據(jù)頁的隨機(jī)io要快很多,這額外的開銷可接受。

即,數(shù)據(jù)庫先將數(shù)據(jù)頁的物理修改情況寫到刷盤較快的redo log文件中,防止數(shù)據(jù)丟失。一旦發(fā)生故障,數(shù)據(jù)庫重啟恢復(fù)的時(shí)候,可以先從redo log把未刷新到磁盤的已經(jīng)提交的物理數(shù)據(jù)頁恢復(fù)回來。

journal

journal是MongoDB存儲(chǔ)引擎層面的概念,MongoDB主要支持的mmapv1、wiredtiger、mongorocks等存儲(chǔ)引擎,都?持配置journal。MongoDB可以基于journal來恢復(fù)因?yàn)楸罎⑽醇皶r(shí)寫到磁盤的信息。

MongoDB 所有的數(shù)據(jù)寫?、讀取最終都是調(diào)存儲(chǔ)引擎層的接?來存儲(chǔ)、讀取數(shù)據(jù),journal 是存儲(chǔ)引擎存儲(chǔ)數(shù)據(jù)時(shí)的一種輔助機(jī)制。

在MongoDB的4.0版本以前,用戶可以設(shè)置是否開啟journal日志;從4.0版本開始,副本集成員必須開啟journal功能。

以wiredtiger為例,如果不配置journal,寫入wiredtiger的數(shù)據(jù),并不會(huì)立即持久化存儲(chǔ);而是每分鐘會(huì)做一次全量的checkpoint( storage.syncPeriodSecs配置項(xiàng),默認(rèn)為1分鐘),將所有的數(shù)據(jù)持久化。如果中間出現(xiàn)宕機(jī),那么數(shù)據(jù)只能恢復(fù)到最近的一次checkpoint,這樣最多可能丟掉1分鐘的數(shù)據(jù)。

所以建議「一定要開啟journal」,開啟journal后,每次寫入會(huì)記錄一條操作日志(通過journal可以重新構(gòu)造出寫入的數(shù)據(jù))。這樣即使出現(xiàn)宕機(jī),啟動(dòng)時(shí) Wiredtiger 會(huì)先將數(shù)據(jù)恢復(fù)到最近的一次checkpoint的點(diǎn),然后重放后續(xù)的 journal操作日志來恢復(fù)數(shù)據(jù)。

MongoDB與MySQL關(guān)于寫確認(rèn)的異同

binlog/oplog

MySQL的binlog和MongoDB的oplog都是數(shù)據(jù)庫層面的寫操作對應(yīng)的邏輯日志,主要用于實(shí)現(xiàn)數(shù)據(jù)在主備之間的同步復(fù)制以及增量備份和恢復(fù)。

binlog

binlog是MySQL數(shù)據(jù)庫層面的一種二進(jìn)制日志,不管底層使用的什么存儲(chǔ)引擎,對數(shù)據(jù)庫的修改都會(huì)產(chǎn)生這種日志。binlog記錄操作的方法是邏輯性語句,可以通過設(shè)置log-bin=mysql-bin來啟動(dòng)該功能。

binlog中記錄了有關(guān)寫操作的執(zhí)行時(shí)間、操作類型、以及操作的具體內(nèi)容,比如SQL語句(statement)或每行實(shí)際數(shù)據(jù)的變更(row)。

MongoDB與MySQL關(guān)于寫確認(rèn)的異同

上圖是MySQL主從之間是如何實(shí)現(xiàn)數(shù)據(jù)復(fù)制的,其中的三個(gè)重要過程是:

  • 主庫(Master)把數(shù)據(jù)庫更改記錄到binlog(圖中的Binary Log)中;
  • 備庫(Slave)將主庫上的binlog復(fù)制到自己的中繼日志(Relay log)中;
  • 備庫讀取中繼日志中的事件,將其重放(Replay)到備庫數(shù)據(jù)之上。

這樣源源不斷的復(fù)制,實(shí)現(xiàn)了數(shù)據(jù)在數(shù)據(jù)庫節(jié)點(diǎn)之間的一致。

oplog

oplog是MongoDB數(shù)據(jù)庫層面的概念,在復(fù)制集架構(gòu)下,主備節(jié)點(diǎn)之間通過oplog來實(shí)現(xiàn)節(jié)點(diǎn)間的數(shù)據(jù)同步。Primary中所有的寫入操作都會(huì)記錄到MongoDB Oplog中,然后從庫會(huì)來主庫一直拉取Oplog并應(yīng)用到自己的數(shù)據(jù)庫中。這里的Oplog是MongoDB local數(shù)據(jù)庫的一個(gè)集合,它是Capped collection,通俗意思就是它是固定大小,循環(huán)使用的。

oplog 在 MongoDB 里是一個(gè)普通的 capped collection,對于存儲(chǔ)引擎來說,oplog只是一部分普通的數(shù)據(jù)而已。

只有按復(fù)制集架構(gòu)啟動(dòng)的節(jié)點(diǎn)會(huì)自動(dòng)在local庫中創(chuàng)建oplog.rs的集合。

oplog中記錄了有關(guān)寫操作的操作時(shí)間、操作類型、以及操作的具體內(nèi)容,幾乎保留的每行實(shí)際數(shù)據(jù)的變更(在4.0及以后版本中,一個(gè)事務(wù)中涉及的多個(gè)文檔,會(huì)寫在一條oplog中)。

MongoDB與MySQL關(guān)于寫確認(rèn)的異同

上圖是MongoDB主備之間如何實(shí)現(xiàn)數(shù)據(jù)復(fù)制的,其中的四個(gè)重要過程是:

  • 主庫(Primary)把數(shù)據(jù)庫更改記錄到oplog(圖中的Capped Oplog集合)中;
  • 備庫(Secondary)把主庫上的oplog拉取到自己的回放隊(duì)列中(Queue)中;
  • 備庫讀取隊(duì)列中的oplog,批量回放(applyOps)到備庫數(shù)據(jù)中;
  • 再將隊(duì)列中的Oplog寫入到備庫中的oplog.rs集合中。

這樣源源不斷的復(fù)制,實(shí)現(xiàn)了數(shù)據(jù)在數(shù)據(jù)庫節(jié)點(diǎn)之間的一致。

另外MongoDB支持鏈?zhǔn)綇?fù)制,即oplog不一定從Primary中獲取,還可以從其他Secondary獲取。上圖是MongoDB主備之間如何實(shí)現(xiàn)數(shù)據(jù)復(fù)制的,其中的四個(gè)重要過程是:

  • 主庫(Primary)把數(shù)據(jù)庫更改記錄到oplog(圖中的Capped Oplog集合)中;
  • 備庫(Secondary)把主庫上的oplog拉取到自己的回放隊(duì)列中(Queue)中;
  • 備庫讀取隊(duì)列中的oplog,批量回放(applyOps)到備庫數(shù)據(jù)中;
  • 再將隊(duì)列中的Oplog寫入到備庫中的oplog.rs集合中。

這樣源源不斷的復(fù)制,實(shí)現(xiàn)了數(shù)據(jù)在數(shù)據(jù)庫節(jié)點(diǎn)之間的一致。

另外MongoDB支持鏈?zhǔn)綇?fù)制,即oplog不一定從Primary中獲取,還可以從其他Secondary獲取。

redo與binlog

  1. redo log是在innodb存儲(chǔ)引擎層產(chǎn)生,而binlog是MySQL數(shù)據(jù)庫的上層產(chǎn)生的,并且binlog不僅僅針對innodb存儲(chǔ)引擎,MySQL數(shù)據(jù)庫中的任何存儲(chǔ)引擎對于數(shù)據(jù)庫的更改都會(huì)產(chǎn)生binlog。
  2. 兩種日志記錄的內(nèi)容形式不同。MySQL的binlog是邏輯日志,其記錄是對應(yīng)的SQL語句或行的修改內(nèi)容。而innodb存儲(chǔ)引擎層面的redo log是物理日志。
  3. 兩種日志與記錄寫入磁盤的時(shí)間點(diǎn)不同,binlog只在事務(wù)提交完成后進(jìn)行一次寫入。而innodb存儲(chǔ)引擎的redo log在事務(wù)進(jìn)行中不斷地被寫入,并日志不是隨事務(wù)提交的順序進(jìn)行寫入的。
  4. binlog僅在事務(wù)提交時(shí)記錄,并且對于每一個(gè)事務(wù),僅在事務(wù)提交時(shí)記錄,并且對于每一個(gè)事務(wù),僅包含對應(yīng)事務(wù)的一個(gè)日志。而對于innodb存儲(chǔ)引擎的redo log,由于其記錄是物理操作日志,因此每個(gè)事務(wù)對應(yīng)多個(gè)日志條目,并且事務(wù)的redo log寫入是并發(fā)的,并非在事務(wù)提交時(shí)寫入,其在文件中記錄的順序并非是事務(wù)開始的順序。
  5. binlog不是循環(huán)使用,在寫滿或者重啟之后,會(huì)生成新的binlog文件,redo log是循環(huán)使用。
  6. binlog可以作為恢復(fù)數(shù)據(jù)使用,主從復(fù)制搭建,redo log作為異常宕機(jī)或者介質(zhì)故障后的數(shù)據(jù)恢復(fù)使用。

MongoDB與MySQL關(guān)于寫確認(rèn)的異同

journal與oplog

journal日志是在wiretiger、mmapV1等存儲(chǔ)引擎層產(chǎn)生,而oplog是MongoDB數(shù)據(jù)庫的主從復(fù)制層面的概念,oplog也與存儲(chǔ)引擎無關(guān);

兩種日志記錄的內(nèi)容形式不同。MongoDB的oplog是邏輯日志,其記錄的是對應(yīng)的寫操作的內(nèi)容。而journal存儲(chǔ)的物理修改;

兩種日志與記錄寫入磁盤的時(shí)間點(diǎn)不同。

MongoDB 復(fù)制集里寫入一個(gè)文檔時(shí),需要修改如下數(shù)據(jù)

  1. 將文檔數(shù)據(jù)寫入對應(yīng)的集合
  2. 更新集合的所有索引信息
  3. 寫入一條oplog用于同步 最終存儲(chǔ)引擎會(huì)將所有修改操作應(yīng)用,并將上述3個(gè)操作寫?到一條 journal 操作日志里。
  4. journal不是循環(huán)使用,在寫滿或者重啟之后,會(huì)生成新的journal文件,oplog是循環(huán)使用;
  5. oplog可以作為恢復(fù)數(shù)據(jù)使用,復(fù)制集架構(gòu),journal作為一場宕機(jī)或者介質(zhì)故障后的數(shù)據(jù)恢復(fù)使用。

MongoDB與MySQL關(guān)于寫確認(rèn)的異同

寫確認(rèn)

寫確認(rèn)這個(gè)概念其實(shí)是來自于MongoDB中的write concern,描述的是MongoDB對一個(gè)寫操作的確認(rèn)(acknowledge)等級。而MySQL中對應(yīng)的這個(gè)概念,可以理解為,用戶在提交(commit)寫操作的時(shí)候,需要經(jīng)過哪些操作之后就會(huì)告知用戶提交成功。

MongoDB

在MongoDB中,數(shù)據(jù)庫支持基于write concern功能使用戶配置靈活的寫入策略,則不同的策略對應(yīng)不同的數(shù)據(jù)寫入程度即返回給用戶寫入成功,用戶可以繼續(xù)操作下一個(gè)寫請求。

write concern

write concern支持3個(gè)配置項(xiàng):

{ w: , j: , wtimeout: }

其中:

  1. w,該參數(shù)要求寫操作已經(jīng)寫入到個(gè)節(jié)點(diǎn)才向用戶確認(rèn);
    1. {w: 0} 對客戶端的寫入不需要發(fā)送任何確認(rèn),適用于性能要求高,但不關(guān)注正確性的場景;
    2. {w: 1} 默認(rèn)的writeConcern,數(shù)據(jù)寫入到Primary就向客戶端發(fā)送確認(rèn);
    3. {w: "majority"} 數(shù)據(jù)寫入到副本集大多數(shù)成員后向客戶端發(fā)送確認(rèn),適用于對數(shù)據(jù)安全性要求比較高的場景,該選項(xiàng)會(huì)降低寫入性能;
  2. j,該參數(shù)表示是否寫操作要進(jìn)行journal持久化之后才向用戶確認(rèn);
    1. {j: true} 要求primary寫操作進(jìn)行了journal持久化之后才向用戶確認(rèn);
    2. {j: false} 要求寫操作已經(jīng)在journal緩存中即可向用戶確認(rèn);journal后續(xù)會(huì)將持久化到磁盤,默認(rèn)是100ms;
  3. wtimeout,該參數(shù)表示寫入超時(shí)時(shí)間,w大于1時(shí)有效;當(dāng)w大于1時(shí),寫操作需要成功寫入若干個(gè)節(jié)點(diǎn)才算成功,如果寫入過程中節(jié)點(diǎn)有故障,導(dǎo)致寫操作遲遲不能滿足w要求,也就一直不能向用戶返回確認(rèn)結(jié)果,為了防止這種情況,用戶可以設(shè)置wtimeout來指定超時(shí)時(shí)間,寫入過程持續(xù)超過該時(shí)間仍未結(jié)束,則認(rèn)為寫入失敗。

副本集下的寫確認(rèn)

下面以一個(gè)副本集架構(gòu)來描述,一個(gè)寫操作的流程,來認(rèn)識MongoDB下的寫確認(rèn)。

MongoDB與MySQL關(guān)于寫確認(rèn)的異同

上面這個(gè)寫操作,{w:2},需要至少兩個(gè)節(jié)點(diǎn)寫成功才可以返回給用戶寫成功;而每個(gè)節(jié)點(diǎn)的寫入成功可以基于參數(shù){j}來判斷,如果{j:true},則每個(gè)節(jié)點(diǎn)寫入操作的journal都刷盤才可以;如果{j:false},則寫入操作的journal在緩存中即可以返回成功;

另外,MongoDB的Primary如何知道Secondary是否已經(jīng)同步成功呢,是基于如下流程:

  1. Client向Primary發(fā)起請求,指定writeConcern為{w: "majority"},Primary收到請求,本地寫入并記錄寫請求到oplog,然后等待大多數(shù)節(jié)點(diǎn)都同步了這條/批oplog(Secondary應(yīng)用完oplog會(huì)向主報(bào)告最新進(jìn)度);
  2. Secondary拉取到Primary上新寫入的oplog,本地重放并記錄oplog。為了讓Secondary能在第一時(shí)間內(nèi)拉取到主上的oplog,find命令支持一個(gè)awaitData的選項(xiàng),當(dāng)find沒有任何符合條件的文檔時(shí),并不立即返回,而是等待最多maxTimeMS(默認(rèn)為2s)時(shí)間看是否有新的符合條件的數(shù)據(jù),如果有就返回;所以當(dāng)新寫入oplog時(shí),備立馬能獲取到新的oplog;
  3. Secondary上有單獨(dú)的線程,當(dāng)oplog的最新時(shí)間戳發(fā)生更新時(shí),就會(huì)向Primary發(fā)送replSetUpdatePosition命令更新自己的oplog時(shí)間戳;
  4. 當(dāng)Primary發(fā)現(xiàn)有足夠多的節(jié)點(diǎn)oplog時(shí)間戳已經(jīng)滿足條件了,向客戶端發(fā)送確認(rèn),這樣,Primary即可知道數(shù)據(jù)已經(jīng)同步到了。

MongoDB與MySQL關(guān)于寫確認(rèn)的異同

MySQL

MySQL數(shù)據(jù)庫在所謂寫確認(rèn)或?qū)懗晒Ψ矫婵梢酝ㄟ^執(zhí)行事務(wù)的commit提交來體現(xiàn),提交成功則為寫成功。因此我主要從事務(wù)在執(zhí)行事務(wù)以及commit事務(wù)的過程中,涉及的redo log、binlog以及兩種日志的刷盤和主從復(fù)制的流程來分析MySQL的寫成功相關(guān)的設(shè)置和問題。

MySQL復(fù)制架構(gòu)

目前MySQL較為流量的版本包括5.5、5.6、5.7、8.0,而8.0版本中使用的Group Replication來實(shí)現(xiàn)多節(jié)點(diǎn)的數(shù)據(jù)一致性,這種組復(fù)制依靠分布式一致性協(xié)議(Paxos協(xié)議的變體),實(shí)現(xiàn)了分布式下數(shù)據(jù)的最終一致性。

MySQL中有幾種常見復(fù)制機(jī)制:

  • 同步復(fù)制。當(dāng)主庫提交事務(wù)之后,所有的從庫節(jié)點(diǎn)必須收到、Replay并且提交這些事務(wù),然后主庫線程才能繼續(xù)做后續(xù)操作。但缺點(diǎn)是,主庫完成一個(gè)事務(wù)的時(shí)間會(huì)被拉長,性能降低。
  • 異步復(fù)制。主庫將事務(wù) Binlog 事件寫入到 Binlog文件中,此時(shí)主庫只會(huì)通知一下 Dump 線程發(fā)送這些新的Binlog,然后主庫就會(huì)繼續(xù)處理提交操作,而此時(shí)不會(huì)保證這些 Binlog 傳到任何一個(gè)從庫節(jié)點(diǎn)上。

MongoDB與MySQL關(guān)于寫確認(rèn)的異同

  • 半同步復(fù)制。是介于全同步復(fù)制與全異步復(fù)制之間的一種,主庫只需要等待至少一個(gè)從庫節(jié)點(diǎn)收到并且 Flush Binlog 到 Relay Log 文件即可,主庫不需要等待所有從庫給主庫反饋。同時(shí),這里只是一個(gè)收到的反饋,而不是已經(jīng)完全完成并且提交的反饋,如此,節(jié)省了很多時(shí)間。

MongoDB與MySQL關(guān)于寫確認(rèn)的異同

  • 組復(fù)制。由若干個(gè)節(jié)點(diǎn)共同組成一個(gè)復(fù)制組,一個(gè)事務(wù)的提交,必須經(jīng)過組內(nèi)大多數(shù)節(jié)點(diǎn)(N / 2 + 1)決議并通過,才能得以提交。比如由3個(gè)節(jié)點(diǎn)組成一個(gè)復(fù)制組,Consensus層為一致性協(xié)議層,在事務(wù)提交過程中,發(fā)生組間通訊,由2個(gè)節(jié)點(diǎn)決議(certify)通過這個(gè)事務(wù),事務(wù)才能夠最終得以提交并響應(yīng)。

除了組復(fù)制,半同步復(fù)制技術(shù)是性能和安全相對更好的設(shè)計(jì),尤其在5.7版本中,優(yōu)化了之前版本的半同步復(fù)制相關(guān)的邏輯,因此我們主要以5.7版本來介紹。

MySQL5.6/5.5半同步復(fù)制的原理:提交事務(wù)的線程會(huì)被鎖定,直到至少一個(gè)Slave收到這個(gè)事務(wù),由于事務(wù)在被提交到存儲(chǔ)引擎之后才被發(fā)送到Slave上,所以事務(wù)的丟失數(shù)量可以下降到最多每線程一個(gè)。因?yàn)槭聞?wù)是在被提交之后才發(fā)送給Slave的,當(dāng)Slave沒有接收成功,并且Master掛了,會(huì)導(dǎo)致主從不一致:主有數(shù)據(jù),從沒有數(shù)據(jù)。這個(gè)被稱為AFTER_COMMIT。


MySQL5.7在Master事務(wù)提交的時(shí)間方面做了改進(jìn),事務(wù)是在提交之前發(fā)送給Slave(AFTER_SYNC),當(dāng)Slave沒有接收成功,并且Master宕機(jī)了,不會(huì)導(dǎo)致主從不一致,因?yàn)榇藭r(shí)主還沒有提交,所以主從都沒有數(shù)據(jù)。

MongoDB與MySQL關(guān)于寫確認(rèn)的異同


不過假如Slave接收成功,并且Master中的binlog未來得及刷盤并且在存儲(chǔ)引擎提交之前宕機(jī)了,那么很明顯這個(gè)事務(wù)是不成功的,但由于對應(yīng)的Binlog已經(jīng)做了Sync操作,從庫已經(jīng)收到了這些Binlog,并且執(zhí)行成功,相當(dāng)于在從庫上多了數(shù)據(jù),也算是有問題的,但多了數(shù)據(jù),問題一般不算嚴(yán)重。此時(shí)可能就需要8.0版本中的組復(fù)制了。

MySQL寫確認(rèn)行為

我們以MySQL的5.7版本的半同步復(fù)制的主從架構(gòu)的為例子,來介紹MySQL各個(gè)參數(shù)對寫確認(rèn)即commit的不同影響。

MongoDB與MySQL關(guān)于寫確認(rèn)的異同

上圖中,能夠體現(xiàn)半同步復(fù)制(AFTER SYNC)的過程為:

  • 第6步,寫binlog;(sync_binlog參數(shù)在此起作用)
  • 第7步,同步binlog到備庫的Relay log;(sync_relay_log參數(shù)在此起作用)
  • 第8步,返回給主庫ack;
  • 第9步和第10步,提交事務(wù),將redo log中該事務(wù)標(biāo)記為已提交;(innodb_flush_log_at_trx_commit參數(shù)在此起作用)
  • 第11步,返回給用戶寫成功;

上圖中,能體現(xiàn)redo log和binlog順序一致性的過程為:

  • 第4步,將redo log置為prepare并刷盤;
  • 第6步,寫入binlog;(sync_binlog參數(shù)在此起作用)
  • 第9步和第10步,提交事務(wù),并將redo log置為提交狀態(tài);

下面將把上面介紹的與刷盤有關(guān)的配置項(xiàng)引入這整個(gè)過程,來看寫操作不同的行為和風(fēng)險(xiǎn)。

MongoDB與MySQL關(guān)于寫確認(rèn)的異同

注意:以上是在開始內(nèi)部兩階段提交的流程,即innodb_support_xa=true,這個(gè)時(shí)候可以通過判斷binlog來恢復(fù)會(huì)提交的事務(wù),因此innodb_flush_log_at_trx_commit看起來可有可無;如果未開啟內(nèi)部事務(wù)的兩階段提交,則更會(huì)復(fù)雜,只有innodb_flush_log_at_trx_commit = 1 且 sync_binlog = 1 且 sync_relay_log = 1的情況下,可以保證已提交事務(wù)的安全,其他情況都有可能導(dǎo)致數(shù)據(jù)丟失或者主從數(shù)據(jù)不一致的風(fēng)險(xiǎn)。

但是在innodb_flush_log_at_trx_commit = 1 且 sync_binlog = 1 且 sync_relay_log = 1 的情況下,MySQL的性能相對最低。可以在提高性能的情況下,比如 innodb_flush_log_at_trx_commit = 2 且 sync_binlog = N (N為500 或1000),由于這種情況,redo log和binlog都在系統(tǒng)緩存中,可以使用帶蓄電池后備電源的緩存cache,防止系統(tǒng)斷電異常。

此外,rpl_semi_sync_master_wait_for_slave_count參數(shù)是控制同步到多少個(gè)節(jié)點(diǎn)的,類似MongoDB中write concern中的 w 參數(shù),如果這個(gè)參數(shù)設(shè)置為0(其實(shí)不能,最低1),則變?yōu)榱思兇獾漠惒綇?fù)制;如果這個(gè)參數(shù)設(shè)置為最大(所有從節(jié)點(diǎn)個(gè)數(shù)),則變?yōu)榱思兇獾耐綇?fù)制,因此這個(gè)地方也可以根據(jù)需要來進(jìn)行調(diào)整,來提交數(shù)據(jù)的安全。

同時(shí),有可能影響同步模式的還包括rpl_semi_sync_master_wait_no_slave參數(shù)、影響復(fù)制等待超時(shí)的參數(shù)rpl_semi_sync_master_timeout等。當(dāng)rpl_semi_sync_master_wait_no_slave為OFF時(shí),只要master發(fā)現(xiàn)Rpl_semi_sync_master_clients小于rpl_semi_sync_master_wait_for_slave_count,則master立即轉(zhuǎn)為異步模式;如果為ON時(shí),如果在事務(wù)提交階段(master等待ACK)超時(shí)rpl_semi_sync_master_timeout,master會(huì)轉(zhuǎn)為異步模式。

對比

配置比較

MongoDB與MySQL關(guān)于寫確認(rèn)的異同

其他

雖然MongoDB和MySQL在很多方面可以有類似或相似的設(shè)置,但是還是存在一些區(qū)別,比如:

  1. MongoDB的journal中包含了oplog的信息;而binlog和redo log是兩個(gè)相對獨(dú)立的內(nèi)容;
  2. MySQL幾乎所有的寫操作都是基于事務(wù)來提交的;而MongoDB在4.0開始支持多文檔的事務(wù),單文檔的事務(wù)基于內(nèi)部事務(wù)邏輯實(shí)現(xiàn),未直接提供給用戶;
  3. MySQL的寫確認(rèn)是已commit提交成功為標(biāo)志,MongoDB的普通寫操作是返回寫入成功為標(biāo)志;事務(wù)寫操作也是已commit為標(biāo)志;

總結(jié)

本文章所介紹的寫確認(rèn)的概念,涉及到了MongoDB與MySQL的日志文件(redo log/journal)、同步用日志(binlog/oplog)、刷盤機(jī)制和時(shí)機(jī)、主從同步架構(gòu)等多個(gè)流程和模塊,目的就是實(shí)現(xiàn)寫操作的原子性、持久性、分布式環(huán)境下的數(shù)據(jù)一致性等,對數(shù)據(jù)的性能和安全都有影響,需要根據(jù)數(shù)據(jù)、業(yè)務(wù)、壓力、安全等客觀因素去調(diào)整。

由于涉及的內(nèi)容非常多,未對所有的情況進(jìn)行測試驗(yàn)證,可能有疏漏或錯(cuò)誤,希望大家不吝賜教。也希望本篇內(nèi)容對于對MySQL和MongoDB都有興趣的同學(xué)可以作為一個(gè)總結(jié)和參考。


參考資料

高性能MySQL( https://item.jd.com/11220393.ht ml
MongoDB官方手冊( https://docs.mongodb.com/manual /
深入淺出MongoDB復(fù)制( https://mongoing.com/archives/5 200
mysql基于binlog的復(fù)制( https://blog.csdn.net/u01254801 6/article/details/86584293
MongoDB journal 與 oplog,究竟誰先寫入?( https://mongoing.com/archives/3 988
MySQL5.7新特性--官方高可用方案MGR介紹( https://www.cnblogs.com/luoahong/ar ticles/8043035.html
MongoDB writeConcern原理解析( https://mongoing.com/archives/2 916
mysql日志系統(tǒng)之redo log和bin log( https://www.jianshu.com/p/4bcfffb27 ed5
MySQL 5.7 半同步復(fù)制增強(qiáng)【轉(zhuǎn)】( https://www.cnblogs.com/mao3714/p/8 777470.html
MySQL 中Redo與Binlog順序一致性問題  【轉(zhuǎn)】( https://www.cnblogs.com/mao3714/p/8 734838.html
詳細(xì)分析MySQL事務(wù)日志(redo log和undo log)( https://www.cnblogs.com/f-ck-need-u /archive/2018/05/08/9010872.html
MySQL 的"雙1設(shè)置"-數(shù)據(jù)安全的關(guān)鍵參數(shù)(案例分享)( https://www.cnblogs.com/kevingrace/ p/10441086.html
rpl_semi_sync_master_wait_no_slave 參數(shù)研究實(shí)驗(yàn)( https://www.cnblogs.com/konggg/p/12 205505.html
MySQL5.7新特性半同步復(fù)制之AFTER_SYNC/AFTER_COMMIT的過程分析和總結(jié)( http://blog.itpub.net/15498/vi ewspace-2143986/

以上,Enjoy~

點(diǎn)擊【 閱讀】,可了解更多數(shù)據(jù)庫相關(guān)詳請

MongoDB與MySQL關(guān)于寫確認(rèn)的異同

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI