標籤:content 目錄 記憶體日誌 指定 s函數 學習 服務 作用 _id
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) |
函數指令碼
| 1234567891011121314 |
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