NO IMAGE

mongodb副本集是有故障恢復功能的主從叢集,由一個primary節點和一個或多個secondary節點組成。
同步過程: Primary節點寫入資料,Secondary通過讀取Primary的oplog得到複製資訊,開始複製資料並且將複製資訊寫入到自己的oplog。如果某個操作失敗,則備份節點停止從當前資料來源複製資料。如果某個備份節點由於某些原因掛掉了,當重新啟動後,就會自動從oplog的最後一個操作開始同步,同步完成後,將資訊寫入自己的oplog,由於複製操作是先複製資料,複製完成後再寫入oplog,有可能相同的操作會同步兩份,不過MongoDB在設計之初就考慮到這個問題,將oplog的同一個操作執行多次,與執行一次的效果是一樣的。
簡單的說就是:當Primary節點完成資料操作後,Secondary會做出一系列的動作保證資料的同步
• 1、檢查自己local庫的oplog.rs集合,找出最近的時間戳。
• 2、檢查Primary節點local庫oplog.rs集合,找出大於此時間戳的記錄。
• 3、將找到的記錄插入到自己的oplog.rs集合中,並執行這些操作。
副本集的同步和主從同步一樣,都是非同步同步的過程,不同的是副本集有個自動故障轉移的功能。其原理是:slave端從primary端獲取日誌,然後在自己身上完全順序的執行日誌所記錄的各種操作(該日誌是不記錄查詢操作的),這個日誌就是local資料庫中的oplog.rs表,預設在64位機器上這個表是比較大的,佔磁碟大小的5%,oplog.rs的大小可以在啟動引數中設 定:–oplogSize 1000,單位是M。
注意:在副本集的環境中,要是所有的Secondary都宕機了,只剩下Primary。最後Primary會變成Secondary,不能提供服務。
開發環境搭建
準備伺服器
27017
27018
27019
建立mongod例項

目錄

第一個成員

$ mongod –port 27018 –dbpath c:/data/slave1 –replSet rs0 –smallfiles –oplogSize 128

第二個成員

$ mongod –port 27018 –dbpath c:/data/slave1 –replSet rs0 –smallfiles –oplogSize 128

第三個成員

$ mongod –port 27019 –dbpath c:/data/slave2 –replSet rs0 –smallfiles –oplogSize 128
這裡建立了三個所屬副本集名為rs0的節點,每個節點的資料目錄通過–dbpath指定,埠通過–port指定,–smallfiles和–oplogSize設定減少每個mongod例項使用的磁碟空間。這是理想的開發環境,防止機器過載。
連線資料庫
$ mongo –port 27017
這裡本地環境,需要指定埠號。
初始化副本集

編寫配置檔案格式

