1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        掌握WiredTiger存儲引擎,幫你解決分布式事務(wù)難題!

        共 4157字,需瀏覽 9分鐘

         ·

        2022-05-14 10:39

        ??點擊“博文視點Broadview”,獲取更多書訊

        MongoDB作為領(lǐng)先的NoSQL,為了支撐更多的需求場景,也在不斷完善其功能。從早期支持大吞吐量讀/寫操作的MMAPv1存儲引擎,到引入支持高并發(fā)操作的WiredTiger存儲引擎,以及對事務(wù)功能的持續(xù)演進(jìn),MongoDB不僅保留了最初的架構(gòu)優(yōu)勢,同時又汲取了其他數(shù)據(jù)庫的優(yōu)點。

        MongoDB從 3.0版本引入WiredTiger存儲引擎之后開始支持事務(wù),MongoDB 3.6之前的版本只能支持單文檔的事務(wù),從MongoDB 4.0版本開始支持復(fù)制集部署模式下的事務(wù),從MongoDB 4.2版本開始支持分片集群中的事務(wù)。

        本文就主要對MongoDB事務(wù)的基本原理、事務(wù)的snapshot隔離、實現(xiàn)事務(wù)間并發(fā)操作的MVCC并發(fā)控制機制,以及事務(wù)日志做一些介紹!


        01

        事務(wù)的基本原理

        與關(guān)系型數(shù)據(jù)庫一樣,MongoDB事務(wù)同樣具有ACID特性,說明如下。

        • 原子性(Automicity):一個事務(wù)要么完全執(zhí)行成功,要么不做任何改變。

        • 一致性(Consistency):當(dāng)多個事務(wù)并行執(zhí)行時,元素的屬性在每個事務(wù)中保持一致。

        • 隔離性(Isolation):當(dāng)多個事務(wù)同時執(zhí)行時,互不影響。WiredTiger本身支持多種不同類型的隔離級別,如讀-未提交(read-uncommitted)、讀-已提交(read-committed)和快照(snapshot)隔離。MongoDB默認(rèn)選擇的是快照隔離。

        • 持久性(Durability):一旦提交事務(wù),數(shù)據(jù)的更改就不會丟失。

        在不同隔離級別下,一個事務(wù)的生命周期內(nèi),可能出現(xiàn)臟讀、不可重復(fù)讀、幻讀等現(xiàn)象。

        下面介紹這3種現(xiàn)象出現(xiàn)的場景與含義。

        1. 臟讀現(xiàn)象

        例如,某款手機在數(shù)據(jù)庫中的庫存還有1部,客戶A發(fā)起一個查詢手機庫存的事務(wù),同時,客戶B發(fā)起了一個購買手機的事務(wù)(但未提交事務(wù)),此時客戶A讀到手機庫存為0部,認(rèn)為售完了。但客戶B突然不想購買這款手機了,于是回滾了此事務(wù),手機庫存又變?yōu)?部,客戶A讀到的手機庫存為0部就是一個臟讀數(shù)據(jù),如下圖所示。

        2. 不可重復(fù)讀現(xiàn)象

        例如,某款手機在數(shù)據(jù)庫中的庫存還有1部,客戶A發(fā)起一個查詢手機庫存的事務(wù)(事務(wù)還未完成),讀到其值為1。同時,客戶B發(fā)起了一個購買手機的事務(wù)(提交了事務(wù)),此時客戶A再次查詢手機庫存,讀到其值為0??蛻鬉在同一個事務(wù)中讀到的同一條記錄的取值不一樣,這種現(xiàn)象就是不可重復(fù)讀,如下圖所示。

        3. 幻讀現(xiàn)象

        例如,某款手機在數(shù)據(jù)庫中的庫存還有1部,客戶A發(fā)起一個購買手機的事務(wù)(事務(wù)還未完成),讀到其值為1。同時,管理員B發(fā)起了一個增加1部手機的事務(wù)(提交了事務(wù)),此時客戶A再次查詢手機庫存,讀到其值為1(有新增數(shù)據(jù))。客戶A在同一個事務(wù)中本來應(yīng)該讀到的庫存值為0,認(rèn)為手機已經(jīng)售完,但發(fā)現(xiàn)庫存中還有1部手機,客戶A兩次讀到的數(shù)據(jù)集不一樣,這種現(xiàn)象就是幻讀,如下圖所示。

        下面介紹與事務(wù)相關(guān)的數(shù)據(jù)結(jié)構(gòu),如下圖所示。

         其中,

        (1)id字段:這是事務(wù)的全局唯一標(biāo)識,通過分析它與具體的操作關(guān)聯(lián),就能夠知道一個事務(wù)包含哪些操作。

        (2)snapshot_data字段:MongoDB使用的是快照隔離級別的事務(wù),這個字段用于保存事務(wù)的快照信息,具體來說它會有snap_min和snap_max兩個屬性,通過這兩個屬性能夠計算一個事務(wù)開始時的數(shù)據(jù)范圍,每個事務(wù)開始時都會構(gòu)造一個這樣的快照。

        (3)commit_timestamp字段:表示事務(wù)提交的時間。

        (4)durable_timestamp字段:表示事務(wù)修改的數(shù)據(jù)已持久化的時間,與具體操作中的durable_ts字段關(guān)聯(lián)。

        (5)prepare_timestamp字段:表示事務(wù)開始準(zhǔn)備的時間。

        (6)WT_TXN_OP字段:包含事務(wù)的修改操作,用于事務(wù)回滾和生成事務(wù)日志(Journal)。

        (7)logrec字段:表示事務(wù)日志的緩存,用于在內(nèi)存中保存事務(wù)日志(對于MongoDB來說Journal日志就是事務(wù)日志)。


        02

        事務(wù)的snapshot隔離

        WiredTiger存儲引擎支持read-uncommitted、read-committed和snapshot3種事務(wù)隔離級別,MongoDB啟動時默認(rèn)選擇snapshot隔離。

        事務(wù)開始時,系統(tǒng)會創(chuàng)建一個快照,從已提交的事務(wù)中獲取行版本數(shù)據(jù),如果行版本數(shù)據(jù)標(biāo)識的事務(wù)尚未提交,則從更早的事務(wù)中獲取已提交的行版本數(shù)據(jù)作為其事務(wù)開始時的值。

        通過事務(wù)可以看到其他還未提交的事務(wù)修改的行版本數(shù)據(jù),但不會看到事務(wù)id大于snap_max的事務(wù)修改的數(shù)據(jù)。

        快照數(shù)據(jù)的獲取流程如下圖所示。

        假設(shè)圖中的5個事務(wù)對同一條記錄進(jìn)行操作,E事務(wù)開始時,生成的快照數(shù)據(jù)包含B、D兩個未完成的事務(wù),同時獲取離它最近且完成了的C事務(wù)修改后的值作為事務(wù)開始時的取值,即2。

        如果E事務(wù)為寫事務(wù),對庫存值進(jìn)行修改,則會進(jìn)行沖突檢測,以防止對過期數(shù)據(jù)的修改,保證數(shù)據(jù)的一致性(如D事務(wù)在E事務(wù)提交之前完成,行版本已發(fā)生變化,若E事務(wù)還要進(jìn)行修改,則提交時會產(chǎn)生沖突)。

        通過一段代碼加深對快照隔離級別事務(wù)的認(rèn)識:

        session1 = client.start_session()  //開啟一個sessionsession1.start_transaction()   //在session內(nèi)部,開啟一個事務(wù)inventory.insert_one({'_id': 4, 'model':'switch', 'count': 200}, session= session)doc1 = inventory.find_one({'_id': 4}, session=session1)pprint.pprint(doc1)doc2 = inventory.find_one({'_id': 4})pprint.pprint(doc2)session1.commit_transaction()  //提交事務(wù)doc3 = inventory.find_one({'_id': 4})pprint.pprint(doc3)session1.end_session()    //結(jié)束session

        任何事務(wù)都是封裝在一個session中進(jìn)行的。


        03

        MVCC并發(fā)控制機制

        要實現(xiàn)事務(wù)之間的并發(fā)操作,可以使用鎖機制或MVCC控制等。對于WiredTiger來說,使用MVCC控制來實現(xiàn)并發(fā)操作,相較于其他鎖機制的并發(fā),MVCC實現(xiàn)的是一種樂觀并發(fā)機制。

        MVCC并發(fā)控制機制如下圖所示:

        (1)A事務(wù)首先從表中讀取要修改的行數(shù)據(jù),讀取的庫存值為100,行記錄的版本號為1。

        (2)B事務(wù)也從中讀取要修改的相同行數(shù)據(jù),讀取的庫存值為100,行記錄的版本號為1。

        (3)A事務(wù)修改庫存值后提交,同時行記錄版本號加1,變?yōu)?,大于A事物一開始讀取行記錄版本號1,A事務(wù)可以提交。

        (4)但B事務(wù)提交時發(fā)現(xiàn)此時行記錄版本號已經(jīng)變?yōu)?,產(chǎn)生沖突,B事務(wù)提交失敗。

        (5)B事務(wù)嘗試重新提交,此時再次讀取的版本號為2,加1后版本號變?yōu)?,不會產(chǎn)生沖突,正常提交B事務(wù)。

        通過代碼分析事務(wù)的并發(fā)與沖突。

        session1 = client.start_session() //開啟一個session1session1.start_transaction()  //在session1中開啟一個事務(wù)1inventory.delete_one({'_id':4}, session=session1)doc1 = inventory.find_one({'_id': 4},session=session1)pprint.pprint(doc1)     //輸出none,說明在事務(wù)中已經(jīng)刪除

        session2 = client.start_session() //開啟一個session2session2.start_transaction() //在session2中開啟一個事務(wù)2inventory.delete_one({'_id':4}, session=session2) //執(zhí)行產(chǎn)生事務(wù)沖突

        session1.abort_transaction() //終止事務(wù)1session1.end_session() //結(jié)束session1session2.abort_transaction() //終止事務(wù)2session2.end_session() //結(jié)束session2

        doc2 = inventory.find_one({'_id': 4}) //隱式開啟第3個session和事務(wù)pprint.pprint(doc2) //在事務(wù)外可以找到,說明事務(wù)1被終止后回滾了


        04

        事務(wù)日志(Journal)

        Journal是一種WAL(Write Ahead Log)事務(wù)日志,目的是實現(xiàn)事務(wù)提交層面的數(shù)據(jù)持久化。

        Journal持久化的對象不是修改的數(shù)據(jù),而是修改的動作,以日志形式先保存到事務(wù)日志緩存中,再根據(jù)相應(yīng)的配置按一定的周期,將緩存中的日志數(shù)據(jù)寫入日志文件中。

        事務(wù)日志落盤的規(guī)則如下。

        (1)按時間周期落盤。

        在默認(rèn)情況下,以50毫秒為周期,將內(nèi)存中的事務(wù)日志同步到磁盤中的日志文件。

        (2)提交寫操作時強制同步落盤。

        當(dāng)設(shè)置寫操作的寫關(guān)注為j:true時,強制將此寫操作的事務(wù)日志同步到磁盤中的日志文件。

        (3)事務(wù)日志文件的大小達(dá)到100MB。

        以上內(nèi)容節(jié)選自《MongoDB核心原理與實踐》一書,歡迎閱讀本書更多精彩內(nèi)容。


         

        下單立減50,快快掃碼搶購吧!

         

        如果喜歡本文
        歡迎 在看留言分享至朋友圈 三連

         熱文推薦  





        ▼點擊閱讀原文,了解本書詳情~  

        瀏覽 18
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            无码狠狠躁久久久久久久网址 | 91在线精品秘 一区二区秋霞 | 国产精品久久久久久久免费龙宫 | 国内一区二区在线看 | 国产乱╳╳╳╳性视频大全 | 亚洲AV大片 | 护士在办公室被躁bo1我要 | 国产一级免费网站 | 中文字幕一区二区久久人妻网站 | 不伦 的搜索结果 - 91n |