mongodb的write concern

原文鏈接

mongodb有一個write concern的設置,作用是保障write operation的可靠性。一般是在client driver裏設置的,和db.getLastError()方法關係很大

一般來說,所有的mongo driver,在執行一個寫操作(insert、update、delete)之後,都會立刻調用db.getLastError()方法。這樣才有機會知道剛纔的寫操作是否成功,如果捕獲到錯誤,就可以進行相應的處理。處理邏輯也是完全由client決定的,比如寫入日誌、拋出錯誤、等待一段時間再次嘗試寫入等。作爲mongodb server並不關心,server只負責通知client發生了錯誤

這裏有2點需要注意:

1、db.getLastError()方法是由driver負責調用的,所以業務代碼不需要去顯式調用。這點後面還會專門提到

2、driver一定會調用db.getLastError()函數,但是並不一定能捕獲到錯誤。這主要取決於write concern的設置級別,這也是本文的主題

write concern:0(Unacknowledged)

此級別調用的時序圖如下:

driver調用了getLastError()之後,mongod立刻返回結果,然後才實際進行寫操作。所以getLastError()的返回值一定是null,即使之後的Apply發生了錯誤,driver也不知道。使用這個級別的write concern,driver的寫入調用立刻返回,所以性能是最好的,但是可靠性是最差的,因此並不推薦使用。在各平臺最新版本的driver中,也不再以0作爲默認級別。其實還有一個w:-1的級別,是error ignored,基本上和w:0差不多。區別在於,w:-1不會捕獲任何錯誤,而w:0可以捕獲network error

write concern:1(acknowledged)

此級別調用的時序圖如下:

和Unacknowledged的區別是,現在mongod只有在Apply(實際寫入操作)完成之後,纔會返回getLastError()的響應。所以如果寫入時發生錯誤,driver就能捕獲到,並進行處理。這個級別的write concern具備基本可靠性,也是目前mongodb的默認設置級別

 

write concern:1 & journal:true(Jounaled)

此級別調用的時序圖如下:

 

Acknowledged級別的write concern也不是絕對可靠的。因爲mongodb的Apply操作,是將數據寫入內存,定期通過fsync寫入硬盤。如果在Apply之後,fsync之前mongod掛了,或者甚至server掛了,那持久化實際上是失敗的。但是在w:1的級別下,driver無法捕獲到這種情況下的error(因爲response在apply之後就已經返回到driver)

mongod解決這個問題的辦法是使用Journal機制,寫操作在寫入內存之後,還會寫到journal文件中,這樣如果mongod非正常down掉,重啓以後就可以根據journal文件中的內容,來還原寫操作。在64位的mongod下,journal默認是打開的。但是32位的版本,需要用--journal參數來啓動

在driver層面,則是除了設置w:1之外,再設置journal:true或j:true,來捕獲這個情況下的error

 

write concern:2(Replica Acknowledged)

這個級別只在replica set的部署模式下生效

 

這個級別下,只有secondary從primary完成了複製之後,getLastError()的結果纔會返回。也可以同時設置journal:true或j:true,則還要等journal寫入也成功後纔會返回。但是注意,只要primary的journal寫入就會返回,而不需要等待secondary的journal也寫入。類似的也可以設置w:3,表示至少要有3個節點有數據;或者w:majority,表示>1/2的節點有數據。一般小規模的集羣就是3節點部署,所以配置w:2就可以了

建議

設置write concern級別,其實就是在寫操作的性能和可靠性之間做權衡。寫操作的等待時間越長,可靠性就越好。對於非關鍵數據,建議使用默認的w:1就可以了,對於關鍵數據,則使用w:1 & j:true比較好。這裏要注意,journal無論如何都是建議打開的,設置j:true,只是說driver調用getLastError()之後是否要等待journal寫入完成再返回。並不是說不設置j:true就關閉了server端的journal

關於getLastError()

一般來說,開發者寫的代碼,不需要自行調用db.getLastError()函數,driver在每一個寫操作之後,都會立刻自動調用該方法

 

Javascript代碼  收藏代碼
  1. db.collection("test", {}, function (err, collection) {  
  2.         collection.insert({name: "world peace"}, function (err, result) {  
  3.             assert.equal(null, err);  
  4.             console.log(result);  
  5.             db.close();  
  6.         })  
  7.   
  8.     });  


這段代碼,driver在insert()之後,隱式調用db.getLastError(),如果捕獲到任何錯誤,就會賦給回調函數中的err參數。區別就在於是否能夠捕獲到錯誤。在w:-1時,err永遠是null(沒有機會捕獲到error);在w:0時,一般也捕獲不到,除了network error;在w:1時,如果mongod apply發生錯誤,就會傳遞給err參數了。代碼都是一樣的,區別就在於設置的write concern級別


發佈了52 篇原創文章 · 獲贊 23 · 訪問量 26萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章