$ rsconf = {
“_id” : “rs0”,
“members” : [
{
“_id” : 0,
“host” : “127.0.0.1:27017”
},
{
“_id” : 1,
“host” : “127.0.0.1:27018”
},
{
“_id” : 2,
“host” : “127.0.0.1:27019”
}
]
}
$ rs.initiate( rsconf )
檢視當前配置
$ rs.conf()
{
“_id” : “rs0”,
“version” : 1,
“protocolVersion” : NumberLong(1),
“members” : [
{
“_id” : 0,
“host” : “127.0.0.1:27017”,
“arbiterOnly” : false,
“buildIndexes” : true,
“hidden” : false,
“priority” : 1,
“tags” : {

        },
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 1,
"host" : "127.0.0.1:27018",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 2,
"host" : "127.0.0.1:27019",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true,
"heartbeatIntervalMillis" : 2000,
"heartbeatTimeoutSecs" : 10,
"electionTimeoutMillis" : 10000,
"getLastErrorModes" : {
},
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
}
}

}
在mongodb會將配置裡的節點自動新增到副本集rs0中。
檢視副本集狀態
$ rs.status()
{
“set” : “rs0”,
“date” : ISODate(“2018-01-11T10:34:22.369Z”),
“myState” : 1,
“term” : NumberLong(1),
“heartbeatIntervalMillis” : NumberLong(2000),
“members” : [
{
“_id” : 0,
“name” : “127.0.0.1:27017”,
“health” : 1,
“state” : 1,
“stateStr” : “PRIMARY”,
“uptime” : 1142,
“optime” : {
“ts” : Timestamp(1463293650, 2),
“t” : NumberLong(1)
},
“optimeDate” : ISODate(“2018-01-11T10:27:30Z”),
“electionTime” : Timestamp(1463293650, 1),
“electionDate” : ISODate(“2018-01-11T10:27:30Z”),
“configVersion” : 1,
“self” : true
},
{
“_id” : 1,
“name” : “127.0.0.1:27018”,
“health” : 1,
“state” : 2,
“stateStr” : “SECONDARY”,
“uptime” : 422,
“optime” : {
“ts” : Timestamp(1463293650, 2),
“t” : NumberLong(1)
},
“optimeDate” : ISODate(“2018-01-11T10:27:30Z”),
“lastHeartbeat” : ISODate(“2018-01-11T10:34:20.407Z”),
“lastHeartbeatRecv” : ISODate(“2018-01-11T10:34:21.504Z”),
“pingMs” : NumberLong(0),
“syncingTo” : “127.0.0.1:27017”,
“configVersion” : 1
},
{
“_id” : 2,
“name” : “127.0.0.1:27019”,
“health” : 1,
“state” : 2,
“stateStr” : “SECONDARY”,
“uptime” : 422,
“optime” : {
“ts” : Timestamp(1463293650, 2),
“t” : NumberLong(1)
},
“optimeDate” : ISODate(“2018-01-11T10:27:30Z”),
“lastHeartbeat” : ISODate(“2018-01-11T10:34:20.407Z”),
“lastHeartbeatRecv” : ISODate(“2018-01-11T10:34:21.504Z”),
“pingMs” : NumberLong(0),
“syncingTo” : “127.0.0.1:27017”,
“configVersion” : 1
}
],
“ok” : 1
}
到這裡,整個副本集已經搭建成功了。
功能測試
複製功能
在Primary(127.0.0.1:27017)上插入資料

我們連線到主節點Primary

$ mongo –port 27017

檢視資料庫,只有一個local

$ show dbs
local 0.000GB

新建資料庫

$ use testdb

向資料庫插入資料

$ db.test.insert({“name”:”test data”,”value”:1111})

檢視是否插入成功

$ db.test.find()
{ “_id” : ObjectId(“57382a2641cff36fe7f3fc30”), “name” : “test data”, “value” : 1111 }
我們斷開連線,連線到任一從節點Secondary(127.0.0.1:27018)
$ mongo –port 27018

切換資料庫

$ use testdb

檢視資料,這裡不能直接用 db.test.find() 檢視。mongodb預設是從主節點讀寫資料的,副本節點上不允許讀,需要設定副本節點可以讀。

$ db.getMongo().setSlaveOk()

檢視資料

