您现在的位置是:网站首页> 编程资料编程资料

MongoDB的主从复制及副本集的replSet配置教程_MongoDB_

2023-05-27 557人已围观

简介 MongoDB的主从复制及副本集的replSet配置教程_MongoDB_

复制
MongoDB的复制功能很重要,尤其是现在的存储引擎还不支持单击持久性。不仅可以用复制来应对故障切换,数据集成,还可以做读扩展,热备份或作为离线批处理的数据源。

1.主从复制
主从复制是MongoDB最常用的复制方式。可用于备份,故障恢复和读扩展等。
基本就是搭建一个主节点和一个或多个从节点,每个从节点需要知道主节点的地址。运行mongod --master启动主服务器。运行mongod --slave --source master_address启动从服务器。
[root@test02 ~]# mongod --fork --dbpath /data/node2 --logpath /data/mongodb.log --port 10001 --logappend --master
从节点选择不同的目录和端口,并且用--source为从节点指明主节点的地址。
[root@test02 ~]# mongod --fork --dbpath /data/node3 --logpath /data/mongodb2.log --port 10002 --logappend --slave --source localhost:10001
所有的从节点都是从主节点复制信息,目前还不能从节点到从节点复制机制,原因是从节点没有自己的oplog。
一个集群中从节点没有明确的限制,但是多个节点对单点主机发起的查询也是吃不消的,不超过12个节点的集群可以良好运转。

1.1 选项
(1)--only
在从节点上指定只复制特定某个数据库(默认复制所有数据库)。
(2)--slavedelay
用在从节点上,当应用主节点的操作时增加延迟。这样可以轻松设置延时从节点了,这样的节点对于用户无意间删除重要数据或插入垃圾数据起到防护作用。通过延缓操作,可以有个恢复时间差。
(3)--fastsync
以主节点的数据快照为基础启动从节点。如果数据目录一开始时主节点的数据快照,从节点用这个选项启动要比做完整同步块很多。
(4)--autoresync
如果主节点和从节点不同步,可以自动同步了。
(5)--oplogsuze
主节点oplog的大小(单位是MB)。

1.2 添加以及删除源

 cat >> /etc/hosts <

启动从节点时可以用--source指定主节点,也可以在shell中配置这个源。
[root@test02 ~]# mongod --fork --dbpath /data/node3 --logpath /data/mongodb.log --port 10003 --logappend --slave
将192.168.27.212:10001作为源插入到从节点上。

 > db.sources.insert({ "host" : "192.168.27.212:10001"}); 

