傳統的主從模式,須要手工指定集羣中的Master。
若是Master發生故障,通常都是人工介入,指定新的Master。
這個過程對於應用通常不是透明的,每每伴隨着應用從新修改配置文件,重啓應用服務器等。算法
而MongoDB副本集,集羣中的任何節點均可能成爲Master節點。
一旦Master節點故障,則會在其他節點中選舉出一個新的Master節點。
並引導剩餘節點鏈接到新的Master節點。這個過程對於應用是透明的。spring
Bully算法是一種協調者(主節點)競選算法,主要思想是集羣的每一個成員均可以聲明它是主節點並通知其餘節點。
別的節點能夠選擇接受這個聲稱或是拒絕並進入主節點競爭。被其餘全部節點接受的節點才能成爲主節點。
節點按照一些屬性來判斷誰應該勝出。這個屬性能夠是一個靜態ID,也能夠是更新的度量像最近一次事務ID(最新的節點會勝出)sql
1.獲得每一個服務器節點的最後操做時間戳。每一個mongodb都有oplog機制會記錄本機的操做,方便和主服務器進行對比數據是否同步還能夠用於錯誤恢復。mongodb
2.若是集羣中大部分服務器down機了,保留活着的節點都爲 secondary狀態並中止,不選舉了。數據庫
3.若是集羣中選舉出來的主節點或者全部從節點最後一次同步時間看起來很舊了,中止選舉等待人來操做。安全
4.若是上面都沒有問題就選擇最後操做時間戳最新(保證數據是最新的)的服務器節點做爲主節點。
選舉的觸發條件:
1.初始化一個副本集時。
2.副本集和主節點斷開鏈接,多是網絡問題。
3.主節點掛掉。
4.人爲介入,好比修改節點優先級等
5.選舉還有個前提條件,參與選舉的節點數量必須大於副本集總節點數量的一半,若是已經小於一半了全部節點保持只讀狀態。服務器
每一個虛擬機都使用以下的配置文件啓動實例:網絡
./mongod --dbpath=/data0/mongodbtest/replset/data/ --logpath=/data0/mongodbtest/replset/log/mongodb.log --port 27017 --replSet repset --maxConns=1000 --logappend --fork
介紹一下mongod啓動涉及到的參數 --dbpath 數據文件路徑 --logpath 日誌文件路徑 --port 端口號,默認是27017.我這裏使用的也是這個端口號. --replSet 複製集的名字,一個replica sets中的每一個節點的這個參 數都要用一個複製集名字,這裏是mvbox. --maxConns 最大鏈接數 --fork 後臺運行 --logappend 日誌文件循環使用,若是日誌文件已滿,那麼新日誌覆蓋最久日誌。
而後在任意一臺虛擬機登錄mongo,輸入以下設置架構
三個副本集組成的集羣
config = { _id:"mvbox", members:[ {_id:0,host:"192.168.1.1:27017"}, {_id:1,host:"192.168.1.2:27017"}, {_id:2,host:"192.168.1.3:27017"}] } rs.initiate(config);
帶有延遲複製的集羣(設置優先級能夠指定主輔副本集)
config = { _id:"repset", members:[
{_id:0,host:"192.168.4.135:27017",priority:2},
{_id:1,host:"192.168.4.136:27017",priority:0,slaveDelay:3600},
{_id:2,host:"192.168.4.138:27017",priority:10}]
}app
rs.initiate(config);
初始化集羣時,設置仲裁者的配置以下
config = { _id:"mvbox", members:[
{_id:0,host:"192.168.1.1:27017"},
{_id:1,host:"192.168.1.2:27017",arbiterOnly:true},
{_id:2,host:"192.168.1.3:27017"}]
}
rs.initiate(config);
注意:mvbox爲集羣名
能夠看到副本集已經生效
可使用rs.status()查看集羣狀態,或者rs.isMaster()
修改節點的優先級能夠觸發從新選舉,這樣能夠人工指定主節點。
使用以下命令,在主節點登陸,將192.168.1.3提高爲Master。
rs.conf(); cfg=rs.conf(); cfg.members[0].priority=1 cfg.members[1].priority=1 cfg.members[2].priority=10 rs.reconfig(cfg);
須要注意的是,修改節點優先級須要登陸Master節點運行。不然報錯。
再次查看集羣狀態,能夠看到192.168.1.3已經做爲Master運行
MongoDB的節點類型有主節點(Master),副本節點(Slave或者稱爲Secondary),仲裁節點,Secondary-Only節點,Hidden節點,Delayed節點和Non-Voting節點。
仲裁節點不存儲數據,只是負責故障轉移的羣體投票,這樣就少了數據複製的壓力。
Secondary-Only:不能成爲primary節點,只能做爲secondary副本節點,防止一些性能不高的節點成爲主節點。
Hidden:這類節點是不可以被客戶端制定IP引用,也不能被設置爲主節點,可是能夠投票,通常用於備份數據。
Delayed:能夠指定一個時間延遲從primary節點同步數據。主要用於備份數據,若是實時同步,誤刪除數據立刻同步到從節點。因此延遲複製主要用於避免用戶錯誤。
Non-Voting:沒有選舉權的secondary節點,純粹的備份數據節點。
6 .設置隱藏節點(Hidden)
隱藏節點能夠在選舉中投票,可是不能被客戶端引用,也不能成爲主節點。也就是說這個節點不能用於讀寫分離的場景。
將192.168.1.3設置爲隱藏節點。
注意,只有優先級爲0的成員才能設置爲隱藏節點。
若是設置優先級不爲0的節點爲隱藏節點,則報錯以下
使用以下命令設置隱藏節點
cfg=rs.conf(); cfg.members[0].priority=10 cfg.members[1].priority=1 cfg.members[2].priority=0 cfg.members[2].hidden=1 rs.reconfig(cfg);
設置完成以後,使用rs.status()查看該節點仍是SECONDARY狀態。
可是經過rs.isMaster()和rs.conf()能夠看到這個節點的變化。
rs.isMaster()的hosts中192.168.1.3節點已經不可見
而且rs.conf()顯示該節點狀態爲hidden
7 .設置仲裁節點
仲裁節點不存儲數據,只是用於投票。因此仲裁節點對於服務器負載很低。
節點一旦以仲裁者的身份加入集羣,他就只能是仲裁者,沒法將仲裁者配置爲非仲裁者,反之也是同樣。
另一個集羣最多隻能使用一個仲裁者,額外的仲裁者拖累選舉新Master節點的速度,同時也不能提供更好的數據安全性。
初始化集羣時,設置仲裁者的配置以下
config = { _id:"mvbox", members:[ {_id:0,host:"192.168.1.1:27017"}, {_id:1,host:"192.168.1.2:27017",arbiterOnly:true}, {_id:2,host:"192.168.1.3:27017"}] }
使用仲裁者主要是由於MongoDB副本集須要奇數成員,而又沒有足夠服務器的狀況。在服務器充足的狀況下,不該該使用仲裁者節點。
8 .設置延遲複製節點(延遲節點)
MongoDB官方沒有增量備份方案,只有一個導出的工具mongodump。
他不能像數據庫同樣,經過binlog或者歸檔日誌將數據推到事故發生的前一刻。
假設天天凌晨2點使用mongodump備份,而下午5點發生事故,數據庫損毀,則凌晨2點到下午5點的數據所有都會丟失。
雖然副本集能夠必定程度避免這個問題,可是默認狀況下不能避免人爲的失誤。
好比沒有指定篩選條件刪除了所有的數據。副本節點會應用這個命令,刪除全部副本節點的數據。
在這個場景下,可使用延遲節點,它會延遲應用複製。
若是主節點發生了人爲的失誤,而這個操做由於延遲的緣由,尚未應用在延遲節點。
這個時候,修改延遲節點的優先級爲最高級,使他成爲新的Master服務器。
延遲節點的優先級必須爲0.這個和hidden節點是同樣的。
設置192.168.1.2爲延遲節點
cfg=rs.conf(); cfg.members[1].priority=0 cfg.members[1].slaveDelay=3600 rs.reconfig(cfg);
slaveDelay的單位是秒
在192.168.1.1主節點刪除一個集合全部數據,模擬人爲失誤。
db.users.remove({});
在192.168.1.3查看,發現數據已經所有丟失。
db.users.find();
而在192.168.1.2延遲節點,能夠看到由於延遲複製的緣故,數據還在。
這個時候千萬不要提高延遲節點的優先級。由於這樣他會當即應用原主節點的全部操做,併成爲新的主節點。這樣誤操做就同步到了延遲節點。
首先,關閉副本集中其餘的成員,除了延遲節點。
刪除其餘成員數據目錄中的全部數據。確保每一個其餘成員的數據目錄都是空的(除了延遲節點)
重啓其餘成員,他們會自動從延遲節點中恢復數據(且並不改變以前的節點配置)。
9 .設置Secondary-Only節點
Priority爲0的節點永遠不能成爲主節點,因此設置Secondary-only節點只須要將其priority設置爲0.
10 .設置Non-Voting節點
假設設置192.168.1.1不能投票,則使用以下命令
cfg=rs.conf(); cfg.members[0].votes=0; rs.reconfig(cfg);
11 .副本集成員狀態
副本集成員狀態指的是rs.status()的stateStr字段
STARTUP:剛加入到複製集中,配置還未加載 STARTUP2:配置已加載完,初始化狀態 RECOVERING:正在恢復,不適用讀 ARBITER: 仲裁者 DOWN:節點不可到達 UNKNOWN:未獲取其餘節點狀態而不知是什麼狀態,通常發生在只有兩個成員的架構,腦裂 REMOVED:移除複製集 ROLLBACK:數據回滾,在回滾結束時,轉移到RECOVERING或SECONDARY狀態 FATAL:出錯。查看日誌grep 「replSet FATAL」找出錯緣由,從新作同步 PRIMARY:主節點 SECONDARY:備份節點
12. 讀寫分離
若是Master節點讀寫壓力過大,能夠考慮讀寫分離的方案。
不過須要考慮一種場景,就是主服務器的寫入壓力很是的大,因此副本節點複製的寫入壓力一樣很大。
這時副本節點若是讀取壓力也很大的話,根據MongoDB庫級別讀寫鎖的機制,
極可能複製寫入程序拿不到寫鎖,從而致使副本節點與主節點有較大延遲。
若是進行讀寫分離,首先須要在副本節點聲明其爲slave,
db.getMongo().setSlaveOk();
其中的ReadRreference有幾種設置:
primary:默認參數,只從主節點上進行讀取操做;
primaryPreferred:大部分從主節點上讀取數據,只有主節點不可用時從secondary節點讀取數據。
secondary:只從secondary節點上進行讀取操做,存在的問題是secondary節點的數據會比primary節點數據「舊」。
secondaryPreferred:優先從secondary節點進行讀取操做,secondary節點不可用時從主節點讀取數據;
nearest:不論是主節點、secondary節點,從網絡延遲最低的節點上讀取數據。
MongoDB客戶端配置,能夠提出來作成spring注入,設置最大鏈接數什麼的。
MongoClientOptions options = MongoClientOptions.builder().maxWaitTime(1000 * 60 * 2) .connectionsPerHost(500).build(); mongoClient = new MongoClient(Arrays.asList(new ServerAddress("10.205.68.57", 8700), new ServerAddress("10.205.68.15", 8700), new ServerAddress("10.205.69.13", 8700)), options); mongoClient.setReadPreference(ReadPreference.secondaryPreferred());
13.mongodb慢查詢的設置
開啓慢日誌 1.查看mongodb慢日誌是否開起 use BJ_Rack; db.getProfilingStatus(); 發現沒有開戶慢日誌 2.開啓慢日誌,設置超過200毫秒的操做爲慢操做 db.setProfilingLevel(1); db.setProfilingLevel(1,200); 超過200ms的才記錄 0 不開啓 1 記錄慢查詢 2 記錄全部查詢 db.getProfilingStatus() 3.查看慢日誌內容 獲得50個比較慢的操做日誌. db.system.profile.find().sort({$natural:-1}) #### 查看查詢時間超過某個時間的 use local db.system.profile.find({millis:{$gte:500}}).sort({"ts":-1}).limit(3) #### 查詢最慢的查詢 db.system.profile.find().sort({"millis":-1}).limit(3) 經過配置文件開啓: operationProfiling: mode: slowOp slowOpThresholdMs: 100 查看當前操做 db.currentOp(true);查看當前節點的鏈接狀況db.serverStatus().connections