$ db.test.find()
{ “_id” : ObjectId(“57382a2641cff36fe7f3fc30”), “name” : “test data”, “value” : 1111 }
可以看到資料已經同步過來了,測試OK。
自動故障轉移
我們先檢視各個節點狀態:
$ rs.status()
{
“set” : “rs0”,
“date” : ISODate(“2018-01-11T08:03:51.757Z”),
“myState” : 2,
“term” : NumberLong(1),
“syncingTo” : “127.0.0.1:27017”,
“heartbeatIntervalMillis” : NumberLong(2000),
“members” : [
{
“_id” : 0,
“name” : “127.0.0.1:27017”,
“health” : 1,
“state” : 1,
“stateStr” : “PRIMARY”,
“uptime” : 5790,
“optime” : {
“ts” : Timestamp(1463298598, 2),
“t” : NumberLong(1)
},
“optimeDate” : ISODate(“2018-01-11T07:49:58Z”),
“lastHeartbeat” : ISODate(“2018-01-11T08:03:50.886Z”),
“lastHeartbeatRecv” : ISODate(“2018-01-11T08:03:49.938Z”),
“pingMs” : NumberLong(0),
“electionTime” : Timestamp(0, 0),
“electionDate” : ISODate(“1970-01-01T00:00:00Z”),
“configVersion” : 1
},
{
“_id” : 1,
“name” : “127.0.0.1:27018”,
“health” : 1,
“state” : 2,
“stateStr” : “SECONDARY”,
“uptime” : 6370,
“optime” : {
“ts” : Timestamp(1463298598, 2),
“t” : NumberLong(1)
},
“optimeDate” : ISODate(“2018-01-11T07:49:58Z”),
“syncingTo” : “127.0.0.1:27017”,
“configVersion” : 1,
“self” : true
},
{
“_id” : 2,
“name” : “127.0.0.1:27019”,
“health” : 1,
“state” : 2,
“stateStr” : “SECONDARY”,
“uptime” : 5790,
“optime” : {
“ts” : Timestamp(1463298598, 2),
“t” : NumberLong(1)
},
“optimeDate” : ISODate(“2018-01-11T07:49:58Z”),
“lastHeartbeat” : ISODate(“2018-01-11T08:03:50.886Z”),
“lastHeartbeatRecv” : ISODate(“2018-01-11T08:03:51.021Z”),
“pingMs” : NumberLong(0),
“syncingTo” : “127.0.0.1:27017”,
“configVersion” : 1
}
],
“ok” : 1
}
關掉主節點Primary:

連線到主節點primary

$ mongo –port 27017

切換到 admin 資料庫(關掉資料庫命令只能在 admin 資料庫)

$ use admin

關掉

$ db.shutdownServer()
我們再進入任一節點:
$ mongo –port 27018

檢視副本集狀態

$ rs.status()
{
“set” : “rs0”,
“date” : ISODate(“2018-01-11T08:16:12.253Z”),
“myState” : 1,
“term” : NumberLong(2),
“heartbeatIntervalMillis” : NumberLong(2000),
“members” : [
{
“_id” : 0,
“name” : “127.0.0.1:27017”,
“health” : 0,
“state” : 8,
“stateStr” : “(not reachable/healthy)”, #這裡變為不可達狀態
“uptime” : 0,
“optime” : {
“ts” : Timestamp(0, 0),
“t” : NumberLong(-1)
},
“optimeDate” : ISODate(“1970-01-01T00:00:00Z”),
“lastHeartbeat” : ISODate(“2018-01-11T08:16:11.064Z”),
“lastHeartbeatRecv” : ISODate(“2018-01-11T08:09:36.193Z”),
“pingMs” : NumberLong(0),
“lastHeartbeatMessage” : “Connection refused”,
“configVersion” : -1
},
{
“_id” : 1,
“name” : “127.0.0.1:27018”,
“health” : 1,
“state” : 1,
“stateStr” : “PRIMARY”, #成為主節點
“uptime” : 7111,
“optime” : {
“ts” : Timestamp(1463299787, 1),
“t” : NumberLong(2)
},
“optimeDate” : ISODate(“2018-01-11T08:09:47Z”),
“electionTime” : Timestamp(1463299786, 1),
“electionDate” : ISODate(“2018-01-11T08:09:46Z”),
“configVersion” : 1,
“self” : true
},
{
……
}
],
“ok” : 1
}
可以看到127.0.0.1:27017這臺已經是不可達的狀態了。
127.0.0.1:27018被選舉成為新的主節點Primary。自動故障轉移測試成功。
我們再次做資料同步測試:

連線主節點

$ mongo –port 27018
$ use testdb

向新的主節點 :27018 插入資料

$ db.test.insert({“name” : “test data2”, “value” : 2222})

檢視資料

$ db.test.find()
{ “_id” : ObjectId(“57382a2641cff36fe7f3fc30”), “name” : “test data”, “value” : 1111 }
{ “_id” : ObjectId(“573831bc15f8a9f0fd3e51ee”), “name” : “test data2”, “value” : 2222 }
下面我們再次啟動之前停掉的主節點 27017。

