一、複製原理
MongoDB的複製功能是使用操作日誌oplog實現的,oplog包含主節點(Master)的每一次寫操作,oplog是local本地資料庫中的一個資料集合,其它非主節點(Secondary)通過讀取主節點的oplog集合中的記錄同步到對應的集合,然後再寫入到自身的local資料庫的oplog集合中。每個節點都維護著自己的oplog,記錄著每一次從主節點複製資料的操作。這樣每個成員都可以作為同步源提供給其它成員使用。
注意:需要注意Secondary節點同步資料的順序是先同步資料,然後再寫入oplog;這點和mysql的機制不同。但是每個節點oplog中記錄的同步資料是完全一致的,所以也不擔心被執行多次。
二、oplog集合
1.insert操作
/* 1 */ { "ts" : Timestamp(1520580648, 1), "t" : NumberLong(20), "h" : NumberLong(-8701728013874689868), "v" : 2, "op" : "i", "ns" : "test.person", "ui" : UUID("782befd9-80ae-4a2c-86ae-33a147e7c948"), "wall" : ISODate("2018-03-09T07:30:48.120Z"), "o" : { "_id" : ObjectId("5aa2382f7239a98c7e679114"), "name" : "zhang" } }
2.update操作
/* 1 */ { "ts" : Timestamp(1520584444, 2), "t" : NumberLong(20), "h" : NumberLong(7151217369265341585), "v" : 2, "op" : "u", "ns" : "test.person", "ui" : UUID("782befd9-80ae-4a2c-86ae-33a147e7c948"), "o2" : { "_id" : ObjectId("5aa2382f7239a98c7e679114") }, "wall" : ISODate("2018-03-09T08:34:04.777Z"), "o" : { "$v" : 1, "$set" : { "name" : "wang" } } }
- ts: 操作時間,當前timestamp + 計數器,計數器每秒都被重置
- h:操作的全域性唯一標識
- v:oplog版本資訊
- op:操作型別:
- i:插入操作
- u:更新操作
- d:刪除操作
- c:執行命令(如createDatabase,dropDatabase)
- n:空操作,特殊用途
- ns:操作針對的集合
- ui:
- o:操作內容,如果是更新操作
- o2:操作查詢條件,僅update操作包含該欄位
- wall:記錄的時間戳。
3.查詢oplog集合
db.oplog.rs.find( {"op":{$in:["i","u","d"]}} ) .sort({"wall":-1});
三、初始化同步
1.選擇一個成員作為同步源,在local.me中建立識別符號;刪除已存在的資料庫。
2.將同步源的所有資料複製到本地。所有的操作都被集合到oplog中。
3.將第一個oplog同步中的操作記錄下來。
4.建立相關索引,如果集合比較大該過程可能會花費很長的時間。
5.將建立索引過程中同步源增加的記錄同步過來。
6.同步完成,修改節點狀態為SECONDARY
四、心跳
每個成員每隔兩秒鐘就會向其它成員傳送一個心跳請求,心跳的請求資訊量非常的小,用於檢查每個成員的狀態。
心跳最主要的功能之一就是讓主節點知道自己是否滿足集合“大多數”的條件。如果主節點不再得到“大多數”伺服器的支援,它就會退位變成備份節點。
成員狀態
Number |
Name |
State Description |
0 |
Not yet an active member of any set. All members start up in this state. The mongod parses the replica set configuration document while inSTARTUP. |
|
1 |
The member in state primary is the only member that can accept write operations. Eligible to vote. |
|
2 |
A member in state secondary is replicating the data store. Eligible to vote. |
|
3 |
Members either perform startup self-checks, or transition from completing a rollback or resync. Eligible to vote. |
|
5 |
The member has joined the set and is running an initial sync. |
|
6 |
The member’s state, as seen from another member of the set, is not yet known. |
|
7 |
Arbiters do not replicate data and exist solely to participate in elections. |
|
8 |
The member, as seen from another member of the set, is unreachable. |
|
9 |
This member is actively performing a rollback. Data is not available for reads. |
|
10 |
This member was once in a replica set but was subsequently removed. |
五、選舉
當一個成員無法到達主節點時,它就會申請被選舉為主節點。希望被選舉為主節點的成員會向它能到達的所有成員傳送通知。如果這個成員不符合候選人的要求,其它成員可能會知道相關原因:這個成員的資料落後於副本集,或者已經有一個執行中的主節點(希望被選舉為主節點的成員無法到達這個主節點)。在這些情況下,其它成員不會允許進行選舉。
如果沒有其它成員反對,其他成員就會對這個成員進行選舉投票,如果滿足副本集中“大多數”贊成票,它就被選舉成功,轉換成為主節點。否則選舉失敗仍然處於備份節點狀態,之後還可以再次申請被選舉為主節點。而主節點會一直主節點狀態,除非它由於不再滿足“大多數”的要求或者當機而退位,另外副本集被重新配置也會導致主節點退位。
在網路良好的情況下,同時投票伺服器也正常執行那麼選舉過程會很快,由於節點之間的互ping是每隔2S,所以如果有主節點不可用那麼2S之內就會有成員發現,然後就會立即開始選舉,整個過程正常只會花費幾毫秒。如果存在網路問題或者伺服器過載響應緩慢都有可能觸發選舉。在這種情況下,心跳會在最多10S之後超時。如果選舉打成平局,每個成員都需要等待30S才能開始下一次選舉,所以如果發生太多錯誤的情況下選舉可能會花費幾分鐘的時間。
六、回滾
一般情況下跨資料中心複製要比同資料中心複製慢。
上圖的兩個資料中心之間出現網路故障,DC1最後的操作是126,DC2最後的操作是125;DC1的126操作還沒有被複制到DC2;由於採取的是多數節點的投票機制,DC2資料中心的副本滿足“大多數”節點的要求(一共5臺伺服器,3臺伺服器即可超過半數投票)。因此其中一臺伺服器會被選舉成為新的主節點,這個主節點會繼續後續的寫操作。假設在DC1的網路恢復之前DC2已經操作到了130。
DC1
123 |
124 |
125 |
126 |
DC2
123 |
124 |
125 |
126'' |
127'' |
128'' |
129'' |
130'' |
在DC1網路恢復之後,DC1就會從DC2同步126之後的操作,但是會發現這個操作是無法操作的,這時候DC1和DC2就會進入回滾過程,DC1和DC2會查詢到二者共同的操作點125,DC1和DC2都會回滾到125,然後二者才會繼續後面的同步操作
注意:如果回滾的資料量比較大需要很長的時間,這時可能會導致回滾失敗,對於回滾失敗的節點,必須要重新進行同步。一般造成這種情況的主要原因是備份節點遠遠落後於主節點,而這時主節點掛了。
備註: 作者:pursuer.chen 部落格:http://www.cnblogs.com/chenmh 本站點所有隨筆都是原創,歡迎大家轉載;但轉載時必須註明文章來源,且在文章開頭明顯處給明連結,否則保留追究責任的權利。 《歡迎交流討論》 |