1. 程式人生 > >MongoDB 學習筆記之 WriteConcern

MongoDB 學習筆記之 WriteConcern

行數據 num 部署 knowledge setting 其余 map not back

WriteConcern:

轉載:MongoDB WriteConcern(寫關註)機制

http://www.ywnds.com/?p=3688&viewuser=40

MongoDB部署模式

MongoDB的部署模式有三種:第一種是單機模式(開發測試);第二種是高可用復制集;第三種是可擴展分片集群。如下圖所示。

技術分享

知道了MongoDB幾種常用的部署模式之後,接下來我們看看每種部署模式的寫操作過程。

MongoDB單點寫操作

技術分享

從上圖可以看出,其中primary是MongoDB的一個實例,裏面有兩個內存區域,一個是Data Buffer(數據緩沖)、一個是Journal Buffer(日誌緩沖)。這兩個內存區域分別對應物理文件Data File和Journal File。

當數據寫入進來時,就會出現如下執行順序:

技術分享

1) 客戶端的數據進來;

2) 數據操作寫入到日誌緩沖;

3) 數據寫入到數據緩沖;

4) 返回操作結果到客戶端(異步);

5) 後臺線程進行日誌緩沖中的數據刷盤,非常頻繁(默認100)毫秒,也可自行設置(30-60);

6) 後臺線程進行數據緩沖中的數據刷盤,默認是60秒;

MongoDB復制集寫操作

技術分享

復制集也是MongoDB最常見的一種部署模式,如果啟用復制集的話,在內存中會多一個OPLOG區域,是在節點之間進行同步的一個手段,它會把操作日誌放到OPLOG中來,然後OPLOG會復制到從節點上。從節點接收並執行OPLOG中的操作日誌來達到數據的同步操作。

1) 客戶端的數據進來;

2) 數據操作寫入到日誌緩沖;

3) 數據寫入到數據緩沖;

4) 把日誌緩沖中的操作日誌放到OPLOG中來;

5) 返回操作結果到客戶端(異步);

6) 後臺線程進行OPLOG復制到從節點,這個頻率是非常高的,比日誌刷盤頻率還要高,從節點會一直監聽主節點,OPLOG一有變化就會進行復制操作;

7) 後臺線程進行日誌緩沖中的數據刷盤,非常頻繁(默認100)毫秒,也可自行設置(30-60);

8) 後臺線程進行數據緩沖中的數據刷盤,默認是60秒;

恢復日誌Journal的作用

1) 用於系統宕機時恢復內存數據(不能像MySQL一樣可以用來恢復歷史數據)

2) 默認為異步刷盤

3) 刷盤間隔,MMAP引擎為30-100ms,Wiredtiger為100MB or checkpoint

4) 可使用j:1來強制同步刷盤

寫關註機制Write Concern的作用

1) 用來指定mongod對寫操作的回執行為。

2) 可在connection level或者寫操作level指定。

3) Write conern支持以下值。

W: 0 | 1 | N | majority | tag

j:1

wtimeout:millis

1)當w:0為Unacknowledged

技術分享

測試(會出現的數據丟失情況)

技術分享

這裏寫一個循環插入10條數據,插入數據{_id:10,a:i},然後把writeConcern設置為0。根據上圖我們可以看到print返回10條插入成功的信息,但是我們db.test.count()查看時只有一條數據,其余9條雖然沒有插入成功但是也返回了正確信息(因為第一條數據_id:10為唯一鍵,再插入同樣的數據就無法插入,兩個ID不能相同)。就因為{writeConcern:{w:0}}導致出現異常時並沒有返回錯誤信息給客戶端。

2)當w:1為Acknowledged

技術分享

測試(會出現的數據丟失情況)

技術分享

當w:1時,就解決了w:0出現的問題,從上圖可以看出第一條數據插入成功,其余9條數據都會插入失敗並返回錯誤信息給客戶端。

