MongoDB 副本集的常用操作及原理


本文是對MongoDB副本集常用操作的一個匯總,同時也穿插着介紹了操作背后的原理及注意點。

結合之前的文章:MongoDB副本集的搭建,大家可以在較短的時間內熟悉MongoDB的搭建和管理。

下面的操作主要分為兩個部分:

1. 修改節點狀態

    主要包括:

    1> 將Primary節點降級為Secondary節點

    2> 凍結Secondary節點

    3> 強制Secondary節點進入維護模式

2. 修改副本集的配置

    1> 添加節點

    2> 刪除節點

    3> 將Secondary節點設置為延遲備份節點

    4> 將Secondary節點設置為隱藏節點

    5> 替換當前的副本集成員

    6> 設置副本集節點的優先級

    7> 阻止Secondary節點升級為Primary節點

    8> 如何設置沒有投票權的Secondary節點

    9> 禁用chainingAllowed

   10> 為Secondary節點顯式指定復制源

   11> 禁止Secondary節點創建索引

 

首先查看MongoDB副本集支持的所有操作

復制代碼
> rs.help()
    rs.status()                                { replSetGetStatus : 1 } checks repl set status
    rs.initiate()                              { replSetInitiate : null } initiates set with default settings
    rs.initiate(cfg)                           { replSetInitiate : cfg } initiates set with configuration cfg
    rs.conf()                                  get the current configuration object from local.system.replset
    rs.reconfig(cfg)                           updates the configuration of a running replica set with cfg (disconnects)
    rs.add(hostportstr)                        add a new member to the set with default attributes (disconnects)
    rs.add(membercfgobj)                       add a new member to the set with extra attributes (disconnects)
    rs.addArb(hostportstr)                     add a new member which is arbiterOnly:true (disconnects)
    rs.stepDown([stepdownSecs, catchUpSecs])   step down as primary (disconnects)
    rs.syncFrom(hostportstr)                   make a secondary sync from the given member
    rs.freeze(secs)                            make a node ineligible to become primary for the time specified
    rs.remove(hostportstr)                     remove a host from the replica set (disconnects)
    rs.slaveOk()                               allow queries on secondary nodes

    rs.printReplicationInfo()                  check oplog size and time range
    rs.printSlaveReplicationInfo()             check replica set members and replication lag
    db.isMaster()                              check who is primary

    reconfiguration helpers disconnect from the database so the shell will display
    an error, even if the command succeeds.
復制代碼

 

修改節點狀態

將Primary節點降級為Secondary節點

myapp:PRIMARY> rs.stepDown()

這個命令會讓primary降級為Secondary節點,並維持60s,如果這段時間內沒有新的primary被選舉出來,這個節點可以要求重新進行選舉。

也可手動指定時間

myapp:PRIMARY> rs.stepDown(30)

在執行完該命令后,原Secondary node3:27017升級為Primary。

其日志輸出為:

復制代碼
2017-05-03T22:24:21.009+0800 I COMMAND  [conn8] Attempting to step down in response to replSetStepDown command
2017-05-03T22:24:25.967+0800 I -        [conn8] end connection 127.0.0.1:45976 (3 connections now open)
2017-05-03T22:24:37.643+0800 I REPL     [ReplicationExecutor] Member node3:27018 is now in state SECONDARY
2017-05-03T22:24:41.123+0800 I REPL     [replication-40] Restarting oplog query due to error: InterruptedDueToReplStateChange: operat
ion was interrupted. Last fetched optime (with hash): { ts: Timestamp 1493821475000|1, t: 2 }[-6379771952742605801]. Restarts remaining: 32017-05-03T22:24:41.167+0800 I REPL     [replication-40] Scheduled new oplog query Fetcher source: node3:27018 database: local query:
 { find: "oplog.rs", filter: { ts: { $gte: Timestamp 1493821475000|1 } }, tailable: true, oplogReplay: true, awaitData: true, maxTimeMS: 60000, term: 2 } query metadata: { $replData: 1, $ssm: { $secondaryOk: true } } active: 1 timeout: 10000ms shutting down?: 0 first: 1 firstCommandScheduler: RemoteCommandRetryScheduler request: RemoteCommand 11695 -- target:node3:27018 db:local cmd:{ find: "oplog.rs", filter: { ts: { $gte: Timestamp 1493821475000|1 } }, tailable: true, oplogReplay: true, awaitData: true, maxTimeMS: 60000, term: 2 } active: 1 callbackHandle.valid: 1 callbackHandle.cancelled: 0 attempt: 1 retryPolicy: RetryPolicyImpl maxAttempts: 1 maxTimeMillis: -1ms2017-05-03T22:24:41.265+0800 I REPL     [replication-39] Choosing new sync source because our current sync source, node3:27018, has a
