中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

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

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

MongoDB與MySQL關于寫確認的異同

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

MongoDB與MySQL關于寫確認的異同

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

不同的寫入確認級別或配置,是數據庫提供給用戶的一種自我控制的能力,用戶可以針對自身業務的特點、數據管理的需要、性能的考慮、數據一致性以及服務可用性各種因素進行考慮,選擇適合的數據庫配置,來實現自身的需要。

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

這些概念主要涉及到寫確認的兩個重要考量點, 一個是本地數據庫寫操作的不丟失,一個是分布式環境下,數據冗余的一致性。

本地數據庫寫操作是指數據庫在處理用戶的寫操作后,能夠持續化,防止因為意外導致的數據丟失,這個主要涉及到日志,比如MySQL中的redo log和MongoDB中的journal日志。

數據冗余的一致性是指多副本的環境下,比如主從或復制集架構下,數據寫入主節點后,如何實現從節點與主節點的數據一致,而主從之間是以另外一個日志實現數據同步的,比如MySQL的binlog和MongoDB中的oplog日志。

另外防止主節點崩潰,數據未能同步到從節點,導致從節點成為新的主節點后,未同步數據丟失,也是寫確認中重要的內容,即不但同步數據,而且要讓數據安全快速的同步。

redo/journal

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

redo log

redo log是MySQL的默認存儲引擎innodb事務日志中的核心日志文件之一,俗稱重做日志,主要用作前滾的數據恢復。

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

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

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

journal

journal是MongoDB存儲引擎層面的概念,MongoDB主要支持的mmapv1、wiredtiger、mongorocks等存儲引擎,都?持配置journal。MongoDB可以基于journal來恢復因為崩潰未及時寫到磁盤的信息。

MongoDB 所有的數據寫?、讀取最終都是調存儲引擎層的接?來存儲、讀取數據,journal 是存儲引擎存儲數據時的一種輔助機制。

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

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

所以建議「一定要開啟journal」,開啟journal后,每次寫入會記錄一條操作日志(通過journal可以重新構造出寫入的數據)。這樣即使出現宕機,啟動時 Wiredtiger 會先將數據恢復到最近的一次checkpoint的點,然后重放后續的 journal操作日志來恢復數據。

MongoDB與MySQL關于寫確認的異同

binlog/oplog

MySQL的binlog和MongoDB的oplog都是數據庫層面的寫操作對應的邏輯日志,主要用于實現數據在主備之間的同步復制以及增量備份和恢復。

binlog

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

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

MongoDB與MySQL關于寫確認的異同

上圖是MySQL主從之間是如何實現數據復制的,其中的三個重要過程是:

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

這樣源源不斷的復制,實現了數據在數據庫節點之間的一致。

oplog

oplog是MongoDB數據庫層面的概念,在復制集架構下,主備節點之間通過oplog來實現節點間的數據同步。Primary中所有的寫入操作都會記錄到MongoDB Oplog中,然后從庫會來主庫一直拉取Oplog并應用到自己的數據庫中。這里的Oplog是MongoDB local數據庫的一個集合,它是Capped collection,通俗意思就是它是固定大小,循環使用的。

oplog 在 MongoDB 里是一個普通的 capped collection,對于存儲引擎來說,oplog只是一部分普通的數據而已。

只有按復制集架構啟動的節點會自動在local庫中創建oplog.rs的集合。

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

MongoDB與MySQL關于寫確認的異同

上圖是MongoDB主備之間如何實現數據復制的,其中的四個重要過程是:

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

這樣源源不斷的復制,實現了數據在數據庫節點之間的一致。

另外MongoDB支持鏈式復制,即oplog不一定從Primary中獲取,還可以從其他Secondary獲取。上圖是MongoDB主備之間如何實現數據復制的,其中的四個重要過程是:

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

這樣源源不斷的復制,實現了數據在數據庫節點之間的一致。

另外MongoDB支持鏈式復制,即oplog不一定從Primary中獲取,還可以從其他Secondary獲取。

redo與binlog

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

MongoDB與MySQL關于寫確認的異同

journal與oplog

journal日志是在wiretiger、mmapV1等存儲引擎層產生,而oplog是MongoDB數據庫的主從復制層面的概念,oplog也與存儲引擎無關;

兩種日志記錄的內容形式不同。MongoDB的oplog是邏輯日志,其記錄的是對應的寫操作的內容。而journal存儲的物理修改;

兩種日志與記錄寫入磁盤的時間點不同。

MongoDB 復制集里寫入一個文檔時,需要修改如下數據

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

MongoDB與MySQL關于寫確認的異同

寫確認

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

MongoDB

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

write concern

write concern支持3個配置項:

{ w: , j: , wtimeout: }

其中:

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

副本集下的寫確認

下面以一個副本集架構來描述,一個寫操作的流程,來認識MongoDB下的寫確認。

MongoDB與MySQL關于寫確認的異同

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

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

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

MongoDB與MySQL關于寫確認的異同

MySQL

MySQL數據庫在所謂寫確認或寫成功方面可以通過執行事務的commit提交來體現,提交成功則為寫成功。因此我主要從事務在執行事務以及commit事務的過程中,涉及的redo log、binlog以及兩種日志的刷盤和主從復制的流程來分析MySQL的寫成功相關的設置和問題。