但是當w:1時mongodb就會在日誌寫完之後返回確定信息,雖然解決了w:0出現的數據丟失問題,但是w:1時如果出現系統崩潰也會導致數據丟失,那就是在日誌信息還沒有刷新到磁盤的那一刻發生系統宕機,此時內存日誌的確是寫入成功了於是mongodb就會返回確定信息。

我們可以通過w:1然後高速寫入數據,然後通過killall -9 mongod來模擬系統崩潰(重啟系統時要記住刪除數據目錄下的mongod.lock文件,不然啟動起不來),最後檢查程序寫入的數據和實際插入的數據(這種情況發生幾率不大)。

技術分享

通過上圖可以看出,數據丟失了731條。做上面這個實驗時在執行journaldataloss函數時,需要開啟另外一個會話用來模擬服務器宕機(killall -9 mongod)

針對w:1出現的服務器宕機時數據丟失的問題可以使用j:1來解決,j:1做到的是日誌刷盤之後才會返回確定信息。

1 > db.test.validate(true)

函數腳本

1 2 3 4 5 6 7 8 9 10 11 12 13 14 function journaldataloss(){ var count=0, start = new Date(); try{ var docs=[]; for(var i=0;i<1000;i++) docs.push({a:i}); while(true){ var res=db.test.insert(docs); count += res.nInserted; if(count % 100000 == 0) print("inserted "+ count+"time used: " + (new Date().getTime() - start.getTime()/1000) +" seconds"); } } catch(error){ print("Total doc inserted successfully:"+ count); } }

3)當j:1為Journal

技術分享

實例(測試會出現的數據丟失情況)

技術分享

另一種情況

技術分享

當j:1時可以解決w:1數據丟失的問題,但是隨之而來的是Mongodb的性能會下降。雖然解決了服務器宕機時數據丟失問題(會丟失60s左右的數據,就是一次間隔沒有刷新到磁盤的數據)。

但是無法解決另外一種情況,無論是w:1還是j:1都無法解決主備置換導致數據丟失的情況。上面我們介紹了MongoDB三種部署模式以及每一種模式的寫操作流程。看下面這幅圖,

技術分享

當j:1時可以保證主節點數據的決定安全性,當日誌落盤之後返回確定信息給客戶端,那麽接下來就會復制OPLOG到復制集中的從節點如果此時主節點宕機,OPLOG沒有復制到從節點並且當主節點宕機後,Mongodb復制集會重新選舉臺secondary為primary。當secondary為primary後假設此時原先的primary被恢復了,啟動之後成為了secondary節點,此時新的primary發現secondary有x數據而自己沒有,那麽此時就會出現數據回滾的情況,secondary會把x數據進行回滾到一個磁盤文件上(rollback_db_name),回頭需要人工去處理,從用戶角度出現這也是一種數據丟失的情況。那麽怎麽解決這種情況呢?就是下面我們要提到的w:2/N/majority可以解決這個數據丟失的情況,w:2決定了數據必須復制最少到一個從節點上時才會返回確定信息給客戶端。

4)當w:2/N/majority replica Acknowledged

技術分享

顯然這種方式雖然保證了數據的一致性,但是無疑會拖慢MongoDB的性能。所以在MongoDB 3.2後官方又給出了一個readconcern機制,具體待研究。

Write concern總結

通過上面幾幅圖對Write concern的解釋可以看出,這是一個對數據安全非常重要的參數,不管是開發還是運維人員都應該對Write concern機制非常了解。對於Write concern來說,級別越高數據越安全,但同時性能就會下降,在數據安全跟性能方面一向如此不能兼得。可根據自己的應用場景來決定Write concern的級別(默認是w:1)。其實j:1到不是特別重要,如果你使用好的復制集同時數據又特別重要的話就可以使用w:majority,因為mongodb中復制集的數據往往比日誌跑的更快,也是一種更有效的方法。下圖是對wirte concern的基本總結。

技術分享

MongoDB 學習筆記之 WriteConcern