1.主从复制
主从复制是MongoDB最常用的复制方式。这种复制方式非常灵活,可用于备份、故障恢复、读扩展等。
通过启动时的选项进行设置,每个从节点要知道主节点的地址,所有从节点都从主节点复制内容,目前还没有能够从从节点复制的机制,原因是从节点并不保存自己的oplog。
相关的启动选项
--master 设置当前服务为主节点 --slave 设置当前服务为从节点 --source 指定主节点的地址 --only 在从节点上指定只复制特定某个数据库(默认复制除local之外的所有数据库) --slavedelay 设置从节点复制主节点时的延时 --fastsync 以主节点的数据快照为基础启动从节点 --autoresync 如果从节点和主节点不同步了,则自动重新同步 --oplogsize 主节点oplog的大小
e.g.
//启动主节点 mongod --dbpath D:\mongoDB\master --logpath D:\mongoDB\master-log\log.log --master --port 10000 //启动从节点 mongod --dbpath D:\mongoDB\slave --logpath D:\mongoDB\slave-log\log.log --slave --source localhost:10000 --port 10001 /* 测试 */ //连接主节点 mongo --host localhost --port 10000 use test; db.user.insert({"id": "001", "name": "路人甲0"}); //连接从节点 mongo --host localhost --port 10001 use test; db.user.find();
1)添加或删除源
启动从节点时可以用source选项指定主节点,也可以再shell中配置。
主从节点关系相关集合
--主节点:local库slaves
--从节点:local库sources
删除源:需要同时删除主节点和从节点相关集合中的记录
添加源:从节点中相关集合新增记录即可,主节点会自动添加记录,e.g.
use local; db.sources.insert({"host": "localhost:10000"});
也可以实现主节点的切换或者一个从节点对应多个不同的主节点。
注:如果不同的主节点有相同的集合,MongoDB会尝试合并,但是不保证正确合并。
2)工作原理
--MongoDB的复制至少需要两个节点。一个是主节点,其它的为从节点。
--主节点负责处理客户端请求,记录在其上执行的所有操作
--从节点负责映射主节点的数据,通过轮询主节点的oplog,然后对自己的数据副本执行这些操作实现
3)oplog
主节点的操作记录,operation log,简称oplog,存储在local库oplog.$main集合中。e.g.
{ "ts" : Timestamp(1395202153, 1), "op" : "i", "ns" : "test.user", "o" : { "_id" : ObjectId("5329186953152d9334a80347"), "id" : "001", "name" : "路人甲0" } } ts:操作的时间戳 op:操作类型 ns:操作的命名空间 o:执行操作的文档
--oplog只记录改变数据库状态的操作
--oplog在存储前需要做等幂变换,即这些操作可以在服务器端多次执行,只要顺序是对的,就不会有问题
--oplog存储在固定集合中,默认大小为剩余磁盘空间的5%
4)同步
从节点第一次启动时,会对主节点数据进行完整的同步。同步完成后,从节点开始查询主节点的oplog并执行这些操作,以保证数据时最新的。
当从节点跟不上同步时(oplog已经滚了一圈了),复制就会停下,从节点需要重新做完整的同步。
--手动同步
use admin; db.runCommand({"resync": 1});
--自动同步:使用autoresync选项启动从节点
注:完整同步代价高昂,应该调整oplog的大小尽量避免。
5)阻塞复制
使主节点进入阻塞状态,直到N个服务器复制了最新的写入操作为止。
db.runCommand({"getLastError": 1, "w": ..., "wtimeout": ...}); w:节点个数,包含主节点本身 wtimeout:以毫秒为单位的超时 e.g. db.runCommand({"getLastError": 1, "w": 1, "wtimeout": 100});
6)查看复制信息
主节点:db.printReplicationInfo();
从节点:db.printSlaveReplicationInfo();
7)权限校验
当主从节点均以auth选项启动时,需要在主节点和从节点的local库中添加相同用户,才能使从节点能够访问主节点的数据。local中的用户可以读写整个服务器。
从节点连接主节点时,会用存储在local.system.users中的用户进行认证。最先尝试repl用户,若没有此用户,则用local.system.users中的第一个可用用户。e.g.
db.addUser("repl", "repl");
2.副本集
副本集就是有自动故障恢复功能的主从集群。
主从集群和副本集的最大区别是副本集没有固定的主节点:整个集群会选举出一个"主节点",当其不能工作时则变更到其它节点。
1)配置
//启动 mongod --dbpath D:\mongoDB\node1 --logpath D:\mongoDB\node1-log\log.log --replSet test --port 10001 mongod --dbpath D:\mongoDB\node2 --logpath D:\mongoDB\node2-log\log.log --replSet test --port 20002 mongod --dbpath D:\mongoDB\node3 --logpath D:\mongoDB\node3-log\log.log --replSet test --port 30003 //配置 --方法一 db.runCommand({"replSetInitiate": { "_id": "test", "members": [ { "_id": 1, "host": "localhost:10001" }, { "_id": 2, "host": "localhost:20002" }, { "_id": 3, "host": "localhost:30003" } ]} }); --方法二 rs.initiate({ "_id": "test", "members": [ { "_id": 1, "host": "localhost:10001" }, { "_id": 2, "host": "localhost:20002" }, { "_id": 3, "host": "localhost:30003" } ]}); //查看状态,配置信息存储在local库的system.replset集合中 rs.status();2)操作
--在PRIMARY上插入数据,在SECONDARY进行查询时出错
error: { "$err" : "not master and slaveOk=false", "code" : 13435 }解决方法:在SECONDARY上执行下列语句
rs.slaveOk();