主要意义在于实现服务高可用
作用
数据是如何复制的?
- 当一个修改操作,无论是插入、更新或删除,到达主节点时,对数据的操作将被记录下来(经过一些必要的转换),这些记录称为oplog
- 从节点通过在主节点上打开一个tailable游标不断获取新进入主节点的oplog,并在自己的数据上回放,以此保持跟主节点的数据一致
如何通过选举完成故障恢复?
复制集中最多可以有50个节点,但具有投票权的节点最多7个
影响选举的因素?
常见选项配置?
1主2从,最简单的复制集
备注:复制集需由3个及以上的具有投票权的节点组成
不同的节点功能?
主节点:接收写入操作,选举时投票
从节点:复制主节点上的新数据,选举时投票
投票节点:只负责投票,不存储数据,一般不推荐使用
硬件的话,节点的配置必须一致,保证地位一样,另外一个就是要独立,保证不会同时宕机
软件的话,节点的版本必须一致,避免出现不兼容问题
增加节点不会增加系统写性能,可能降低写性能,这是因为需要同步,但会提高读性能
这个不展开,之前介绍过,可以看入坑篇
为3个复制集节点创建各自的数据目录,分别为data1、data2、data3
复制集的每个mongod进程应该位于不同的服务器,这里我们用一台机器,要弄3个进程,配置不同的端口号即可
systemLog:
destination: file
path: D:\mongodb\data1\mongod.log # 日志文件路径
logAppend: true
storage:
dbPath: D:\mongodb\data1 # 数据目录
net:
bindIp: 0.0.0.0
port: 28017 # 端口
replication:
replSetName: forlan0
说明:
bindIp为什么是0.0.0.0?适用所有网卡,都可以访问该服务
fork表示以后台进程运行,linux可以配置
这里只展示了1台,其它两个主要改端口号和数据、日志路径
mongod -f D:\mongodb\data\db1\mongod.conf
mongod -f D:\mongodb\data\db2\mongod.conf
mongod -f D:\mongodb\data\db3\mongod.conf
因为 Windows 不支持 fork,以上命令需要在3个不同的窗口执行,执行后不可关闭窗口否则进程将直接结束
rs.initiate()
rs.add("centosvm:28018")
rs.add("centosvm:28019")
centosvm是hostname
rs.initiate({_id: "forlan0",members: [{_id: 0,host: "localhost:28017"},{_id: 1,host: "localhost:28018"},{_id: 2,host: "localhost:28019"}]})
主节点写入
db.test.insert({ a:1 })
从节点读取
rs.slaveOk()
db.test.find()
决定一个写操作落到多少个节点上才算成功
Journaling,类似于关系数据库中的redolog,能够使MongoDB数据库由于意外故障后快速恢复,由于提交journal日志会产生写入阻塞,所以它对写入的操作有性能影响,但对于读没有影响
MongoDB2.4版本后默认开启了Journaling日志功能,mongod实例每次启动时都会检查journal日志文件看是否需要恢复
1、测试writeConcern参数
db.test.insert( {count: 1}, {writeConcern: {w: "majority"}})
db.test.insert( {count: 1}, {writeConcern: {w: 3 }})
db.test.insert( {count: 1}, {writeConcern: {w: 4 }})
2、配置延迟节点,模拟网络延迟(复制延迟)
conf=rs.conf()
conf.members[2].secondaryDelaySecs = 5 //老版本可能是conf.members[2].slaveDelay = 5
conf.members[2].priority = 0 // 不具备选举权限
rs.reconfig(conf)
观察复制延迟下的写入:执行插入操作,设置timeout参数,超时报错
db.test.insert( {count: 1}, {writeConcern: {w: 3, wtimeout:3000 }})
解决的是,从哪里读,决定使用哪一个节点来满足正在发起的读请求
指定 readPreference 时也应注意高可用问题,例如将 readPreference 指定 primary,则发生故障转移不存在没有节点可读。如果业务允许,则应选择 primaryPreferred
作用?
因为readPreference 只能控制使用一类节点,而它可以选择控制到一个或几个节点
场景?
一个 5 个节点的复制集:
所以可以使用 Tag 来达到这样的控制目的,在线应用读取时指定{purpose: “online”},报表读取时指定 {purpose: “analyse”}
主节点写入 {x:1}, 观察该条数据在各个节点均可见
db.test.drop()
db.test.insert({x:1})
在两个从节点分别执行 db.fsyncLock() 来锁定写入(同步)
db.fsyncLock()
主节点写入 {x:2}
db.test.insert({x:2})
主节点上看到有2条数据
从节点上看到只有1条数据
解除从节点锁定 db.fsyncUnlock()
在从节点上看,可以看到同步的数据了
db.test.find().readPref("secondary")
解决的是,什么数据可以读
决定这个节点上的数据哪些是可读的,类似于关系数据库的隔离级别
有事务要求,使用snapshot,否则使用majority
只读取大多数据节点上都提交了的数据
如何实现?
节点上维护多个 x 版本,MVCC 机制,通过维护多个快照来链接不同的版本
实战:
1、安装 3 节点复制集(一主两从)
2、配置文件内 server 参数 enableMajorityReadConcern
3、将复制集中的两个从节点使用 db.fsyncLock() 锁住写入(模拟同步延迟)
db.test.save({"x":1})
db.test.find().readConcern("local")
db.test.find().readConcern("majority")
解锁后就正常了
结论:
写操作在没到达大多数节点前,主节点挂了,写操作就丢失了,操作回滚,可以理解为事务,只不过是大多数节点成功才提交,所以可以避免脏读
只在多文档事务中生效,类似隔离级别,不可重复读
测试:
1、准备数据
db.tx.insertMany([{ x: 1 }, { x: 2 }]);
2、事务操作
var session = db.getMongo().startSession();
session.startTransaction();
var coll = session.getDatabase('test').getCollection("tx");
coll.updateOne({x: 1}, {$set: {y: 1}});
coll.findOne({x: 1});
db.tx.findOne({x: 1});
session.abortTransaction();
事务内操作db.tx.findOne({x: 1}),得到值 {x:1, y:1}
事务外操作db.tx.findOne({x: 1}),得到值 {x:1}
3、可重复读Repeatable Read,事务操作
var session = db.getMongo().startSession();
session.startTransaction({readConcern: {level: "snapshot"},writeConcern: {w: "majority"}});
var coll = session.getDatabase('test').getCollection("tx");
coll.findOne({x: 1});
db.tx.updateOne({x: 1}, {$set: {y: 1}});
db.tx.findOne({x: 1});
coll.findOne({x: 1});
session.abortTransaction();
注意事项