MySQL復制架構

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

MySQL中有幾種常見復制機制:

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

MongoDB與MySQL關于寫確認的異同

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

MongoDB與MySQL關于寫確認的異同

  • 組復制。由若干個節點共同組成一個復制組,一個事務的提交,必須經過組內大多數節點(N / 2 + 1)決議并通過,才能得以提交。比如由3個節點組成一個復制組,Consensus層為一致性協議層,在事務提交過程中,發生組間通訊,由2個節點決議(certify)通過這個事務,事務才能夠最終得以提交并響應。

除了組復制,半同步復制技術是性能和安全相對更好的設計,尤其在5.7版本中,優化了之前版本的半同步復制相關的邏輯,因此我們主要以5.7版本來介紹。

MySQL5.6/5.5半同步復制的原理:提交事務的線程會被鎖定,直到至少一個Slave收到這個事務,由于事務在被提交到存儲引擎之后才被發送到Slave上,所以事務的丟失數量可以下降到最多每線程一個。因為事務是在被提交之后才發送給Slave的,當Slave沒有接收成功,并且Master掛了,會導致主從不一致:主有數據,從沒有數據。這個被稱為AFTER_COMMIT。


MySQL5.7在Master事務提交的時間方面做了改進,事務是在提交之前發送給Slave(AFTER_SYNC),當Slave沒有接收成功,并且Master宕機了,不會導致主從不一致,因為此時主還沒有提交,所以主從都沒有數據。

MongoDB與MySQL關于寫確認的異同


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

MySQL寫確認行為

我們以MySQL的5.7版本的半同步復制的主從架構的為例子,來介紹MySQL各個參數對寫確認即commit的不同影響。

MongoDB與MySQL關于寫確認的異同

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

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

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

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

下面將把上面介紹的與刷盤有關的配置項引入這整個過程,來看寫操作不同的行為和風險。

MongoDB與MySQL關于寫確認的異同

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

但是在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都在系統緩存中,可以使用帶蓄電池后備電源的緩存cache,防止系統斷電異常。

此外,rpl_semi_sync_master_wait_for_slave_count參數是控制同步到多少個節點的,類似MongoDB中write concern中的 w 參數,如果這個參數設置為0(其實不能,最低1),則變為了純粹的異步復制;如果這個參數設置為最大(所有從節點個數),則變為了純粹的同步復制,因此這個地方也可以根據需要來進行調整,來提交數據的安全。

同時,有可能影響同步模式的還包括rpl_semi_sync_master_wait_no_slave參數、影響復制等待超時的參數rpl_semi_sync_master_timeout等。當rpl_semi_sync_master_wait_no_slave為OFF時,只要master發現Rpl_semi_sync_master_clients小于rpl_semi_sync_master_wait_for_slave_count,則master立即轉為異步模式;如果為ON時,如果在事務提交階段(master等待ACK)超時rpl_semi_sync_master_timeout,master會轉為異步模式。

對比

配置比較

MongoDB與MySQL關于寫確認的異同

其他

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

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

總結

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

由于涉及的內容非常多,未對所有的情況進行測試驗證,可能有疏漏或錯誤,希望大家不吝賜教。也希望本篇內容對于對MySQL和MongoDB都有興趣的同學可以作為一個總結和參考。


參考資料

高性能MySQL( https://item.jd.com/11220393.ht ml
MongoDB官方手冊( https://docs.mongodb.com/manual /
深入淺出MongoDB復制( https://mongoing.com/archives/5 200
mysql基于binlog的復制( 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日志系統之redo log和bin log( https://www.jianshu.com/p/4bcfffb27 ed5
MySQL 5.7 半同步復制增強【轉】( https://www.cnblogs.com/mao3714/p/8 777470.html
MySQL 中Redo與Binlog順序一致性問題  【轉】( https://www.cnblogs.com/mao3714/p/8 734838.html
詳細分析MySQL事務日志(redo log和undo log)( https://www.cnblogs.com/f-ck-need-u /archive/2018/05/08/9010872.html
MySQL 的"雙1設置"-數據安全的關鍵參數(案例分享)( https://www.cnblogs.com/kevingrace/ p/10441086.html
rpl_semi_sync_master_wait_no_slave 參數研究實驗( https://www.cnblogs.com/konggg/p/12 205505.html
MySQL5.7新特性半同步復制之AFTER_SYNC/AFTER_COMMIT的過程分析和總結( http://blog.itpub.net/15498/vi ewspace-2143986/

以上,Enjoy~

點擊【 閱讀】,可了解更多數據庫相關詳請

MongoDB與MySQL關于寫確認的異同

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

宁晋县| 绥德县| 安西县| 海淀区| 斗六市| 石林| 武宣县| 石门县| 漠河县| 福海县| 平度市| 达日县| 灌南县| 高唐县| 从江县| 鸡泽县| 宁津县| 德格县| 江川县| 澄江县| 天全县| 苗栗县| 大港区| 宜兰县| 错那县| 秭归县| 梅河口市| 弥勒县| 德江县| 海口市| 蒲江县| 隆化县| 云南省| 铁岭县| 长顺县| 阜宁县| 稻城县| 温州市| 马山县| 太原市| 上杭县|