一、MongoDB 复制集特性
1.复制集群的架构
2.复制集群搭建基础示例
2.复制集群搭建基础示例
主节点配置
dbpath=/data/mongo/master
port=27017
fork=true
logpath=master.log
replSet=MyCluster
从节点配置
dbpath=/data/mongo/slave
port=27018
fork=true
logpath=slave.log
replSet=MyCluster
#子节点配置2
dbpath=/data/mongo/slave2
port=27019
fork=true
logpath=slave2.log
replSet=MyCluster
集群复制配置管理
#查看复制集群的帮助方法
rs.help()
添加配置
// 声明配置变量
var cfg ={"_id":"tuling",
"members":[
{"_id":1,"host":"127.0.0.1:27017"},
{"_id":2,"host":"127.0.0.1:27018"}
]
}
// 初始化配置
rs.initiate(cfg)
// 查看集群状态
rs.status()
变更节点示例:
// 插入新的复制节点
rs.add("127.0.0.1:27019")
// 删除slave 节点
rs.remove("127.0.0.1:27019")
注:默认节点下从节点不能读取数据。调用 rs.slaveOk() 解决。
3.复制集群选举操作
为了保证高可用,在集群当中如果主节点挂掉后,会自动 在从节点中选举一个 重新做为主节点。
选举的原理:
选举协议
pv0: 基于priority 和 optime 选举新主,依赖clock synchronization。
有选举权的节点,每一轮选举最多投一票,在30s内,不能重复投票。
pv1:基于Raft协议,每个成员都有 对候选主列表成员投赞成或者反对票,不是单方面否决选举,没有节点投反对票,且获得赞成票数超过有权投票节点总数的1/2,则能成为Primary。否则进入下一轮选举。
因使用了Raft协议,加快 back-to-back选主,减少整个选举新主所需花费的总时间,相应的会增加WriteConcern(w:1)rollback的可能性。
Raft将时间分为多个term,term以连续的整数来标识,每个term以一次election开始,如果有server被选为leader,则该term的剩余时间该server都是leader。
有些term里,可能并没有选出leader,这时候会开启一个新term来继续选主
选举:
假设X是一个Secondary,那么X会定时检测是否需要选举自己成为Primary。其检测内容包括:
1) 是否集群中有其它节点认为自己是Primary?
2) X节点自己是否已经是Primary?
3) X节点自己是否有资格成为Primary?
如果这三个问题中的任何一个回答是否定的,那么X节点就不会试图把自己变成Primary。(也就是说,只有当X节点是一个能够当Primary 的secondary,并且其它节点都不是Primary时,X才会发起选举并选自己为Primary)。
投票规则:如果没有节点投反对票,且获得赞成票数超过有权投票节点总数的1/2,则能成为Primary。否则进入下一轮选举。
3.2之前(只支持pv0 协议):
|
影响选举的因素:
1)优先级(先看优先级,级别越高,优先为主,priority=0:表示不参与选举、不能成为主
)
2)optime (如果优先级都相同,则有最新的 optime 的成为主) 注意:集群中 prority 最大,但是optime 不是最新的,落后集群其他最新optime超过10s的prority 最大也不能选为主。
3)心跳 (副本级中的每个member默认都是每2秒ping 其他节点,如果超过{"heartbeatTimeoutSecs" : 10} 默认是10秒没有回应,则标记节点不可达s_down)
网络分裂(Network Partition):
如果Primary在少数的那一组,那么次Primary会变成Secondary,多数节点(互相能通信)的那组选举新的主(Primary)。
例外情况:如发生网络分裂,被分裂的一组选举出一个新的Primary,老的Primary还没降级,这就出现了2个Primary,这就是脑裂现象。此时2个Primary都有写入,直到网络恢复后,若老主再次成为Primary,则脑裂过程中选举出的新Primary会回滚脑裂过程新写入的数据;若老主成为Secondary,则回滚老主脑裂过程新写入的数据。
>= 3.2开始:
支持pv0 协议、pv1协议,默认是pv1协议。
影响选举的因素:
1)Replication Election Protocol(从3.2开始支持protocolVersion: 1)
2)优先级(先看优先级,级别越高,优先为主,priority=0:表示不参与选举、不能成为主
)
3)optime (如果优先级都相同,则有最新的 optime 的成为主)
4)心跳 (副本级中的每个member默认都是每2秒ping 其他节点,protocolVersion:0如果超过{"heartbeatTimeoutSecs" : 10} 默认是10秒 或者 protocolVersion:1时 electionTimeoutMillis 默认是10秒没有回应,则标记节点不可达s_down,类似Redis sentinel主观下线)
下面status的节点有资格成为选举者:
PRIMARY
SECONDARY
RECOVERING
ARBITER
ROLLBACK
什么时候发生选举主?
1)初始化副本集
2)修改了节点的priority (config.members[0].priority = 3)
3)网络分裂(当前的Primary和多数的节点不通,当前Primary变成Secondary多数节点的组重新选Primary)
4)当前主上执行rs.stepDown()
5)Secondary ping超过heartbeatTimeoutSecs 后不可达,则标记Primary s_down,发生选主
示例:
重新配置节点
var cfg ={"_id":"tuling",
"protocolVersion" : 1,
"members":[
{"_id":1,"host":"127.0.0.1:27017","priority":10},
{"_id":2,"host":"127.0.0.1:27018","priority":0},
{"_id":3,"host":"127.0.0.1:27019","priority":5},
{"_id":4,"host":"127.0.0.1:27020","arbiterOnly":true}
]
}
// 重新装载配置,并重新生成集群节点。
rs.reconfig(cfg)
//重新查看集群状态
rs.status()
节点说明:
PRIMARY 节点: 可以查询和新增数据
SECONDARY 节点:只能查询 不能新增 基于priority 权重可以被选为主节点
RBITER 节点: 不能查询数据 和新增数据 ,不能变成主节点
二、MongoDB 分片操作
知识点:
1.为什么需要分片?
随着数据的增长,单机实例的瓶颈是很明显的。可以通过复制的机制应对压力,但mongodb中单个集群的 节点数量限制到了12个以内,所以需要通过分片进一步横向扩展。此外分片也可节约磁盘的存储。
1.mongodb 中的分片架构
分片中的节点说明:
2.分片示例流程:
配置 并启动config 节点集群
# 节点1 config1-37017.conf
dbpath=/data/mongo/config1
port=37017
fork=true
logpath=logs/config1.log
replSet=configCluster
configsvr=true
# 节点2 config2-37018.conf
dbpath=/data/mongo/config2
port=37018
fork=true
logpath=logs/config2.log
replSet=configCluster
configsvr=true
进入shell 并添加 config 集群配置:
var cfg ={"_id":"configCluster",
"protocolVersion" : 1,
"members":[
{"_id":0,"host":"127.0.0.1:37017"},
{"_id":1,"host":"127.0.0.1:37018"}
]
}
// 重新装载配置,并重新生成集群。
rs.initiate(cfg)
# 配置 shard 节点集群==============
# 节点1 shard1-47017.conf
dbpath=/data/mongo/shard1
port=47017
fork=true
logpath=logs/shard1.log
shardsvr=true
# 节点2 shard2-47018.conf
dbpath=/data/mongo/shard2
port=47018
fork=true
logpath=logs/shard2.log
shardsvr=true
配置 路由节点 mongos ==============
# 节点 route-27017.conf
port=27017
bind_ip=0.0.0.0
fork=true
logpath=logs/route.log
configdb=conf/127.0.0.1:37017,127.0.0.1:37018
// 添加分片节点
sh.status()
sh.addShard("127.0.0.1:47017");
sh.addShard("127.0.0.1:47018");
为数据库开启分片功能
sh.enableSharding("tuling")
为指定集合开启分片功能
sh.shardCollection("tuling.emp",{"_id":1})
修改分片大小
use config
db.settings.find()
db.settings.save({_id:"chunksize",value:1})
尝试插入1万条数据:
for(var i=1;i<=100000;i++){
db.emp.insert({"_id":i,"name":"copy"+i});
}
db.emp.createIndex({_id: 'hashed'})
三、MongoDB用户权限管理
// 创建管理员用户
use admin;
db.createUser({"user":"admin","pwd":"123456","roles":["root"]})
#验证用户信息
db.auth("admin","123456")
#查看用户信息
db.getUsers()
# 修改密码
db.changeUserPassword("admin","123456")
以auth 方式启动mongod,需要添加auth=true 参数 ,mongdb 的权限体系才会起作用:
#以auth 方向启动mongod (也可以在mongo.conf 中添加auth=true 参数)
./bin/mongod -f conf/mongo.conf --auth
# 验证用户
use admin;
db.auth("admin","123456")
创建只读用户
db.createUser({"user":"dev","pwd":"123456","roles":["read"]})
重新登陆 验证用户权限
use demo;
db.auth("dev","123456")