立即查询会得到插入的文档:

 > use local switched to db local > db.sources.find(); { "_id" : ObjectId("530be5049ab1ad709cfe66b7"), "host" : "test02:10001" 

当同步完成后,文档更新:

 > db.sources.find(); { "_id" : ObjectId("530bf0ab058022d91574c79c"), "host" : "test02:10001", "source" : "main", "syncedTo" : Timestamp(1393291443, 1), "dbsNextPass" : { "foo" : true, "test" : true } } 

2.副本集
副本集就是有自动故障恢复功能的主从集群。主从集群和副本集最为明显的区别就是副本集没有固定的主节点:整个集群会选举出一个主节点,当其不能工作时,则变更到其它节点。副本集总会有一个活跃节点和一个或多个备份节点。
副本集最好的优点就是全自动化的。

 mongod --fork --dbpath /data/node2 --logpath /data/mongodb.log --port 10001 --logappend --replSet myrepl/test03:10002 mongod --fork --dbpath /data/node3 --logpath /data/mongodb.log --port 10002 --logappend --replSet myrepl/test02:10001 

副本集的亮点是自检测功能:在其中指定单台服务器后,MongoDB会自动搜索并连接其余的节点。
启动几台服务器后,日志会告诉你副本集没有初始化。需要在shell中初始化副本集。
连接任意一个服务器。初始化命令只执行一次:

 > db.runCommand({"replSetInitiate" : { ... "_id" : "myrepl", ... "members" : [ ... { ... "_id" : 1, ... "host" : "test02:10001" ... }, ... { ... "_id" : 2, ... "host" : "test03:10002" ... } ... ]}}) { "startupStatus" : 4, "info" : "myrepl/test03:10002", "ok" : 0, "errmsg" : "all members and seeds must be reachable to initiate set" } 

(1)"_id" : "myrepl"     副本集的名称
(2)"members" : [...]    副本集中的服务器列表,每个服务器至少两个键。
(3)"_id" : N            每个服务器唯一的ID
(4)"host" : hostname    这个键指定服务器主机
或者:

 config = {"_id" : "myrepl", "members" : [ {"_id" : 0, "host" : "test02:10001"}, {"_id" : 1, "host" : "test03:10002"} ]} rs.initiate(config); rs.status(); myrepl:SECONDARY> rs.status(); { "set" : "myrepl", "date" : ISODate("2014-02-25T02:17:39Z"), "myState" : 2, "syncingTo" : "test03:10002", "members" : [ { "_id" : 0, "name" : "test02:10001", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 968, "optime" : Timestamp(1393294457, 1), "optimeDate" : ISODate("2014-02-25T02:14:17Z"), "errmsg" : "syncing to: test03:10002", "self" : true }, { "_id" : 1, "name" : "test03:10002", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 48, "optime" : Timestamp(1393294457, 1), "optimeDate" : ISODate("2014-02-25T02:14:17Z"), "lastHeartbeat" : ISODate("2014-02-25T02:17:38Z"), "lastHeartbeatRecv" : ISODate("2014-02-25T02:17:39Z"), "pingMs" : 1, "syncingTo" : "test02:10001" } ], "ok" : 1 } 

如果这时候把primary节点停掉,在secondary节点执行写操作,就会发生如下错误提示:

 myrepl:SECONDARY> db.test.insert({name : "baobao"}); 
 not master 

如果只有2台Mongodb,配置复制集群还不够安全,需要1个外在角色调整各个节点的角色。
(1)standard:常规节点,存储一份完整的数据副本,参与选举投票,可能称为活跃节点。
(2)passive:存储完整的数据副本,参与投票,不能成为活跃节点。
(3)arbiter:仲裁者只负责投票,不接受复制数据,也不能成为活跃节点。
当Primary宕掉后,可以通过Arbiter在Secodarys中选举一个Primary节点,避免单点故障。
可以增加一个仲裁节点,只负责仲裁,不做数据存储。

 mongod --fork --dbpath /data/node1 --logpath /data/mongodb.log --port 10003 --logappend --replSet myrepl/test02:10001,test03:10002 myrepl:PRIMARY> rs.addArb("test01:10003"); { "ok" : 1 } 

查看各节点的状态:

 myrepl:PRIMARY> rs.status(); { "set" : "myrepl", "date" : ISODate("2014-02-25T02:30:26Z"), "myState" : 1, "members" : [ { "_id" : 0, "name" : "test02:10001", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 1735, "optime" : Timestamp(1393295409, 1), "optimeDate" : ISODate("2014-02-25T02:30:09Z"), "self" : true }, { "_id" : 1, "name" : "test03:10002", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 204, "optime" : Timestamp(1393295409, 1), "optimeDate" : ISODate("2014-02-25T02:30:09Z"), "lastHeartbeat" : ISODate("2014-02-25T02:30:26Z"), "lastHeartbeatRecv" : ISODate("2014-02-25T02:30:24Z"), "pingMs" : 1, "syncingTo" : "test02:10001" }, { "_id" : 2, "name" : "test01:10003", "health" : 1, "state" : 6, "stateStr" : "UNKNOWN", "uptime" : 17, "lastHeartbeat" : ISODate("2014-02-25T02:30:25Z"), "lastHeartbeatRecv" : ISODate("1970-01-01T00:00:00Z"), "pingMs" : 1, "lastHeartbeatMessage" : "still initializing" } ], "ok" : 1 } 

对比三个节点对自身节点性质的判断:

 myrepl:PRIMARY> db.isMaster(); { "setName" : "myrepl", "ismaster" : true, "secondary" : false, "hosts" : [ "test03:10002", "test02:10001" ], "arbiters" : [ "test01:10003" ], "primary" : "test03:10002", "me" : "test03:10002", "maxBsonObjectSize" : 16777216, "maxMessageSizeBytes" : 48000000, "localTime" : ISODate("2014-02-25T02:32:29.760Z"), "ok" : 1 } myrepl:SECONDARY> db.isMaster(); { "setName" : "myrepl", "ismaster" : false, "secondary" : true, "hosts" : [ "test02:10001", "test03:10002" ], "arbiters" : [ "test01:10003" ], "primary" : "test03:10002", "me" : "test02:10001", "maxBsonObjectSize" : 16777216, "maxMessageSizeBytes" : 48000000, "localTime" : ISODate("2014-02-25T02:33:50.144Z"), "ok" : 1 } myrepl:SECONDARY> db.isMaster(); { "setName" : "myrepl", "ismaster" : false, "secondary" : true, "hosts" : [ "test02:10001", "test03:10002" ], "arbiters" : [ "test01:10003" ], "primary" : "test03:10002", "me" : "test02:10001", "maxBsonObjectSize" : 16777216, "maxMessageSizeBytes" : 48000000, "localTime" : ISODate("2014-02-25T02:33:50.144Z"), "ok" : 1 } 

在节点配置中修改priority键,来配置成标准节点或者被动节点。
默认优先级为1,可以是0~1000.
"arbiterOnly"键可以指定仲裁节点。
备份节点会从活跃节点抽取oplog,并执行操作,就像活跃备份系统中的备份服务器一样。活跃节点也会写操作到自己的本地oplog,这样就能成为活跃节点了。oplog中的操作也包括严格递增的序号。通过序号判断数据的时效性。
2.1 故障切换和活跃节点的选举
如果活跃节点坏了,其他节点会选一个新的活跃节点。新的活跃节点由副本集中的大多数选举出来。仲裁节点只负责投票,避免出现僵局。新的节点是优先级最高的节点。
活跃节点使用心跳来跟踪集群中多少节点对其可见,如果不超过半数,则活跃节点自动降为备份节点。可以防止活跃节点一直不放权。
无论活跃节点何时变化,新活跃节点的数据被假定为系统的最新数据。其他节点的操作都会回滚,所有节点连接新的活跃节点后要重新同步。这些节点会查看自己的oplog,找出其中活跃节点没有执行过的操作,然后向活跃节点请求这些操作影响的文档的最新副本。
正在执行重新同步的节点被视为恢复中,在完成这个过程前,不能成为活跃节点候选者。
2.2 关于副本集replSet的配置我们文后会附带详细地讲。

3.在从服务器上执行操作
从节点的主要作用是作为故障恢复机制,以防止主节点数据丢失或者停止服务。
可以在从节点做备份的数据源。也可以用来扩展读取性能,或者进行数据处理。
3.1 读扩展
用MongoDB扩展读取的一种方式就是将查询放在从节点上,减轻主节点的负载。当负载是读密集型时这样非常不错。当是写密集型时,需要用自动分片来扩展。
使用从节点来扩展MongoDB的读取有个要点,就是数据复制并不同步,就是在主节点插入或更新数据口,有片刻从节点的数据不是最新的。
扩展读取需要打开一个特殊选项slaveOkey,告诉从服务器是否可以处理请求。
如果直接在secondary上操作,会发生如下错误:

 myrepl:SECONDARY> db.test.find(); error: { "$err" : "not master and slaveOk=false", "code" : 13435 } 

需要告知Mongodb集群,从哪台机器上进行读操作:

 myrepl:SECONDARY> rs.slaveOk(); myrepl:SECONDARY> db.test.find(); { "_id" : ObjectId("530bfc79eee2c2ce39f9cd95"), "name" : "caoqing" } { "_id" : ObjectId("530bfd8f3627cb16c15dcb32"), "name" : "xiaobao" } 

3.2 用从节点做数据处理
从节点的另外一个服务就是作为一种机制来减轻密集型处理的负载,或作为聚合,避免影响主节点的性能。用--master启动一个普通的从节点,同时使用--master和--slave矛盾。这意味着如果能对从节点进行写入,像平常一样查询,就把它作为一个主节点。从节点还是会不断的从主节点复制数据。这样就可以对从节点执行阻塞操作而不影响主节点的性能。
从节点第一次启动时不能有正在复制的数据库,如果有,数据库就不能完成同步,只能更新。
用这种技术要保证不能对正在复制主节点数据的从节点上的数据库执行写入。从节点不能恢复这些操作,就不能正确的映射主节点。

4.工作原理
MongoDB的复制至少需要两台服务器或者节点,其中一个主节点,负责处理客户端请求,其他的都是从节点,负责映射主节点的数据。主节点记录在其上的所有操作。
从节点定期轮询主节点获取这些操作,然后对数据副本执行这些操作。由于和主节点执行了相同的操作,从节点就能保持和主节点的数据同步。
4.1 oplog
主节点的操作记录成为polog(operation log)。oplog存储在一个特殊的数据库里,成为local。oplog就在其中的oplog.$main集合里面。oplog的每个文档都代表主节点执行的一个操作。

 myrepl:PRIMARY> db.oplog.$main.help(); 

查看oplog的内容:

 myrepl:PRIMARY> use local; switched to db local myrepl:PRIMARY> show collections; me oplog.rs replset.minvalid slaves startup_log system.indexes system.replset myrepl:PRIMARY> db.oplog.rs.find(); { "ts" : Timestamp(1393294283, 1), "h" : NumberLong(0), "v" : 2, "op" : "n", "ns" : "", "o" : { "msg" : "initiating set" } } { "ts" : Timestamp(1393294457, 1), "h" : NumberLong("-8949844291534979055"), "v" : 2, "op" : "i", "ns" : "test.test", "o" : { "_id" : ObjectId("530bfc79eee2c2ce39f9cd95"), "name" : "caoqing" } } { "ts" : Timestamp(1393294735, 1), "h" : NumberL
                
                

-六神源码网