手把手教你搭建mongodb副本集
搭建mongodb副本集
一. 什么是副本集
副本集(Replica Set)是一组MongoDB实例组成的集群,由一个主(Primary)服务器和多个备份(Secondary)服务器构成。通过Replication,将数据的更新由Primary推送到其他实例上,在一定的延迟之后,每个MongoDB实例维护相同的数据集副本。通过维护冗余的数据库副本,能够实现数据的异地备份,读写分离和自动故障转移。 早期的MongoDB版本使用master-slave,一主一从和MySQL类似,但slave在此架构中为只读,当主库宕机后,从库不能自动切换为主。目前已经淘汰master-slave模式,改为副本集,这种模式下有一个主(primary),和多个从(secondary),只读。支持给它们设置权重,当主宕掉后,权重最高的从切换为主。在此架构中还可以建立一个仲裁(arbiter)的角色,它只负责裁决,而不存储数据。此架构中读写数据都是在主上,要想实现负载均衡的目的需要手动指定读库的目标server。 以上内容引自(blog.51cto.com/zero01/2059…



二. 开始动手搭建
副本集的目的是实现能够持续性提供服务以及数据的异地安全备份,一般每个实例节点会存放在一个服务器节点上,这里没有那么多服务器,便在同一服务器上进行搭建,使用不同的端口创建实例。
1. 依次执行三条命令
```
mongod --dbpath=/home/mongodb/db/testReplPrim --logpath=/home/mongodb/logs/mongolog_testReplPrim --logappend --fork --port=27017 --replSet=testRepl
```
```
mongod --dbpath=/home/mongodb/db/testReplSec1 --logpath=/home/mongodb/logs/mongolog_testReplSec1 --logappend --fork --port=27018 --replSet=testRepl
```
```
mongod --dbpath=/home/mongodb/db/testReplSec2 --logpath=/home/mongodb/logs/mongolog_testReplSec2 --logappend --fork --port=27019 --replSet=testRepl
```
2. 选择一个mongodb实例作为primary节点,这里我们选择27017
连接到该实例
```
mongo --port 27017
```
```
use admin
```
3. 在admin下创建用户
```
db.createUser({
user:"test01",
pwd:"abc123",
roles:[{
role:"userAdminAnyDatabase",db:"admin"
},{
role:"clusterAdmin",db:"admin"
}]})
```
```
db.auth('test01','abc123')
```
4. 初始化副本集
```
rs.initiate({"_id":"testRepl","members":[{"_id":0,"host":"10.10.10.10:27017",priority:3},{"_id":1,"host":"10.10.10.10:27018",priority:2},{"_id":2,"host":"10.10.10.10:27019",priority:0,slaveDelay:86400}]})
```
ip是随机写的,此时我们已经初始化好了mongodb副本集,其中27017是primary节点,27018和27019位secondary节点,20179实例会延时60秒同步数据。
5. 新建一个数据库
```use testdb```
6. 创建一个user
```db.createUser({"user":"testdb01","pwd":"abc123",roles:[{role:"readWrite",db:"testdb"}]})```
7. 新增一个customers集合并加一条文档
```db.customers.insert({"name":"wang"})```
此时,27017实例中,testdb库下的customer集合会有一条文档,在其他两个实例中也会有相同的数据
8. 连接27018实例
```mongo --port 27018```
```use testdb```
```show collections```
9. 这时会显示:
```
2018-11-08T16:50:10.122+0800 E QUERY [thread1] Error: listCollections failed: { "ok" : 0, "errmsg" : "not master and slaveOk=false", "code" : 13435 } :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
DB.prototype._getCollectionInfosCommand@src/mongo/shell/db.js:773:1
DB.prototype.getCollectionInfos@src/mongo/shell/db.js:785:19
DB.prototype.getCollectionNames@src/mongo/shell/db.js:796:16
shellHelper.show@src/mongo/shell/utils.js:753:9
shellHelper@src/mongo/shell/utils.js:650:15
@(shellhelp2):1:1
```
由于我们是在secondary节点,需要执行如下命令
```rs.slaveOk()```
```show collections```

10. 可以看到,secondary节点已经将数据同步过来了,至此我们已经完成了基本副本集的搭建,不过,不过显而易见的是,我们在启动数据库实例的时候并没有添加--auth选项,也就是说,我们不需要任何验证就可以对数据库进行操作,这在生产环境中是不可行的,所以我们需要添加--auth选项,那我们先把三个服务实例关闭
```
mongod --dbpath=/home/mongodb/db/testReplPrim --logpath=/home/mongodb/logs/mongolog_testReplPrim --logappend --fork --port=27017 --replSet=testRepl --shutdown
```
```
mongod --dbpath=/home/mongodb/db/testReplSec1 --logpath=/home/mongodb/logs/mongolog_testReplSec1 --logappend --fork --port=27018 --replSet=testRepl --shutdown
```
```
mongod --dbpath=/home/mongodb/db/testReplSec2 --logpath=/home/mongodb/logs/mongolog_testReplSec2 --logappend --fork --port=27019 --replSet=testRepl
--shutdown
```
11. 然后分别启动三个实例
```
mongod --dbpath=/home/mongodb/db/testReplPrim --logpath=/home/mongodb/logs/mongolog_testReplPrim --logappend --fork --port=27017 --replSet=testRepl --auth
```
```
mongod --dbpath=/home/mongodb/db/testReplSec1 --logpath=/home/mongodb/logs/mongolog_testReplSec1 --logappend --fork --port=27018 --replSet=testRepl --auth
```
```
mongod --dbpath=/home/mongodb/db/testReplSec2 --logpath=/home/mongodb/logs/mongolog_testReplSec2 --logappend --fork --port=27019 --replSet=testRepl
--auth
```
12. 连接primary实例节点
```mongo --port 27017```
```use admin```
```db.auth('test01','abc123')```
```rs.status()```
会看到如下状态
```
{
"set" : "testRepl",
"date" : ISODate("2018-11-08T10:36:32.750Z"),
"myState" : 3,
"term" : NumberLong(6),
"heartbeatIntervalMillis" : NumberLong(2000),
"members" : [
{
"_id" : 0,
"name" : "10.10.10.10:25231",
"health" : 1,
"state" : 3,
"stateStr" : "RECOVERING",
"uptime" : 1002,
"optime" : {
"ts" : Timestamp(1541671316, 2),
"t" : NumberLong(6)
},
"optimeDate" : ISODate("2018-11-08T10:01:56Z"),
"infoMessage" : "could not find member to sync from",
"configVersion" : 1,
"self" : true
},
{
"_id" : 1,
"name" : "10.10.10.10:25232",
"health" : 0,
"state" : 6,
"stateStr" : "(not reachable/healthy)",
"uptime" : 0,
"optime" : {
"ts" : Timestamp(0, 0),
"t" : NumberLong(-1)
},
"optimeDate" : ISODate("1970-01-01T00:00:00Z"),
"lastHeartbeat" : ISODate("2018-11-08T10:36:30.447Z"),
"lastHeartbeatRecv" : ISODate("1970-01-01T00:00:00Z"),
"pingMs" : NumberLong(0),
"authenticated" : false,
"configVersion" : -1
},
{
"_id" : 2,
"name" : "10.10.10.10:25233",
"health" : 0,
"state" : 6,
"stateStr" : "(not reachable/healthy)",
"uptime" : 0,
"optime" : {
"ts" : Timestamp(0, 0),
"t" : NumberLong(-1)
},
"optimeDate" : ISODate("1970-01-01T00:00:00Z"),
"lastHeartbeat" : ISODate("2018-11-08T10:36:30.452Z"),
"lastHeartbeatRecv" : ISODate("1970-01-01T00:00:00Z"),
"pingMs" : NumberLong(0),
"authenticated" : false,
"configVersion" : -1
}
],
"ok" : 1
}
```
说明主节点无法建立与其他节点互访认证,那如何建立互访认证呢,就需要用到Keyfile
三. 使用keyfile访问控制的方式建立各节点间认证机制
1. 生成keyfile
`openssl rand -base64 100 > /usr/local/keyfile/mongodb_keyfile`
2. 修改文件权限
`chmod 600 /usr/local/keyfile/mongodb_keyfile`
3. 将生成的keyfile文件拷贝到各节点的机器上,注意路径要和mongodb启动时指定的keyfile路径一致
4. 关闭三个服务实例
`mongod --dbpath=/home/mongodb/db/testReplPrim --logpath=/home/mongodb/logs/mongolog_testReplPrim --logappend --fork --port=27017 --replSet=testRepl --shutdown`
`mongod --dbpath=/home/mongodb/db/testReplSec1 --logpath=/home/mongodb/logs/mongolog_testReplSec1 --logappend --fork --port=27018 --replSet=testRepl --shutdown`
`mongod --dbpath=/home/mongodb/db/testReplSec2 --logpath=/home/mongodb/logs/mongolog_testReplSec2 --logappend --fork --port=27019 --replSet=testRepl --shutdown`
5. 重启三个服务实例
`mongod --dbpath=/home/mongodb/db/testReplPrim --logpath=/home/mongodb/logs/mongolog_testReplPrim --logappend --fork --port=27017 --replSet=testRepl keyFile=/usr/local/keyfile/mongodb_keyfile --auth`
`mongod --dbpath=/home/mongodb/db/testReplSec1 --logpath=/home/mongodb/logs/mongolog_testReplSec1 --logappend --fork --port=27018 --replSet=testRepl keyFile=/usr/local/keyfile/mongodb_keyfile --auth`
`mongod --dbpath=/home/mongodb/db/testReplSec2 --logpath=/home/mongodb/logs/mongolog_testReplSec2 --logappend --fork --port=27019 --replSet=testRepl keyFile=/usr/local/keyfile/mongodb_keyfile--auth`
6. 连接端口为21071实例
`mongo --port 27017`
`use admin`
`db.auth('test01','abc123')`
`rs.status()`

转载自:https://juejin.cn/post/6844903710145904654