啟動之前停掉的 27017

$ mongod –port 27017 –dbpath c:/data/master –replSet rs0 –smallfiles –oplogSize 128 &

連線該節點

$ mongo –port 27017

切換資料庫

$ use testdb

設定可讀

$ db.getMongo().setSlaveOk()

檢視資料

$ db.test.find()
{ “_id” : ObjectId(“57382a2641cff36fe7f3fc30”), “name” : “test data”, “value” : 1111 }
{ “_id” : ObjectId(“573831bc15f8a9f0fd3e51ee”), “name” : “test data2”, “value” : 2222 }
可以看到資料也已經同步過來,但是 27017 也已經成為從節點Secondary了。
注意:所有的Secondary都宕機、或則副本集中只剩下一個節點,則該節點只能為Secondary節點,也就意味著整個叢集智慧進行讀操作而不能進行寫操作,當其他的恢復時,之前的primary節點仍然是primary節點。官方推薦的最小的副本集也應該具備一個primary節點和兩個secondary節點。兩個節點的副本集不具備真正的故障轉移能力。
維護
增刪節點
新增一個節點

啟動一個例項

$ mongod –port 27020 –dbpath c:/data/slave3 –replSet rs0 –smallfiles –oplogSize 128 &

進入主節點Primary

$ mongo –port 27018

新增到副本集

$ rs.add(“127.0.0.1:27020”)

檢視副本集狀態

$ rs.status()
{
“set” : “rs0”,
“date” : ISODate(“2018-01-11T09:06:32.461Z”),
“myState” : 1,
“term” : NumberLong(2),
“heartbeatIntervalMillis” : NumberLong(2000),
“members” : [
{
……
},
{
“_id” : 1,
“name” : “127.0.0.1:27018”,
“health” : 1,
“state” : 1,
“stateStr” : “PRIMARY”,
“uptime” : 10131,
“optime” : {
“ts” : Timestamp(1463303179, 1),
“t” : NumberLong(2)
},
“optimeDate” : ISODate(“2018-01-11T09:06:19Z”),
“electionTime” : Timestamp(1463299786, 1),
“electionDate” : ISODate(“2018-01-11T08:09:46Z”),
“configVersion” : 2,
“self” : true
},
{
……
},
{
“_id” : 3,
“name” : “127.0.0.1:27020”,
“health” : 1,
“state” : 2,
“stateStr” : “SECONDARY”,
“uptime” : 12,
“optime” : {
“ts” : Timestamp(1463303179, 1),
“t” : NumberLong(2)
},
“optimeDate” : ISODate(“2018-01-11T09:06:19Z”),
“lastHeartbeat” : ISODate(“2018-01-11T09:06:31.514Z”),
“lastHeartbeatRecv” : ISODate(“2018-01-11T09:06:27.758Z”),
“pingMs” : NumberLong(0),
“configVersion” : 2
}
],
“ok” : 1
}
可以看到已經新增成功。
刪除一個節點

進入需要刪除的節點,切換到admin資料庫,執行db.shutdownServer()關掉。

進入主節點Primary,刪除節點

$ rs.remove(“127.0.0.1:27020”)

檢視副本集狀態

