MongoDB的复制主要分2种,一种是Master-Salve(主从复制),一种是副本集(replica sets),MongoDB4.0之后就不支持主从复制了,官方原话
MongoDB 4.0 removes support for the deprecated master-slave replication. Before you can upgrade to MongoDB 4.0, if your deployment uses master-slave replication, you must upgrade to a replica set.
MongoDB 4.0删除了对主从复制的支持。在升级到MongoDB 4.0之前,如果部署使用主从复制,则必须升级到副本集.本文只讲解副本集的部署步骤。副本集相比较主从复制而言有2点区别:
-
该集群没有特定的主数据库。
-
如果哪个主数据库宕机了,集群中就会推选出一个从属数据库作为主数据库顶上,这就具备了自动故障恢复功能,很牛X的啊。
角色说明:
1.主库
理论上所有副本集中的数据库都能读取数据,但是系统会默认让主库来完成读取数据的功能
2.辅助副本
主服务器是副本集中唯一接收写操作的成员。MongoDB在主服务器上应用写操作,然后在主服务器的oplog上记录操作。辅助成员复制此日志并将操作应用于其数据集。
3.仲裁者
在主库宕机后重新投票选举出新的主库,它自己不能是主库也不能是辅助副本
副本集配置
1.创建每个库的配置文件,日志文件和数据存档的目录,我本机选择的是 /Data/MongoReplSet/下,MongoReplSet也是我自建的
MongoReplSet下的目录结构
├── conf
│ ├── db1.conf
│ ├── db2.conf
│ └── db3.conf
├── dbs
│ ├── db1
│ ├── db2
│ └── db3
└── logs
├── db1.log
├── db2.log
└── db3.log
conf下的配置内容,其中replSet的值是这个副本集的名称
db1.conf
dbpath=/Data/MongoReplSet/dbs/db1
logpath=/Data/MongoReplSet/logs/db1.log
logappend=true
noprealloc=true
port=27011
fork=true
replSet=testdb2.conf
dbpath=/Data/MongoReplSet/dbs/db2
logpath=/Data/MongoReplSet/logs/db2.log
logappend=true
noprealloc=true
port=27012
fork=true
replSet=testdb3.conf
dbpath=/Data/MongoReplSet/dbs/db3
logpath=/Data/MongoReplSet/logs/db3.log
logappend=true
noprealloc=true
port=27013
fork=true
replSet=test
2.进入3个实例中的任何一个,初始化副本集
mongo --port 27011
use admin
config={
_id:'test',
members:[
{_id:1, host:'localhost:27011',priority:2},
{_id:2, host:'localhost:27012',priority:1},
{_id:3, host:'localhost:27013',arbiterOnly:true}
]
}
rs.initiate(config)
_id:'test'
表示副本集名称,与前面conf配置文件中的replSet参数配置的名称要一致。
priority:2
表示优先级,优先级越高,副本集初始化时会选举为主库。arbiterOnly:true
表示该实例为仲裁节点,不存储数据,只参与投票。
3.rs.status()查看副本集状态
test:SECONDARY> rs.status()
{
"set" : "test",
"date" : ISODate("2019-03-05T05:44:28.581Z"),
"myState" : 2,
"term" : NumberLong(0),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"heartbeatIntervalMillis" : NumberLong(2000),
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(0, 0),
"t" : NumberLong(-1)
},
"appliedOpTime" : {
"ts" : Timestamp(1551764659, 1),
"t" : NumberLong(-1)
},
"durableOpTime" : {
"ts" : Timestamp(1551764659, 1),
"t" : NumberLong(-1)
}
},
"lastStableCheckpointTimestamp" : Timestamp(0, 0),
"members" : [
{
"_id" : 1,
"name" : "localhost:27011",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 108,
"optime" : {
"ts" : Timestamp(1551764659, 1),
"t" : NumberLong(-1)
},
"optimeDate" : ISODate("2019-03-05T05:44:19Z"),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "could not find member to sync from",
"configVersion" : 1,
"self" : true,
"lastHeartbeatMessage" : ""
},
{
"_id" : 2,
"name" : "localhost:27012",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 8,
"optime" : {
"ts" : Timestamp(1551764659, 1),
"t" : NumberLong(-1)
},
"optimeDurable" : {
"ts" : Timestamp(1551764659, 1),
"t" : NumberLong(-1)
},
"optimeDate" : ISODate("2019-03-05T05:44:19Z"),
"optimeDurableDate" : ISODate("2019-03-05T05:44:19Z"),
"lastHeartbeat" : ISODate("2019-03-05T05:44:28.245Z"),
"lastHeartbeatRecv" : ISODate("2019-03-05T05:44:28.124Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"configVersion" : 1
},
{
"_id" : 3,
"name" : "localhost:27013",
"health" : 1,
"state" : 7,
"stateStr" : "ARBITER",
"uptime" : 8,
"lastHeartbeat" : ISODate("2019-03-05T05:44:28.245Z"),
"lastHeartbeatRecv" : ISODate("2019-03-05T05:44:27.654Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"configVersion" : 1
}
],
"ok" : 1,
"operationTime" : Timestamp(1551764659, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1551764659, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
members下面就是整个副片集的成员,其中 27011端口号下面的 infoMessage:‘could not find member to sync from’,表示它没有可以同步的数据集,因为他是主库,只负责写入
4.主库添加测试数据
test:PRIMARY> use test
switched to db test
test:PRIMARY> db.person.insertMany([{"name":"tom", "age": 20}, {"name":"jack", "age":21}, {"name":"luna", "age":18}])
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("5c7e13b79d270105c2390fcd"),
ObjectId("5c7e13b79d270105c2390fce"),
ObjectId("5c7e13b79d270105c2390fcf")
]
}
进副库检查
mongo --port 27012
test:SECONDARY> show dbs
2019-03-05T14:14:44.483+0800 E QUERY [js] Error: listDatabases failed:{
"operationTime" : Timestamp(1551766483, 1),
"ok" : 0,
"errmsg" : "not master and slaveOk=false",
"code" : 13435,
"codeName" : "NotMasterNoSlaveOk",
"$clusterTime" : {
"clusterTime" : Timestamp(1551766483, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
} :
发现没有权限查看,临时解决方案 执行 rs.slaveOk()
test:SECONDARY> rs.slaveOk()
test:SECONDARY> show collections
person
test:SECONDARY> db.person.find()
{ "_id" : ObjectId("5c7e652ecf158632e56497cb"), "name" : "jack", "age" : 21 }
{ "_id" : ObjectId("5c7e652ecf158632e56497cc"), "name" : "luna", "age" : 18 }
{ "_id" : ObjectId("5c7e652ecf158632e56497ca"), "name" : "tom", "age" : 20 }