什么是writeConcern
writeConcern決定一個寫操作落到多少個節點上才算成功,這決定了mongodb是否會丟失數據。
writeConcern的取值包括:
- 0:發起寫操作,不關心是否成功;
- 1~集群最大數據節點數:寫操作需要被復制到指定節點數才算成功;
- majority:寫操作需要被復制到大多數節點上才算成功。
發起寫操作的程序將阻塞到寫操作到達指定的節點數為止。
默認行為
應用程序試圖寫入x=1,進入mongodb的primary節點,一旦寫入primary(未必是寫到磁盤里,可能只是寫入到內存中),就向客戶端響應acknowledge。
之后由mongodb另外的線程將數據由primary異步復制到secondary1和secondary2。此時如果primary發生crash,會導致該數據丟失。
w:"majority"
要解決上述問題,可以使用大多數節點確認模式。
當x=1寫入primary后沒有返回,寫入進程等待數據復制到secondary1或者secondary2后primary發送acknowledge。
此時如果primary發生crash,secondary1會成為新的主節點。
w:"all"
數據要寫入全部節點,才返回成功。
j:true
日志的作用是給一個數據庫節點在宕機的時候可以快速恢復剛才的寫操作,所以一般數據庫都先寫日志文件,再寫數據文件。
默認一個操作進到primary內存的時候,並不會等寫日志,而就返回了。
writeConcern可以決定寫操作到達多少個節點才算成功,journal則定義如何才算成功。取值包括:
- true:寫操作落到journal文件中才算成功;
- false:寫操作達到內存計算成功。
writeConcern的意義
對於5個節點的復制集來說,寫操作落到多少個節點上才算是安全的?
- 1
- 2
- 3
- 4
- 5
- majority
writeConcern實驗
在復制集測試writeConcern參數
db.test.insert({count:1},{writeConcern:{w:"majority"}})
db.test.insert({count:1},{writeConcern:{w:3}})
db.test.insert({count:1},{writeConcern:{w:4}})
配置延遲節點,模擬網絡延遲(復制延遲)
conf=rs.conf()
conf.members[2].slaveDelay=5 // 等待5s去同步主節點數據
conf.memvers[2].priority=0 // 如果有延遲,則不可以參與選舉
rs.reconfig(conf)
觀察復制延遲下的寫入,以及timeout參數
db.test.insert({count:1},{writeConcern:{w:3}})
db.test.insert({count:1},{writeConcern:{w:3,wtimeout:3000}}) // 數據可能已經寫入,需要根據日志等進行后續操作
注意事項
- 雖然多余問半數的writeConcern都是安全的,但通常只會設置majority,因為這是等待寫入延遲時間最短的選擇;
- 不要設置writeConcern等於總節點數,因為一旦有一個節點故障,所有寫操作都將失敗;
- writeConcern雖然會增加寫操作延遲時間,但並不會顯著增加集群壓力,因此無論是否等待,寫操作最終都會復制到所有節點上。設置writeConcern只是讓寫操作等待復制后再返回而已;
- 贏對重要數據應用{w:"majority"},普通數據可以應用{w:1}以確保最佳性能。