$ rs.status()
{
“set” : “rs0”,
“date” : ISODate(“2018-01-11T09:14:04.615Z”),
“myState” : 1,
“term” : NumberLong(2),
“heartbeatIntervalMillis” : NumberLong(2000),
“members” : [
{
……
},
{
“_id” : 1,
“name” : “127.0.0.1:27018”,
“health” : 1,
“state” : 1,
“stateStr” : “PRIMARY”,
“uptime” : 10583,
“optime” : {
“ts” : Timestamp(1463303631, 1),
“t” : NumberLong(2)
},
“optimeDate” : ISODate(“2018-01-11T09:13:51Z”),
“electionTime” : Timestamp(1463299786, 1),
“electionDate” : ISODate(“2018-01-11T08:09:46Z”),
“configVersion” : 3,
“self” : true
},
{
“_id” : 2,
“name” : “127.0.0.1:27019”,
“health” : 1,
“state” : 2,
“stateStr” : “SECONDARY”,
“uptime” : 10003,
“optime” : {
“ts” : Timestamp(1463303631, 1),
“t” : NumberLong(2)
},
“optimeDate” : ISODate(“2018-01-11T09:13:51Z”),
“lastHeartbeat” : ISODate(“2018-01-11T09:14:03.065Z”),
“lastHeartbeatRecv” : ISODate(“2018-01-11T09:14:03.069Z”),
“pingMs” : NumberLong(0),
“syncingTo” : “127.0.0.1:27018”,
“configVersion” : 3
}
],
“ok” : 1
}

也可以通過副本集配置物件修改。

進入需要刪除的節點,切換到admin資料庫,執行db.shutdownServer()關掉。

進入主節點Primary,檢視配置文件,找到需要刪除的節點

$ mongo –port 27018
$ rs.conf()
{
“_id” : “rs0”,
“version” : 1,
“protocolVersion” : NumberLong(1),
“members” : [
{
“_id” : 0,
“host” : “127.0.0.1:27017”,
“arbiterOnly” : false,
“buildIndexes” : true,
“hidden” : false,
“priority” : 1,
“tags” : {

        },
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 1,
"host" : "127.0.0.1:27018",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 2,
"host" : "127.0.0.1:27019",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true,
"heartbeatIntervalMillis" : 2000,
"heartbeatTimeoutSecs" : 10,
"electionTimeoutMillis" : 10000,
"getLastErrorModes" : {
},
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
}
}

}

獲取到配置物件,刪除,重新配置副本集

$ cfg = rs.conf()
$ cfg.members.splice(2,1) #刪除27019
$ rs.reconfig(cfg)
替換副本集節點
如果你需要更改一個節點的主機名並且不改變配置:
cfg = rs.conf()
cfg.members[0].host = “127.0.0.1:27021”
rs.reconfig(cfg)
改變Oplog大小
oplog存在內部限制集合,所以在正常操作過程中你不能修改它的大小。官網參考:oplog
配置副本集tag
標記讓你定製寫關心和讀偏好一個複製集,在rs.conf()中配置,members[n].tags。tags
改變副本集主機名
一般,主機名是不會變化的。但在特殊情況你可能會改變它,請參考:hostname
本地資料庫 local
每個mongod例項都有自己的本地資料庫,用於儲存資料複製過程,和其他特定資料。本地資料庫是無形的複製:集合在本地資料庫複製。請參考:local database
配置從節點Secondary同步物件
從節點的資料一般是從主節點進行復制,然而,在預設情況下,從節點可能基於各個節點ping的時間將同步目標改為其它從節點。對於一些部署,實現自定義的同步目標選擇邏輯有可能會更有效。對於mongodb,你可以暫時覆蓋預設的同步目標,手動配置第二個同步目標,拉取oplog。請參考:sync target
應用
手動切換主節點Primary
將指定的節點的優先順序priority加到最大,即可成為主節點:

切換到主節點Primary,檢視配置

$ rs.conf()
{
“_id” : “rs0”,
“version” : 3, #每修改一次叢集的配置,副本集的version都會 1
“protocolVersion” : NumberLong(1),
“members” : [
{
“_id” : 0,
“host” : “127.0.0.1:27017”,
“arbiterOnly” : false,
“buildIndexes” : true,
“hidden” : false,
“priority” : 1,
“tags” : {

        },
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 1,
"host" : "127.0.0.1:27018",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 2,
"host" : "127.0.0.1:27019",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true,
"heartbeatIntervalMillis" : 2000,
"heartbeatTimeoutSecs" : 10,
"electionTimeoutMillis" : 10000,
"getLastErrorModes" : {
},
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
}
}

}

修改優先順序,讓 27017 成為主節點

$ conf = rs.conf()

修改優先順序

$ conf.members[0].priority = 2

重新載入配置檔案,強制進行一次選舉,期間所有節點均為從節點Secondary

$ rs.reconfig(conf)

檢視副本集狀態

$ rs.status()
{
“set” : “rs0”,
“date” : ISODate(“2018-01-11T09:32:06.298Z”),
“myState” : 2,
“term” : NumberLong(3),
“syncingTo” : “127.0.0.1:27019”,
“heartbeatIntervalMillis” : NumberLong(2000),
“members” : [
{
“_id” : 0,
“name” : “127.0.0.1:27017”,
“health” : 1,
“state” : 1,
“stateStr” : “PRIMARY”,
“uptime” : 2874,
“optime” : {
“ts” : Timestamp(1463304708, 2),
“t” : NumberLong(3)
},
“optimeDate” : ISODate(“2018-01-11T09:31:48Z”),
“lastHeartbeat” : ISODate(“2018-01-11T09:32:05.125Z”),
“lastHeartbeatRecv” : ISODate(“2018-01-11T09:32:06.134Z”),
“pingMs” : NumberLong(0),
“electionTime” : Timestamp(0, 0),
“electionDate” : ISODate(“1970-01-01T00:00:00Z”),
“configVersion” : 4
},
{
“_id” : 1,
“name” : “127.0.0.1:27018”,
“health” : 1,
“state” : 2,
“stateStr” : “SECONDARY”,
“uptime” : 11665,
“optime” : {
“ts” : Timestamp(1463304708, 2),
“t” : NumberLong(3)
},
“optimeDate” : ISODate(“2018-01-11T09:31:48Z”),
“syncingTo” : “127.0.0.1:27019”,
“configVersion” : 4,
“self” : true
},
{
……
}
],
“ok” : 1
}
可以看到27017成為了主節點Primary。
新增仲裁節點
新增仲裁節點與新增資料節點是一樣的。只是在新增時需呼叫:

新增一個例項。為了最大限度地減少建立預設的資料,請設定–journal=false,在指定–dbpath有效

$ mongod –port 27020 –dbpath –journal=false c:/data/arb –replSet rs0 &

新增仲裁節點

$ rs.addArb(“127.0.0.1:27021”)
副本集要求參與選舉投票(vote)的節點數為奇數。當我門資料集節點為偶數時,可以新增一個仲裁節點組成奇數。仲裁節點只參加投票不擁有資料,它對物理資源需要很少。
通過實際測試發現,當整個副本集叢集中達到50%的節點(包括仲裁節點)不可用的時候,剩下的節點只能成為secondary節點,整個叢集只能讀不能 寫。比如叢集中有1個primary節點,2個secondary節點,加1個arbit節點時:當兩個secondary節點掛掉了,那麼剩下的原來的 primary節點也只能降級為secondary節點;當叢集中有1個primary節點,1個secondary節點和1個arbit節點,這時即使 primary節點掛了,剩下的secondary節點也會自動成為primary節點。因為仲裁節點不復制資料,因此利用仲裁節點可以實現最少的機器開銷達到兩個節點熱備的效果。
新增備份節點
hidden(成員用於支援專用功能):這樣設定後此機器在讀寫中都不可見,並且不會被選舉為Primary,但是可以投票,一般用於備份資料。
把27019節點刪除,重啟。再新增讓其為hidden節點:
rs.add(“id”:2,”host”:”127.0.0.1:27019”,”priority”:0,”hidden”:true)新增延遲節點Delayed(成員用於支援專用功能):可以指定一個時間延遲從primary節點同步資料。主要用於處理誤刪除資料馬上同步到從節點導致的不一致問題。 rs.add({“_id”:2,”host”:”127.0.0.1:27019”,”priority”:0,”hidden”:true})
新增延遲節點
Delayed(成員用於支援專用功能):可以指定一個時間延遲從primary節點同步資料。主要用於處理誤刪除資料馬上同步到從節點導致的不一致問題。
rs.add({“_id”:2,”host”:”127.0.0.1:27019”,”priority”:0,”hidden”:true,”slaveDelay”:60}) #單位 s
除了上面的一些節點,還有:
• Secondary-Only:不能成為primary節點,只能作為secondary副本節點,防止一些效能不高的節點成為主節點。
• Non-Voting:沒有選舉權的secondary節點,純粹的備份資料節點。
具體如下:
角色 primary(能否) 客戶端可見 參與投票 延遲同步 複製資料
Default √ √ √ X √
Secondary-Only X √ √ X √
Hidden X X √ X √
Delayed X √ √ √ √
Arbiters X X √ X X
Non-Voting √ √ X X √
讀寫分離
MongoDB副本集對讀寫分離的支援是通過Read Preferences特性進行支援的,這個特性非常複雜和靈活。設定讀寫分離需要先在從節點SECONDARY 設定 setSlaveOk
應用程式驅動通過read reference來設定如何對副本集進行讀取操作,預設的,客戶端驅動所有的讀操作都是直接訪問primary節點的,從而保證了資料的嚴格一致性。
有如下幾種模式:
模式 描述
primary 主節點,預設模式,讀操作只在主節點,如果主節點不可用,報錯或者丟擲異常。
primaryPreferred 首選主節點,大多情況下讀操作在主節點,如果主節點不可用,如故障轉移,讀操作在從節點。
secondary 從節點,讀操作只在從節點, 如果從節點不可用,報錯或者丟擲異常。
secondaryPreferred 首選從節點,大多情況下讀操作在從節點,特殊情況(如單主節點架構)讀操作在主節點。
nearest 最鄰近節點,讀操作在最鄰近的成員,可能是主節點或者從節點,關於最鄰近的成員請參考官網nearest

附: 節點狀態
名稱 描述
STARTUP 沒有任何活躍的節點,所有節點在這種狀態下啟動,解析副本集配置
PRIMARY 副本集的主節點
SECONDARY 副本集從節點,可以讀資料
RECOVERING 可以投票,成員執行啟動自檢,或完成回滾或重新同步。
STARTUP2 節點加入,並執行初始同步
UNKNOWN 從其它節點看來,該節點未知
ARBITER 仲裁者,不復制資料,供投票
DOWN 在其它節點看來,該節點不可達
ROLLBACK 該節點正在執行回滾,不能讀取資料
REMOVED 該節點被刪除
mongo shell中複製相關方法
方法名 描述
rs.add() 新增節點到副本集
rs.addArb() 新增仲裁節點到副本集
rs.conf() 獲取副本集的配置文件
rs.freeze() 指定一段時間內,當前節點不能競選主節點Primary
rs.help() 獲取副本集的基本方法
rs.initiate() 初始化一個新的副本集
rs.printReplicationInfo() 列印副本集的主節點Primary的狀態報告
rs.printSlaveReplicationInfo() 列印副本集的從節點Secondary的狀態報告
rs.reconfig() 重新配置副本集
rs.remove() 刪除一個節點
rs.slaveOk() 設定當前連線可讀,使用readPref() 和 MongosetReadPref()去設定讀偏好
rs.status() 返回副本集狀態資訊的文件
rs.stepDown() 強制當前主節點Primary成為從節點Secondary,並觸發投票選舉
rs.syncFrom() 設定新的同步目標,覆蓋預設的同步目標
複製 資料庫的命令
名稱 描述
replSetFreeze 阻止當前節點競爭當主節點Primary一段時間
replSetGetStatus 返回副本集狀態資訊的文件
replSetInitiate 初始化一個新的副本集
replSetMaintenance 啟用或禁用維護模式,使從節點Secondary進入恢復狀態
replSetReconfig 重新配置副本集
replSetStepDown 強制當前主節點Primary成為從節點Secondary,並觸發投票選舉
replSetSyncFrom 設定新的同步目標,覆蓋預設的同步目標
resync 強制重新同步,僅在主從同步有效
applyOps 內部命令,應用oplog到當前的資料集
isMaster 顯示該節點否是主節點和其它的相關資訊