MongoDB 寫安全(Write Concern)

xiaoliuliu2050發表於2018-07-09

MongoDB Write Concern,簡稱MongoDB寫入安全機制,是一種客戶端設定,用於控制寫入安全的級別。Write Concern 描述了MongoDB寫入到mongod單例項,副本集,以及分片叢集時何時應答給客戶端。預設情況下,mongoDB文件增刪改都會一直等待資料庫響應(確認寫入是否成功),然後才會繼續執行。本文講述了MongoDB 應答機制及相關引數。

一、MongoDB應答機制

    MongoDB應答機制就是說對於當前資料庫的寫入成功與否告知客戶端(db.getLastError())。如下:
            mongoDB client發出寫入(或更新)請求---->mongoDB Server端寫入---->通知客戶端已經寫入OK
    主要分為2種應答機制
            應答式寫入(預設情形,安全寫入,適用於資料強一致性場景)
            非應答式寫入(非安全寫入,適用於資料弱一致性場景)
    實現方式
            通過Write Concern來實現,客戶端驅動呼叫db.getLastError()方法,錯誤返回給客戶端
            如果捕獲到錯誤,則可以通過客戶端定義的邏輯嘗試再次寫入或記錄到特定日誌等
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

二、Write Concern用法

    { w: <value>, j: <boolean>, wtimeout: <number> }

    w : 該選項要求確認操作已經傳播到指定數量的mongod例項或指定標籤的mongod例項
            w可選的的值
                    <number>
                            w:1(應答式寫入)
                                    要求確認操作已經傳播到指定的單個mongod例項或副本集主例項(預設為1)
                            w:0(非應答式寫入)
                                    不返回任何響應,所以無法知道寫入是否成功
                                    但是對於嘗試向已關閉的套接字寫入或者網路故障會返回異常資訊
                            w:>1(用於副本集環境)
                                    該值用於設定寫入節點的數目,包括主節點

            "majority"(大多數)
                    適用於叢集架構,要求寫入操作已經傳遞到絕大多數投票節點以及主節點後進行應答

            <tag set>
                    要求寫入操作已經傳遞到指定tag標記副本集中的成員後進行應答

    j : 該選項要求確認寫操作已經寫入journal日誌之後應答客戶端(需要開啟journal功能)
            則在意外重啟,當機等情形下可以通過journal來進行資料恢復
            寫入journal操作必須等待直到下次提交日誌時完成寫入
            為降低延遲,MongoDB可以通過增加commit journal的頻率來加快journal寫入

    wtimeout:
            該選項指定一個時間限制,以防止寫操作無限制被阻塞導致無法應答給客戶端
            wtimeout的單位為ms,當w值大於1時生效,該引數即僅適用於叢集環境
            當某個節點寫入時超出指定wtimeout之後,mongod將返回一個錯誤
            在捕獲到超時之前,mongod並不會撤銷其他節點已成功完成的寫入
            wtimeout值為0時等同於沒有配置wtimeout選項,容易導致由於某個節點掛起而無法應答

    對於單例項應答的情形,是將資料寫入到記憶體後開始應答,除非j:true,則保證掉電後不會丟失資料
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

三、幾種不用應答模式圖示說明

1、非應答式寫入圖示

    MongoDB不對客戶端進行應答,驅動會檢查套接字,網路錯誤等。
    mongos> db.version()
    3.2.9
    mongos> db.version()
    3.2.9
    mongos> db
    test
    mongos> db.blogs.insert({ename:"leshami",url:"http://blog.csdn.net/leshami"},{writeConcern:{w:0}})
    WriteResult({ })   //此處應答為空

    mongos> db.blogs.find({},{_id:0})
    { "ename" : "leshami", "url" : "http://blog.csdn.net/leshami" }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

這裡寫圖片描述

2、應答式寫入圖示

    應答式寫入是預設值
    MongoDB會在收到寫入操作並且確認該操作在記憶體中應用後進行應答,但不會確認資料是否已寫入磁碟
    同時允許客戶端捕捉網路、重複key等等錯誤

    mongos> db.blogs.insert({ename:"john",url:"http://blog.csdn.net/john"},{writeConcern:{w:1}})
    WriteResult({ "nInserted" : 1 })    //此處應答資訊顯示為1個文件已插入

    mongos> db.blogs.find({},{_id:0})
    { "ename" : "leshami", "url" : "http://blog.csdn.net/leshami" }
    { "ename" : "john", "url" : "http://blog.csdn.net/john" }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

這裡寫圖片描述

3、帶journal應答式寫入圖示

    確認寫操作已經寫入journal日誌之後應答客戶端,必須允許了日誌功能,才能生效。
    寫入journal操作必須等待直到下次提交日誌時完成寫入
    提供通過journal來進行資料恢復
  • 1
  • 2
  • 3
  • 4

這裡寫圖片描述

4、副本集應答寫入圖示

    對於使用副本集的場景,預設情況下僅僅從主(首選)節點進行應答
    建議修改預設的應答情形為特定數目或者majority來保證資料的可靠
    如下示例,w值為2,超時為5s
            db.products.insert(
               { item: "envelopes", qty : 100, type: "Clasp" },
               { writeConcern: { w: 2, wtimeout: 5000 } }
            )       
    如果不希望每次在增刪改時新增writeConcern,可以通過設定settings.getLastErrorDefaults
    如下示例,
            cfg = rs.conf()
            cfg.settings = {}
            cfg.settings.getLastErrorDefaults = { w: "majority", wtimeout: 5000 }
            rs.reconfig(cfg)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

這裡寫圖片描述

四、小結

1、write concern用於控制寫入安全的級別,可以分為應答式寫入以及非應答式寫入 
2、write concern是一個效能和資料強一致性的權衡,應根據業務場景進行設定 
3、對於強一致性場景,建議w>1或者等於majority,以及journal為true,否則w=0 

4、在副本集的情形下,建議通過配置檔案來修改w以及設定wtimeout,以避免由於某個節點掛起導致無法應答



具體使用邏輯:

mongotemplate 設定writeconcern 用來標識什麼情況下 返回寫結果。

設定writeResultChecking 用來標識對寫結果 怎麼處理。


如果 mongo 遇到了可以處理的異常,會自動丟擲異常。

如果MongoDB執行過程中,遇到了伺服器異常(內部異常),會寫到writeResult 中,

這個時候 根據writeResultChecking 的值對writeResult 做不同的解析,


在資料強一致性要求下,可以設定writeconcern w1 ,writeResultChecking exception 保證dao 層使用丟擲異常。

在資料若一致性要求下,可以設定writeconcern none ,writeResultChecking none .




相關文章