Mongodb通過GetLastError命令寫入安全機制

來源:互聯網
上載者:User

一、簡介

很多人抱怨mongodb是記憶體資料庫,也沒有事務,會不安全,其實這都是對Mongodb的誤解,Mongodb有完整的redolog,binlog和持久化機制,不必太擔心資料丟失問題。

journal是Mongodb中的redo log,而Oplog則是負責複製的binlog(對應Mysql)。

在google.groupuser上,mongo的開發人員有一段這樣的解釋:

#########
By default:
Collection data (including oplog) is fsynced to disk every 60 seconds.
Write operations are fsynced to journal file every 100 milliseconds.
Note, oplog is available right away in memory for slaves to read. Oplog is a capped collection
so a new oplog is never created, old data just rolls off.
GetLastError with params:
(no params) = return after data updated in memory.
fsync: true:
with –journal = wait for next fsync to journal file (up to 100 milliseconds);
without –journal = force fsync of collection data to disk then return.
w: 2 = wait for data to be updated in memory on at least two replicas.
########

可以看到:

1、如果開啟journal,那麼即使斷電也只會丟失100ms的資料,這對大多數應用來說都可以容忍了。從1.9.2+,mongodb都會預設開啟journal功能,以確保資料安全。而且journal的重新整理時間是可以改變的,2-300ms的範圍,使用 –journalCommitInterval 命令。

2、Oplog和資料重新整理到磁碟的時間是60s,對於複製來說,不用等到oplog重新整理磁碟,在記憶體中就可以直接複製到Sencondary節點。

GetLastError Command

getLastError 是Mongodb的一個命令,從名字上看,它好像是取得最後一個error,但其實它是Mongodb的一種用戶端阻塞方式。用這個命令來獲得寫操作是否成功的資訊。

getlastError有幾個參數:j,w,fsync。在大多數的語言驅動中,這個命令是被封裝成writeConcern類,比如java。

二、什麼時候使用這個命令:

1、Mongodb的寫操作預設是沒有任何傳回值的,這減少了寫操作的等待時間,也就是說,不管有沒有寫入到磁碟或者有沒有遇到錯誤,它都不會報錯。但一般我們是不放心這麼做的,這時候就調用getlastError命令,得到傳回值。

以java為例,舉個例子:當我們為欄位建立了一個唯一索引,針對這個欄位我們插入兩條相同的資料,不設定WriterConcern或者設定WriterConcern.NORMAL模式,這時候即便拋出異常,也不會得到任何錯誤。insert()函數在java中的傳回值是WriteResult類,
WriteResult( CommandResult o , WriteConcern concern ){
        _lastErrorResult = o;
        _lastConcern = concern;
        _lazy = false;
        _port = null;
        _db = null;
    }

這個類實際上封裝了getlastError的傳回值,但是這時候WriteResult的_lastErrorResult屬性實際上是空的。因為dup key錯誤是server error,只有在WriterConcern.SAFE或更進階別的模式下,才會得到server error。

2、在多線程模式下讀寫Mongodb的時候,如果這些讀寫操作是有邏輯順序的,那麼這時候也有必要調用getlasterror命令,用以確保上個操作執行完下個操作才能執行,因為兩次執行的串連有可能是不同的。在大多數情況下,我們都會使用串連池去串連mongodb,所以這是需要注意的。

舉個例子:我們之前遇到這個異常”The connection may have been used since this write, cannot obtain a result”,異常原因有兩個,串連池數量太小,競爭太激烈,沒有設定writerConcern.SAFE。
參見:https://groups.google.com/forum/?fromgroups=#!topic/mongodb-user/xzw0Cb831VY
PS:在java等語言中,是不需要顯示調用這個命令的,只需要設定WriterConcern即可。

三、getlastError最佳實務

1、如果沒有特殊要求,最低層級也要使用WriterConcern.SAFE,即w=1。

2、對於不重要的資料,比如log日誌,可以使用WriterConcern.NONE或者WriterConcern.NORMAL,即w=-1或者w=0,省去等待網路的時間。

3、對大量的不連續的資料寫入,如果每次寫入都調用getLastError會降低效能,因為等待網路的時間太長,這種情況下,可以每過N次調用一下getLastError。但是在Shard結構上,這種方式不一定確保之前的寫入是成功的。

4、對連續的批量寫入(batchs of write),要在批量寫入結束的時候調用getlastError,這不僅能確保最後一次寫入正確,而且也能確保所有的寫入都能到達伺服器。如果連續寫入上萬條記錄而不調用getlastError,那麼不能確保在同一個TCP socket裡所有的寫入都成功。這在並發的情況下可能就會有問題。避免這個並發問題,可以參考如何在一個連結(請求)裡完成大量操作,URL:java driver concurrency

http://www.mongodb.org/display/DOCS/Java+Driver+Concurrency

5、對資料安全要求非常高的的配置:j=true,w=”majority” db.runCommand({getlasterror:1,j:true,w:’majority’,wtimeout:10000})
java語言可以在MongoOption中設定,MongoOption中的這些設定是全域的,對於單獨的一個(串連)操作,還可以分別設定。

參考:
1、http://www.mongodb.org/display/DOCS/Journaling
2、http://www.mongodb.org/display/DOCS/Java+Driver+Concurrency
3、http://www.mongodb.org/display/DOCS/getLastError+Command

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.