mongodb replica sets复制集详解
2016-06-07 21:55
579 查看
一.replicasets介绍
一个复制集是一组包含相同数据集的mongod实例.一个复制集只能有一个是primary节点,其它的节点为secondary节点.和主从复制的原理一样,复制集也是通过读取oplog来进行数据传输.oplog是一个cappedcollection即固定表,创建表的时候可以指定其大小,当oplog满的时候会删除旧的数据.所以设置oplog的大小非常重要,如果oplog在primary节点被覆盖而尚未被secondary节点读取的话就要重新resync.
一般的使用replicasets复制集使用如下架构,一主一备,还有一个仲裁负责进行failover.仲裁主机不存放数据.
复制集使用的异步同步方式,复制集成员直接每隔2s发送一次hearbeat(pings).当主节点与其它成员通信超时10s后,一个secondary节点将会被选举为primary节点.在新的版本中,如果存在多个secondary节点,当第一个节点被选举为primary后,其它的secondary节点将从它开始复制数据.
二.创建replicasets
下面是搭建一个一主两从三节点replicasets的具体步骤
(1).添加replSet参数
在你所有节点的mongodb实例添加replSet参数,在一个group中的replSet参数需要一致,有点类似于oracledg中的db_name参数.然后启动所有节点的mongodb实例
例如我的主机名为mongodb1的配置文件:
[root@mongodb1~]#cat/etc/mongod.conf
port=27017
dbpath=/data/db
logpath=/data/log/mongod.log
fork=true
oplogSize=500
replSet=rs0[/code]
然后启动所有的实例:
[root@mongodb1~]#mongod-f/etc/mongod.conf
abouttoforkchildprocess,waitinguntilserverisreadyforconnections.
forkedprocess:2722
childprocessstartedsuccessfully,parentexiting[/code]
(2).初始化replicaset
使用rs.initiate()来初始化复制集,在一个节点而且只能在一个节点进行初始化,例如我们这里在mongodb1上进行初始化,那么这个节点将会成为primary节点.这里我们没有配置config参数文件,那么系统会使用默认的配置文件.
>rs.initiate()
{
"info2":"noconfigurationspecified.Usingadefaultconfigurationfortheset",
"me":"mongodb1:27017",
"ok":1
}
rs0:OTHER>[/code]
当然你也可以先配置一个配置文件,然后使用rs.initiate(rsconf)来初始化,例如:
rsconf={
_id:"rs0",
members:[
{
_id:0,
host:"<hostname>:27017"
}
]
}[/code]
(3).检查初始化配置文件
使用rs.conf()来查看初始化配置文件:rs0:OTHER>rs.conf()
{
"_id":"rs0",
"version":1,
"protocolVersion":NumberLong(1),
"members":[
{
"_id":0,
"host":"mongodb1:27017",
"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
},
"replicaSetId":ObjectId("575647b35e9005faa0e8d690")
}
}[/code]
可以看到当前的members只有一个,即_id为0的,即我们刚刚初始化的这个节点.
(4).将剩下的成员添加到复制集
使用rs.add()方法将成员添加到复制集.你必须连接到primary节点来执行添加成员的操作.你可以使用rs.status()查看主节点信息:rs0:PRIMARY>rs.status()
{
"set":"rs0",
"date":ISODate("2016-06-07T04:16:20.542Z"),
"myState":1,
"term":NumberLong(1),
"heartbeatIntervalMillis":NumberLong(2000),
"members":[
{
"_id":0,
"name":"mongodb1:27017",
"health":1,
"state":1,
"stateStr":"PRIMARY",
"uptime":1184,
"optime":{
"ts":Timestamp(1465272244,1),
"t":NumberLong(1)
},
"optimeDate":ISODate("2016-06-07T04:04:04Z"),
"electionTime":Timestamp(1465272243,2),
"electionDate":ISODate("2016-06-07T04:04:03Z"),
"configVersion":1,
"self":true
}
],
"ok":1
}[/code]
添加成员:
rs0:PRIMARY>rs.add("mongodb2:27017")
{"ok":1}
rs0:PRIMARY>rs.add("mongodb3:27017")
{"ok":1}[/code]
再次查看复制集配置,可以看到members有三个成员了.
rs0:PRIMARY>rs.conf()
{
"_id":"rs0",
"version":3,
"protocolVersion":NumberLong(1),
"members":[
{
"_id":0,
"host":"mongodb1:27017",
"arbiterOnly":false,
"buildIndexes":true,
"hidden":false,
"priority":1,
"tags":{
},
"slaveDelay":NumberLong(0),
"votes":1
},
{
"_id":1,
"host":"mongodb2:27017",
"arbiterOnly":false,
"buildIndexes":true,
"hidden":false,
"priority":1,
"tags":{
},
"slaveDelay":NumberLong(0),
"votes":1
},
{
"_id":2,
"host":"mongodb3:27017",
"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
},
"replicaSetId":ObjectId("575647b35e9005faa0e8d690")
}
}[/code]
查看复制集状态,可以看到mongodb1是primary节点,其它两个是secondary节点:
rs0:PRIMARY>rs.status()
{
"set":"rs0",
"date":ISODate("2016-06-07T04:28:12.721Z"),
"myState":1,
"term":NumberLong(1),
"heartbeatIntervalMillis":NumberLong(2000),
"members":[
{
"_id":0,
"name":"mongodb1:27017",
"health":1,
"state":1,
"stateStr":"PRIMARY",
"uptime":1896,
"optime":{
"ts":Timestamp(1465273627,1),
"t":NumberLong(1)
},
"optimeDate":ISODate("2016-06-07T04:27:07Z"),
"electionTime":Timestamp(1465272243,2),
"electionDate":ISODate("2016-06-07T04:04:03Z"),
"configVersion":3,
"self":true
},
{
"_id":1,
"name":"mongodb2:27017",
"health":1,
"state":2,
"stateStr":"SECONDARY",
"uptime":73,
"optime":{
"ts":Timestamp(1465273627,1),
"t":NumberLong(1)
},
"optimeDate":ISODate("2016-06-07T04:27:07Z"),
"lastHeartbeat":ISODate("2016-06-07T04:28:11.197Z"),
"lastHeartbeatRecv":ISODate("2016-06-07T04:28:12.206Z"),
"pingMs":NumberLong(0),
"syncingTo":"mongodb1:27017",
"configVersion":3
},
{
"_id":2,
"name":"mongodb3:27017",
"health":1,
"state":2,
"stateStr":"SECONDARY",
"uptime":65,
"optime":{
"ts":Timestamp(1465273627,1),
"t":NumberLong(1)
},
"optimeDate":ISODate("2016-06-07T04:27:07Z"),
"lastHeartbeat":ISODate("2016-06-07T04:28:11.198Z"),
"lastHeartbeatRecv":ISODate("2016-06-07T04:28:09.224Z"),
"pingMs":NumberLong(0),
"configVersion":3
}
],
"ok":1
}[/code]
我们到mongodb2节点查看日志,发现我们在进行rs.add()的时候,系统自动进行了初始化:
2016-06-07T12:26:57.846+0800IREPL[ReplicationExecutor]Thisnodeismongodb2:27017intheconfig
2016-06-07T12:26:57.846+0800IREPL[ReplicationExecutor]transitiontoSTARTUP2
2016-06-07T12:26:57.846+0800IREPL[rsSync]******
2016-06-07T12:26:57.846+0800IREPL[rsSync]creatingreplicationoplogofsize:500MB...
2016-06-07T12:26:57.846+0800IREPL[ReplicationExecutor]Membermongodb1:27017isnowinstatePRIMARY
2016-06-07T12:26:57.858+0800ISTORAGE[rsSync]StartingWiredTigerRecordStoreThreadlocal.oplog.rs
2016-06-07T12:26:57.858+0800ISTORAGE[rsSync]Thesizestorerreportsthattheoplogcontains0recordstotalingto0bytes
2016-06-07T12:26:57.858+0800ISTORAGE[rsSync]Scanningtheoplogtodeterminewheretoplacemarkersfortruncation
2016-06-07T12:26:57.922+0800IREPL[rsSync]******
2016-06-07T12:26:57.922+0800IREPL[rsSync]initialsyncpending
2016-06-07T12:26:57.940+0800IREPL[ReplicationExecutor]syncingfrom:mongodb1:27017
2016-06-07T12:26:57.943+0800IREPL[rsSync]initialsyncdropalldatabases
2016-06-07T12:26:57.943+0800ISTORAGE[rsSync]dropAllDatabasesExceptLocal2
2016-06-07T12:26:57.966+0800IREPL[rsSync]initialsyncclonealldatabases
2016-06-07T12:26:57.967+0800IREPL[rsSync]initialsynccloningdb:suq
...
...
...
2016-06-07T12:27:00.234+0800IREPL[rsSync]oplogsync3of3
2016-06-07T12:27:00.235+0800IREPL[rsSync]initialsyncfinishingup
2016-06-07T12:27:00.235+0800IREPL[rsSync]setminValid=(term:1,timestamp:Jun712:26:58:1)
2016-06-07T12:27:00.240+0800IREPL[rsSync]initialsyncdone
2016-06-07T12:27:00.241+0800IREPL[ReplicationExecutor]transitiontoRECOVERING
2016-06-07T12:27:00.242+0800IREPL[ReplicationExecutor]transitiontoSECONDARY[/code]
此时登录到mongodb2上发现提示符也变成了secondary,查看数据也全部同步过来了:
rs0:SECONDARY>usesuq
switchedtodbsuq
rs0:SECONDARY>rs.slaveOk()
rs0:SECONDARY>showcollections
t1
test2
test3
test4
test5
test6
test7[/code]
到此replicasets的搭建就结束了,还是蛮简单的.
三.复制集参数
(1)参数介绍
这里介绍rs.conf()里的参数,例如下面这个config内容:rs0:PRIMARY>rs.conf()
{
"_id":"rs0",
"version":3,
"protocolVersion":NumberLong(1),
"members":[
{
"_id":0,
"host":"mongodb1:27017",
"arbiterOnly":false,
"buildIndexes":true,
"hidden":false,
"priority":1,
"tags":{
},
"slaveDelay":NumberLong(0),
"votes":1
},
{
"_id":1,
"host":"mongodb2:27017",
"arbiterOnly":false,
"buildIndexes":true,
"hidden":false,
"priority":1,
"tags":{
},
"slaveDelay":NumberLong(0),
"votes":1
},
{
"_id":2,
"host":"mongodb3:27017",
"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
},
"replicaSetId":ObjectId("575647b35e9005faa0e8d690")
}
}[/code]
_id:是用来标识复制集,参数内容和数据库启动的时候设置的rplSet参数一致
version:用来表示config参数的新旧,每次修改了config然后使用rs.reconfig重新配置的时候version的值会自动加1
protocolversion:是协议版本
members是一个数组,数组成员表示每个节点的信息.下面结束members的主要内容.
_id:用来标识节点号,唯一
host:表示节点的地址和端口信息
arbiterOnly:这是一个bool型,默认为false,用来表示这个节点是否是arbiter节点,只是用来投票
buildIndexes:这也是一个bool型,默认为true.用来表示同步的时候是否同步索引.一般设置为true.如果要设置为false,则必须将priority设置为0
hidden:这也是bool型,默认问false,用来表示这个节点是否为隐藏节点,如果是隐藏节点将不对外服务,只是单纯的同步信息,而且如果设置为了隐藏节点,使用rs.isMaster()方法将无法查看到隐藏节点的信息,但是可以使用rs.status()查看.设置隐藏节点必须首先将节点的priority设置为0
priority:表示权重,默认为1,如果将priority设置为0那么这个节点将永远无法成为primary节点,现在新的版本可以设置为超过1的数
slaveDelay:复制延迟,这个是整数,单位为秒,用来设置复制的延时.一般用来防止误操作,延迟节点必须优先级设置为0,hidden设置为true,然后设置slaveDelay值,
votes:表示这个节点是否有权利进行投票.
tags:表示标记,例如可以标记这个节点的作用等
settings是一些配置信息
chainingAllowed:表示是否允许链式复制,即某个secondary可以作为其它的secondary的源,默认是true.
heartbeatIntervalMillis:表示heartbeat的间隔时间,默认是没个两秒钟发送一个hearbeat包.
heartbeatTimeoutSecs:表示心跳检测超时时间,默认是10秒.
electionTimeoutMillis:表示选举超时时间,默认是10秒.
(2)参数修改
详细的修改参数参考官方文档:修改复制集的参数一般分为三步:
1.将当前的参数进行复制
rs0:PRIMARY>rsconfig=rs.conf()[/code]
2.修改参数
例如我要将节点_id为2的主机的权限设置为0.5
rs0:PRIMARY>rsconfig.members[2].priority=0.5
0.5[/code]
3.重新reconfig设置
rs0:PRIMARY>rs.reconfig(rsconfig)
{"ok":1}[/code]
最后重新查看配置文件:
{
"_id":2,
"host":"mongodb3:27017",
"arbiterOnly":false,
"buildIndexes":true,
"hidden":false,
"priority":0.5,
"tags":{
},
"slaveDelay":NumberLong(0),
"votes":1
}[/code]
四.复制集管理
Replicatemethods方法
可以使用rs.help()来查看所有的复制方法rs0:SECONDARY>rs.help()
rs.status(){replSetGetStatus:1}checksreplsetstatus
rs.initiate(){replSetInitiate:null}initiatessetwithdefaultsettings
rs.initiate(cfg){replSetInitiate:cfg}initiatessetwithconfigurationcfg
rs.conf()getthecurrentconfigurationobjectfromlocal.system.replset
rs.reconfig(cfg)updatestheconfigurationofarunningreplicasetwithcfg(disconnects)
rs.add(hostportstr)addanewmembertothesetwithdefaultattributes(disconnects)
rs.add(membercfgobj)addanewmembertothesetwithextraattributes(disconnects)
rs.addArb(hostportstr)addanewmemberwhichisarbiterOnly:true(disconnects)
rs.stepDown([stepdownSecs,catchUpSecs])stepdownasprimary(disconnects)
rs.syncFrom(hostportstr)makeasecondarysyncfromthegivenmember
rs.freeze(secs)makeanodeineligibletobecomeprimaryforthetimespecified
rs.remove(hostportstr)removeahostfromthereplicaset(disconnects)
rs.slaveOk()allowqueriesonsecondarynodes
rs.printReplicationInfo()checkoplogsizeandtimerange
rs.printSlaveReplicationInfo()checkreplicasetmembersandreplicationlag
db.isMaster()checkwhoisprimary
reconfigurationhelpersdisconnectfromthedatabasesotheshellwilldisplay
anerror,evenifthecommandsucceeds.[/code]
详细可以参考官方文档:
下面的一些修改操作一般都必须在primary节点上执行.
(1)rs.conf查看配置文件
前面已经介绍过了,使用rs.conf()来查看复制集参数
(2)rs.status查看复制集状态
前面已经介绍了一个使用rs.status()查看.还可以使用rs.isMaster()查看节点是否是master节点:
rs0:SECONDARY>rs.isMaster()
{
"hosts":[
"mongodb1:27017",
"mongodb2:27017",
"mongodb3:27017"
],
"setName":"rs0",
"setVersion":4,
"ismaster":false,
"secondary":true,
"primary":"mongodb1:27017",
"me":"mongodb3:27017",
"maxBsonObjectSize":16777216,
"maxMessageSizeBytes":48000000,
"maxWriteBatchSize":1000,
"localTime":ISODate("2016-06-07T12:08:44.914Z"),
"maxWireVersion":4,
"minWireVersion":0,
"ok":1
}[/code]
(3)rs.add添加节点
使用rs.add([host],[arbiterOnly])方法来添加节点到复制集,这个方法有两个参数,第一个参数是host,第二个参数是arbiterOnly,默认为false,当为true的时候表示添加的节点只是用来作为仲裁节点.在3.0以前的版本你需要手工指定_id,3.0以后的版本则不需要,系统会自动添加,下面是常用的语句:
rs.add('mongodb3.example.net:27017')
rs.add({host:"mongodb3:27017",priority:0})
rs.add("mongodb3:27010",true)[/code]
rs0:PRIMARY>rs.add({"host":"mongodb3:27017","priority":0,"hidden":true})
{"ok":1}[/code]
(4)rs.remove删除节点
rs.remove()就一个参数hostname:rs0:PRIMARY>rs.remove("mongodb3:27017")
{"ok":1}[/code]
(5)rs.addArb添加投票节点
rs.addArb()同样可以添加投票节点,也只有一个参数为hostname:rs0:PRIMARY>rs.addArb("mongodb3:27017")
{"ok":1}[/code]
(6)rs.freeze()将节点冻结
rs.freeze()就一个参数,为时间单位秒,表示在多长时间内将此节点冻结,即无法成为primary节点
(7)查看复制延时
rs.printSlaveReplicationInfo()rs0:PRIMARY>rs.printReplicationInfo()
configuredoplogsize:500MB
loglengthstarttoend:30418secs(8.45hrs)
oplogfirsteventtime:TueJun07201612:04:03GMT+0800(CST)
oploglasteventtime:TueJun07201620:31:01GMT+0800(CST)
now:TueJun07201620:39:09GMT+0800(CST)[/code]
rs.printSlaveReplicationInfo()
rs0:SECONDARY>rs.printSlaveReplicationInfo()
source:mongodb2:27017
syncedTo:TueJun07201620:31:01GMT+0800(CST)
0secs(0hrs)behindtheprimary[/code]
结果输出都比较直观,记录了oplog的时间戳,同步延时等信息.
(8)rs.reconfig重新配置参数
rs.reconfig(configuration,force),上面已经介绍了重新配置参数的方法,需要注意的是,在某些情况下执行rs.reconfig()有可能触发将当前的primary降级为secondary节点.当primary降级为secondary的的时候会强制关闭所有的客户端连接,然后花费几分钟时间将secondary节点选举为primary节点,在重新配置期间,数据库将处于不可操作状态.
特别需要注意的是当你指定的force为true的时候有可能会将一个已经提交的写操作回滚掉,因此需要谨慎的使用.
(9)rs.stepDown降级primary
rs.stepDown(stepDownSecs,secondaryCatchUpPeriodSecs)方法将primary节点降级为secondary节点,secondary节点会推选出一个升级为primary节点.此方法有两个参数,第一个参数表示在多少时间内将降级primary,也表示这在此期间此节点无法变为primary,如果你指定了一个非number类型,则默认为60s
第二个参数表示mongod将等待多长时间让一个secondary提升为primary.默认为10s,第一个参数必须大于第二个参数.
rs0:PRIMARY>rs.stepDown()
2016-06-07T20:58:53.657+0800EQUERY[thread1]Error:errordoingquery:failed:networkerrorwhileattemptingtoruncommand'replSetStepDown'onhost'127.0.0.1:27017':
DB.prototype.runCommand@src/mongo/shell/db.js:135:1
DB.prototype.adminCommand@src/mongo/shell/db.js:153:16
rs.stepDown@src/mongo/shell/utils.js:1181:12
@(shell):1:1
2016-06-07T20:58:53.660+0800INETWORK[thread1]tryingreconnectto127.0.0.1:27017(127.0.0.1)failed
2016-06-07T20:58:53.662+0800INETWORK[thread1]reconnect127.0.0.1:27017(127.0.0.1)ok
rs0:SECONDARY>
rs0:SECONDARY>[/code]
需要注意的是stepDown的过程中所有的客户端连接都会断开,会终止一些用户操作,例如创建索引.为了避免回滚,设置第二个参数,让mongod等待一段时间.
如果没有可用的secondary,那么会抛出一个异常.
(10)rs.syncFrom()
rs.syncFrom()可以让管理员里手工设置默认的复制源.参数为["hostname:port"]在3.2版本中一个没有投票权的节点无法作为一个拥有投票权的节点的源.是否拥有投票权查看rs.conf的vote参数.
在rs.status状态中有一个状态为syncingTO表示此节点是从那个节点同步数据,例如:
{
"_id":2,
"name":"mongodb3:27017",
"health":1,
"state":2,
"stateStr":"SECONDARY",
"uptime":33316,
"optime":{
"ts":Timestamp(1465304797,1),
"t":NumberLong(2)
},
"optimeDate":ISODate("2016-06-07T13:06:37Z"),
"syncingTo":"mongodb2:27017",
"configVersion":14,
"self":true
}[/code]
可以看到原来_id为2的节点是从mongodb2(primary)同步数据,我们可以修改他从其它的secondary(mongodb1)来同步数据:
rs0:SECONDARY>rs.syncFrom("mongodb1:27017")
{
"syncFromRequested":"mongodb1:27017",
"prevSyncTarget":"mongodb2:27017",
"ok":1
}[/code]
而且可以可以在日志里面看到如下信息:
2016-06-07T21:10:55.416+0800IREPL[ReplicationExecutor]syncingfrom:mongodb1:27017byrequest
2016-06-07T21:10:55.418+0800IREPL[SyncSourceFeedback]settingsyncSourceFeedbacktomongodb1:27017
2016-06-07T21:10:55.419+0800IASIO[NetworkInterfaceASIO-BGSync-0]Successfullyconnectedtomongodb1:27017
2016-06-07T21:11:17.124+0800IASIO[NetworkInterfaceASIO-BGSync-0]Successfullyconnectedtomongodb1:27017
[/code]
复制维护
(1)修改oplog大小
具体方法见文档:基本思路就是将一个secondary变为单机模式,然后重建local数据库下的oplog.rs集合,在重建的时候需要注意保留最新数据,方法是使用临时表做中间表.
(2)强制将节点转换为primary
具体方法见文档:基本思路就是将节点的优先级调高,然后reconfig
(3)重新同步节点
具体方法见文档:可以使用resync命令:
rs0:SECONDARY>db.runCommand({"resync":1})
{"ok":1}[/code]
如果有多个secondary,可以拷贝其它正常的secondary数据.
还可以先将节点remove,然后删除dbpath下的文件,然后重新add,那么系统会自动进行resync.
(3)修改主机名
详细见文档:相关文章推荐
- MongoDB和System.Transactions
- mongodb插入datetime类型所用函数appendDate的参数Date_t详解
- 遇到问题-----mongodb-------Uncaught TypeError: Cannot read property 'value' of undefined
- 遇到问题-----mongodb-------Uncaught TypeError: Cannot read property 'value' of undefined
- php mongodb 链接失败,提示Authentication failed on database...[坑]
- mongoDB数据库安装+可视化工具安装
- perl 操作mongodb 集锦 demo
- MongoDB基本命令用
- Python调用MongoDB使用心得
- 关于MongoDB里用户权限问题
- 搭建高可用的MongoDB集群
- mongodb分布式集群架构
- Mongodb后台daemon方式启动
- mongodb_修改器($inc/$set/$unset/$push/$pop/upsert......)
- 搭建mongodb集群(副本集+分片)
- 各种脚本语言运用MongoDB的方法
- MongoDB学习
- mongodb命令
- 【MongoDB 可视化工具Robomongo】下载与安装
- 【MongoDB】 基于C#官方驱动2.2版的封装类