n OpTime ({ ts: Timestamp 1493821475000|1, t: 2 }) which is not ahead of ours ({ ts: Timestamp 1493821475000|1, t: 2 }), it does not have a sync source, and it's not the primary (sync source does not know the primary)2017-05-03T22:24:41.266+0800 I REPL     [replication-39] Canceling oplog query because we have to choose a new sync source. Current s
ource: node3:27018, OpTime { ts: Timestamp 0|0, t: -1 }, its sync source index:-12017-05-03T22:24:41.266+0800 W REPL     [rsBackgroundSync] Fetcher stopped querying remote oplog with error: InvalidSyncSource: sync 
source node3:27018 (last visible optime: { ts: Timestamp 0|0, t: -1 }; config version: 1; sync source index: -1; primary index: -1) is no longer valid2017-05-03T22:24:41.266+0800 I REPL     [rsBackgroundSync] could not find member to sync from
2017-05-03T22:24:46.021+0800 I REPL     [SyncSourceFeedback] SyncSourceFeedback error sending update to node3:27018: InvalidSyncSourc
e: Sync source was cleared. Was node3:270182017-05-03T22:24:46.775+0800 I REPL     [ReplicationExecutor] Starting an election, since we've seen no PRIMARY in the past 10000ms
2017-05-03T22:24:46.775+0800 I REPL     [ReplicationExecutor] conducting a dry run election to see if we could be elected
2017-05-03T22:24:46.857+0800 I REPL     [ReplicationExecutor] VoteRequester(term 2 dry run) received a yes vote from node3:27019; res
ponse message: { term: 2, voteGranted: true, reason: "", ok: 1.0 }2017-05-03T22:24:46.858+0800 I REPL     [ReplicationExecutor] dry election run succeeded, running for election
2017-05-03T22:24:46.891+0800 I REPL     [ReplicationExecutor] VoteRequester(term 3) received a yes vote from node3:27018; response me
ssage: { term: 3, voteGranted: true, reason: "", ok: 1.0 }2017-05-03T22:24:46.891+0800 I REPL     [ReplicationExecutor] election succeeded, assuming primary role in term 3
2017-05-03T22:24:46.891+0800 I REPL     [ReplicationExecutor] transition to PRIMARY
2017-05-03T22:24:46.892+0800 I ASIO     [NetworkInterfaceASIO-Replication-0] Connecting to node3:27019
2017-05-03T22:24:46.894+0800 I ASIO     [NetworkInterfaceASIO-Replication-0] Connecting to node3:27019
2017-05-03T22:24:46.894+0800 I ASIO     [NetworkInterfaceASIO-Replication-0] Successfully connected to node3:27019
2017-05-03T22:24:46.895+0800 I REPL     [ReplicationExecutor] My optime is most up-to-date, skipping catch-up and completing transiti
on to primary.2017-05-03T22:24:46.895+0800 I ASIO     [NetworkInterfaceASIO-Replication-0] Successfully connected to node3:27019
2017-05-03T22:24:47.348+0800 I REPL     [rsSync] transition to primary complete; database writes are now permitted
2017-05-03T22:24:49.231+0800 I NETWORK  [thread1] connection accepted from 192.168.244.30:35837 #9 (3 connections now open)
2017-05-03T22:24:49.236+0800 I NETWORK  [conn9] received client metadata from 192.168.244.30:35837 conn9: { driver: { name: "NetworkI
nterfaceASIO-RS", version: "3.4.2" }, os: { type: "Linux", name: "Red Hat Enterprise Linux Server release 6.7 (Santiago)", architecture: "x86_64", version: "Kernel 2.6.32-573.el6.x86_64" } }2017-05-03T22:24:49.317+0800 I NETWORK  [thread1] connection accepted from 192.168.244.30:35838 #10 (4 connections now open)
2017-05-03T22:24:49.318+0800 I NETWORK  [conn10] received client metadata from 192.168.244.30:35838 conn10: { driver: { name: "Networ
kInterfaceASIO-RS", version: "3.4.2" }, os: { type: "Linux", name: "Red Hat Enterprise Linux Server release 6.7 (Santiago)", architecture: "x86_64", version: "Kernel 2.6.32-573.el6.x86_64" } }
復制代碼
View Code

原Primary node3:27018降低為Secondary

復制代碼
2017-05-03T22:24:36.262+0800 I COMMAND  [conn7] Attempting to step down in response to replSetStepDown command
2017-05-03T22:24:36.303+0800 I REPL     [conn7] transition to SECONDARY
2017-05-03T22:24:36.315+0800 I NETWORK  [conn7] legacy transport layer closing all connections
2017-05-03T22:24:36.316+0800 I NETWORK  [conn7] Skip closing connection for connection # 5
2017-05-03T22:24:36.316+0800 I NETWORK  [conn7] Skip closing connection for connection # 4
2017-05-03T22:24:36.316+0800 I NETWORK  [conn7] Skip closing connection for connection # 4
2017-05-03T22:24:36.316+0800 I NETWORK  [conn7] Skip closing connection for connection # 3
2017-05-03T22:24:36.316+0800 I NETWORK  [conn7] Skip closing connection for connection # 1
2017-05-03T22:24:36.316+0800 I NETWORK  [conn7] Skip closing connection for connection # 1
2017-05-03T22:24:36.382+0800 I NETWORK  [thread1] connection accepted from 127.0.0.1:43359 #8 (5 connections now open)
2017-05-03T22:24:36.383+0800 I NETWORK  [conn8] received client metadata from 127.0.0.1:43359 conn8: { application: { name: "MongoDB 
Shell" }, driver: { name: "MongoDB Internal Client", version: "3.4.2" }, os: { type: "Linux", name: "Red Hat Enterprise Linux Server release 6.7 (Santiago)", architecture: "x86_64", version: "Kernel 2.6.32-573.el6.x86_64" } }2017-05-03T22:24:36.408+0800 I -        [conn7] AssertionException handling request, closing client connection: 172 Operation attempt
ed on a closed transport Session.2017-05-03T22:24:36.408+0800 I -        [conn7] end connection 127.0.0.1:43355 (6 connections now open)
2017-05-03T22:24:41.262+0800 I COMMAND  [conn5] command local.oplog.rs command: find { find: "oplog.rs", filter: { ts: { $gte: Timest
amp 1493821475000|1 } }, tailable: true, oplogReplay: true, awaitData: true, maxTimeMS: 60000, term: 2 } planSummary: COLLSCAN cursorid:12906944372 keysExamined:0 docsExamined:1 writeConflicts:1 numYields:1 nreturned:1 reslen:392 locks:{ Global: { acquireCount: { r: 4 } }, Database: { acquireCount: { r: 2 } }, oplog: { acquireCount: { r: 2 } } } protocol:op_command 100ms2017-05-03T22:24:48.311+0800 I REPL     [ReplicationExecutor] Member node3:27017 is now in state PRIMARY
2017-05-03T22:24:49.163+0800 I REPL     [rsBackgroundSync] sync source candidate: node3:27017
2017-05-03T22:24:49.164+0800 I ASIO     [NetworkInterfaceASIO-RS-0] Connecting to node3:27017
2017-05-03T22:24:49.236+0800 I ASIO     [NetworkInterfaceASIO-RS-0] Successfully connected to node3:27017
2017-05-03T22:24:49.316+0800 I ASIO     [NetworkInterfaceASIO-RS-0] Connecting to node3:27017
2017-05-03T22:24:49.318+0800 I ASIO     [NetworkInterfaceASIO-RS-0] Successfully connected to node3:27017
2017-05-03T22:25:41.020+0800 I -        [conn4] end connection 192.168.244.30:36940 (5 connections now open)
2017-05-03T22:29:02.653+0800 I ASIO     [NetworkInterfaceASIO-RS-0] Connecting to node3:27017
2017-05-03T22:29:02.669+0800 I ASIO     [NetworkInterfaceASIO-RS-0] Successfully connected to node3:27017
2017-05-03T22:29:41.442+0800 I -        [conn5] end connection 192.168.244.30:36941 (4 connections now open)
復制代碼
View Code

 

凍結Secondary節點

如果需要對Primary做一下維護,但是不希望在維護的這段時間內將其它Secondary節點選舉為Primary節點,可以在每次Secondary節點上執行freeze命令,強制使它們始終處於Secondary節點狀態。

myapp:SECONDARY> rs.freeze(100)

注:只能在Secondary節點上執行

復制代碼
myapp:PRIMARY> rs.freeze(100)
{
    "ok" : 0,
    "errmsg" : "cannot freeze node when primary or running for election. state: Primary",
    "code" : 95,
    "codeName" : "NotSecondary"
}
復制代碼

如果要解凍Secondary節點,只需執行

myapp:SECONDARY> rs.freeze()

 

強制Secondary節點進入維護模式

當Secondary節點進入到維護模式后,它的狀態即轉化為“RECOVERING”,在這個狀態的節點,客戶端不會發送讀請求給它,同時它也不能作為復制源。

進入維護模式有兩種觸發方式:

1. 自動觸發

    譬如Secondary上執行壓縮

2. 手動觸發

myapp:SECONDARY> db.adminCommand({"replSetMaintenance":true})

 

修改副本集的配置

添加節點

myapp:PRIMARY> rs.add("node3:27017")
myapp:PRIMARY> rs.add({_id: 3, host: "node3:27017", priority: 0, hidden: true})

也可通過配置文件的方式

復制代碼
> cfg={
    "_id" : 3,
    "host" : "node3:27017",
    "arbiterOnly" : false,
    "buildIndexes" : true,
    "hidden" : true,
    "priority" : 0,
    "tags" : {
        
    },
    "slaveDelay" : NumberLong(0),
    "votes" : 1
}
> rs.add(cfg)
復制代碼

 

刪除節點

第一種方式

myapp:PRIMARY> rs.remove("node3:27017")

第二種方式

myapp:PRIMARY> cfg = rs.conf()
myapp:PRIMARY> cfg.members.splice(2,1)
myapp:PRIMARY> rs.reconfig(cfg)

注:執行rs.reconfig並不必然帶來副本集的重新選舉,加force參數同樣如此。

The rs.reconfig() shell method can trigger the current primary to step down in some situations. 

 

修改節點的配置

將Secondary節點設置為延遲備份節點

cfg = rs.conf()
cfg.members[1].priority = 0
cfg.members[1].hidden = true
cfg.members[1].slaveDelay = 3600
rs.reconfig(cfg)

 

將Secondary節點設置為隱藏節點

cfg = rs.conf()
cfg.members[0].priority = 0
cfg.members[0].hidden = true
rs.reconfig(cfg)

 

替換當前的副本集成員

cfg = rs.conf()
cfg.members[0].host = "mongo2.example.net"
rs.reconfig(cfg)

 

設置副本集節點的優先級

cfg = rs.conf()
cfg.members[0].priority = 0.5
cfg.members[1].priority = 2
cfg.members[2].priority = 2
rs.reconfig(cfg)

優先級的有效取值是0~1000,可為小數,默認為1

從MongoDB 3.2開始

Non-voting members must have priority of 0.
Members with priority greater than 0 cannot have 0 votes.

注:如果將當前Secondary節點的優先級設置的大於Primary節點的優先級,會導致當前Primary節點的退位。

 

阻止Secondary節點升級為Primary節點

只需將priority設置為0

fg = rs.conf()
cfg.members[2].priority = 0
rs.reconfig(cfg)

 

如何設置沒有投票權的Secondary節點

MongoDB限制一個副本集最多只能擁有50個成員節點,其中,最多只有7個成員節點擁有投票權。

之所以作此限制,主要是考慮到心跳請求導致的網絡流量,畢竟每個成員都要向其它所有成員發送心跳請求,和選舉花費的時間。

從MongoDB 3.2開始,任何priority大於0的節點都不可將votes設置為0

所以,對於沒有投票權的Secondary節點,votes和priority必須同時設置為0

cfg = rs.conf() 
cfg.members[3].votes = 0 
cfg.members[3].priority = 0 
cfg.members[4].votes = 0
cfg.members[4].priority = 0 
rs.reconfig(cfg) 

 

禁用chainingAllowed

默認情況下,允許級聯復制。

即備份集中如果新添加了一個節點,這個節點很可能是從其中一個Secondary節點處進行復制,而不是從Primary節點處復制。

MongoDB根據ping時間選擇同步源,一個節點向另一個節點發送心跳請求,就可以得知心跳請求所耗費的時間。MongoDB維護着不同節點間心跳請求的平均花費時間,選擇同步源時,會選擇一個離自己比較近而且數據比自己新的節點。

如何判斷節點是從哪個節點處進行復制的呢?

myapp:PRIMARY> rs.status().members[1].syncingTo
node3:27018

當然,級聯復制也有顯而易見的缺點:復制鏈越長,將寫操作復制到所有Secondary節點所花費的時間就越長。

可通過如下方式禁用

cfg=rs.conf()
cfg.settings.chainingAllowed=false
rs.reconfig(cfg)

將chainingAllowed設置為false后,所有Secondary節點都會從Primary節點復制數據。

 

為Secondary節點顯式指定復制源

rs.syncFrom("node3:27019")

 

禁止Secondary節點創建索引

有時,並不需要Secondary節點擁有和Primary節點相同的索引,譬如這個節點只是用來處理數據備份或者離線的批量任務。這個時候,就可以阻止Secondary節點創建索引。

在MongoDB 3.4版本中,不允許直接修改,只能在添加節點時顯式指定

復制代碼
myapp:PRIMARY> cfg=rs.conf()
myapp:PRIMARY> cfg.members[2].buildIndexes=false
false
myapp:PRIMARY> rs.reconfig(cfg)
{
    "ok" : 0,
    "errmsg" : "priority must be 0 when buildIndexes=false",
    "code" : 103,
    "codeName" : "NewReplicaSetConfigurationIncompatible"
}
myapp:PRIMARY> cfg.members[2].buildIndexes=false
false
myapp:PRIMARY> cfg.members[2].priority=0
0
myapp:PRIMARY> rs.reconfig(cfg)
{
    "ok" : 0,
    "errmsg" : "New and old configurations differ in the setting of the buildIndexes field for member node3:27017; to make this c
hange, remove then re-add the member",    "code" : 103,
    "codeName" : "NewReplicaSetConfigurationIncompatible"
}
myapp:PRIMARY> rs.remove("node3:27017")
{ "ok" : 1 }
myapp:PRIMARY> rs.add({_id: 2, host: "node3:27017", priority: 0, buildIndexes:false})
{ "ok" : 1 }
復制代碼

從上述測試中可以看出,如果要將節點的buildIndexes設置為false,必須同時將priority設置為0。

 

參考

1.《MongoDB權威指南》

2. MongoDB官方文檔

轉載自:

https://www.cnblogs.com/ivictor/p/6804408.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM