MongoDB 复制

1.主从复制

主从复制是MongoDB最常用的复制方式,这种方式很灵活.可用于备份,故障恢复,读扩展等.

最基本的设置方式就是建立一个主节点和一个或多个从节点,每个从节点要知道主节点的地址.

运行mongod --master就启动了主服务器,运行mongod --slave --source master_address

就启动了从服务器.其中master_address是主节点的地址.

生产环境下会有多台服务器的,这里用一台机器来测试.

首先给主节点建立数据目录:

mongod --dbpath "F:\mongo\dbs\master" --port 10000 --master

--logpath "F:\mongo\logs\master\MongoDB.txt" --rest

设置从节点:

mongod --dbpath "F:\mongo\dbs\slave" --port 10001 --slave --source 127.0.0.1:10000 --logpath "F:\mongo\logs\slave\MongoDB.txt" --rest

现在向主节点服务器添加数据:

在从节点服务器查询数据:

所有的从节点都从主节点复制内容.

一个集群中有多少个从节点并没有明确的限制.最好是不超过12个从节点数据库的集群.

 

2.主从复制的选项

--only

在从节点上指定只复制特定的某个数据库(默认是复制所有数据库)

--slavedelay

用在从节点上,当应用主节点的操作时,从节点增加延时复制(单位秒).这样就能轻松设置延时从节点,这种节点对用户

无意中删除重要文档或者插入垃圾数据等有防护作用,这些不良操作都会被复制到所有的从节点上,通过延时执行操作,

可以有个恢复的时间差.

--fastsync

以主节点的数据快照为基础启动从节点.如果数据目录一开始是主节点的数据快照,从节点用这个选项启动要比

做完整的同步快的多.

--autoresync

如果从节点与主节点不同步了,则自动重新同步

--oplogsize

主节点oplog的大小(单位MB)

 

3.添加及删除源

启动从节点时可以用--source指定主节点,也可以在shell中配置这个源.

如上例主节点绑定了127.0.0.1:10000.启动从节点时可以不添加源,而后向source集合添加主节点信息:

mongod --dbpath "F:\mongo\dbs\slave" --port 10001 --slave --logpath "F:\mongo\logs\slave\MongoDB.txt" --rest

可以在shell中,将127.0.0.1:10000作为源添加到从节点上:

use local

db.sources.insert({"host":"127.0.0.1:10000"})

看看从属节点的日志,会发现它与127.0.0.1:10000同步.

如果在生产环境下,想更改从节点的配置,改用refactor.com为源,这可以这样做:

db.sources.insert({"host":"refactor.com"})
db.sources.remove({"host":"127.0.0.1:10000"})

可以把sources集合当作普通的集合进行操作.

要是切换的两个主节点有相同的集合,MongoDB或尝试合并,但不能保证正确合并.要是使用一个从节点对应

多个不同的主节点,最好在主节点上使用不同的命名空间

 

4.副本集

副本集(Replica Set)就是有自动故障恢复功能的主从集群.主从集群和副本集最明显的区别是副本集没有固定的"主节点",

整个集群会选举出一个"主节点",当其不能工作时则变更到其他节点.副本集总会有一个活跃节点(primary)和

一个或多个备份节点(secondary).

副本集可以在活跃节点有问题时自动切换.

 

5.初始化副本集

设置副本集比设置主从集群稍微复杂一点.

先给副本集起个名称,是为了易于与别的副本集区分,也是为了方便将整个集合视为一个整体,这里取名:refactor

启动服务器--replSet的作用是让服务器知道这个"refactor"副本集还有别的同伴 位置在 refactor/127.0.0.1:10001

mongod --dbpath "F:\mongo\dbs\master" --port 10000 --replSet refactor/127.0.0.1:10001 --logpath "F:\mongo\logs\master\MongoDB.txt" --rest

以同样的方式启动另一台:

mongod --dbpath "F:\mongo\dbs\slave" --port 10001 --replSet refactor/127.0.0.1:10000 --logpath "F:\mongo\logs\slave\MongoDB.txt" --rest

如果想要添加第三台,两种方式:

mongod --dbpath "F:\mongo\dbs\slave1" --port 10002
--replSet refactor/127.0.0.1:10000
--logpath "F:\mongo\logs\slave1\MongoDB.txt" --rest

mongod --dbpath "F:\mongo\dbs\slave1" --port 10002
--replSet refactor/127.0.0.1:10000,127.0.0.1:10001
--logpath "F:\mongo\logs\slave1\MongoDB.txt" --rest

副本集有自动检测功能:在其中指定单台服务器后,MongoDB就会自动搜索并连接其余的节点.

 

在shell中初始化副本集

 

在shell,连接其中一个服务器,初始化命令只能执行一次:

use admin
db.runCommand(
  {
    "replSetInitiate":
    {
      "_id":"refactor",//副本集的名称
      "members"://副本集中的服务器列表
      [
        {
          "_id":1,//每个服务器的唯一id
          "host":"127.0.0.1:10000"//指定服务器的主机
        },
        {
          "_id":2,
          "host":"127.0.0.1:10001"
        }
      ]
    }
  }
)

在活跃节点中添加数据:

在备份节点查询,会出现

error: { "$err" : "not master and slaveok=false", "code" : 13435 }错误.

执行如下语句:

db.getMongo().setSlaveOk()

 

6.副本集中的节点

任何时间,集群中只有一个活跃节点,其他的都是备份节点.活跃节点实际上是活跃服务器,指定的活跃节点可以随时间而改变.

有几种不同类型的节点可以存在与副本集中

standard 标准节点

这是常规节点,它存储一份完整的数据副本,参与选举投票有可能成为活跃节点

passive 被动结点

存储了完整的数据副本,参与投票,不能成为活跃节点

arbiter 仲裁者

仲裁者只能参与投票,不接收复制的数据,也不能成为活跃节点.

标准节点和被动节点之间的区别仅仅是数量的差别,每个参与节点(非仲裁)有优先权.

优先权按照优先值从大到小.

在节点配置中修改priority键,来配置标准节点或者被动节点.

>members.push({"_id":3,"host":"127.0.0.1:10002","priority":40})

默认优先级为1,可以是0-1000(含)

"arbiterOnly"键可以指定仲裁节点

>members.push({"_id":4,"host":"127.0.0.1:10003","arbiterOnly":true})

备份节点会从活跃节点抽取oplog,并执行操作,就像活跃备份系统中的备份服务器一样.活跃节点也会写操作

到自己的本地oplog.oplog中的操作包含严格递增的序号,这个序号来判定数据的时效性.

 

7.故障切换和活跃节点选举

如果活跃节点出现故障,其余节点会选一个新的活跃节点.选举过程可以由任何非活跃节点发起,新的活跃节点由

副本集中的大多数选举产生.仲裁节点也参与选举,避免出现僵局.新的活跃节点将是优先级最高的节点,优先级相同

这数据较新的节点获胜.

不论活跃节点何时变化,新的活跃节点的数据就被假定为系统的最新数据.对其他几点(原来的活跃节点)的操作都会

回滚,即便是之前的活跃节点已经恢复工作了.为了完成回滚,所有节点连接新的活跃节点后重新同步.这些节点会查看

自己的oplog,找出自重活跃节点没有的操作,然后向活跃节点请求这些操作影响的文档最新副本.正在执行重新同步的

节点被视为恢复中,在完成这个过程之前不能成为活跃节点的候选者.

 

8.在从服务器上执行操作

从节点的主要作用是作为故障恢复机制,以防主节点数据丢失或停止服务.

从节点可以用作备份数据源,可以用来扩展读取性能,或者进行数据处理.

 

9.读扩展

用MongoDB扩展读取的一种方式是将查询放在从节点上.这样,主节点的负载就减轻了.一般来说,当负载是读取密集型

时,这是很好的方案.要是谢密集型,则要用分片来进行扩展.

使用从节点来扩展MongoDB的读取有个要点,就是数据复制并不同步,也就是说在主节点插入和更新数据后,

有片刻从节点的数据不是最新的.在考虑用查询从节点完成请求时,应注意.

扩展读取本身很简单,像往常一样设置主从复制,连接从服务器处理请求.唯一的技巧是有个特殊的查询选项,告诉

从服务器是否可以处理请求(默认是不可以的).这个选项是slaveOkay,所有的MongoDB驱动程序都提供了

一种机制来设置它.有些驱动程序还提供工具使得请求分布到从节点的过程自动化,但这个过程随驱动程序的

不同而不同.

 

10.用从节点做数据处理

从节点的另外一个用途是作为一种机制来减轻密集型处理的负载,或作为聚合,避免影响主节点的性能.用--mster

参数启动一个普通的从节点.同时使用--slave和--master有点矛盾,这意味着如果能对从节点进行写入,像往常

一样查询,就把它作为一个普通的MongoDB主节点就行了,向从节点插入数据不会同步到主节点中.

从节点还是会不断的从真正的主节点复制数据.

这样,就可以对从节点执行阻塞操作也不影响主节点的性能.

用这种技术的时候,一定要确保不能对正在复制主节点数据的从节点上的数据库进行写入.从节点不能恢复这些操作,

就不能映射主节点.

 

11.工作原理

MongoDB的复制至少需要两个服务器或节点.其中一个是主节点,负责处理客户端请求,其他都是从节点

负责映射主节点的数据.主节点记录在其上执行的所有操作.从节点定期轮训主节点获得这些操作,然后对自己的

数据副本执行这些操作.由于和主节点执行了相同的操作,从节点就能保持与主节点的数据同步.

 

oplog

主节点的操作记录成为oplog(operation log).oplog存储在一个特殊的数据库中,叫做local.

oplog就在其中的oplpg.$main集合里面.oplpg中的每个文档都代表主节点上执行的一个操作.

> db.oplog.$main.findOne()
{
  "ts" : {
      "t" : 1342705298000,
      "i" : 11
     },
  "op" : "n",
  "ns" : "",
  "o" : {

      }
}

"ts" 

操作的时间戳.时间戳是一种内部类型,用于跟踪操作执行的时间,由4个字节的时间戳和4个自己的递增计数器构成

"op"

操作类型,只有一个字节.("i"代表插入)

"ns" 

执行操作的命名空间(集合名)

"o"

进一步执行要执行操作的文档,对插入来说,就是要插入的文档.

oplog只记录改变数据库状态的操作.如查询不会存储在oplog中,这是因为oplog只是作为从节点与

主节点保持数据同步的机制.

存储在oplog中的操作也不是完全和主节点的操作已于一样的.这些操作在存储之前先要做等幂变换,也就是说

这些操作可以在服务器端多次执行,只要顺序是对的,就不会有问题.如使用"$inc"执行的增加更新操作,

会变成"$set"操作.

oplog存储在固定集合中.由于新操作也会存储在oplog中,他们会自动替换旧的操作.这样能保证oplog不能

超过预先设定的大小.启动服务器时可以用--oplogsize指定这个大小,单位是MB.默认情况下,64位的实例将会使用

oplog 5%的可用空间.这个空间将在local数据库中分配,并在服务器启动时预先分配.

 

12.同步

从节点第一次启动时,会对主节点数据进行完整的同步.从节点复制主节点上的每个文档,很耗资源.同步完成后,

从节点开始查询主节点的oplog并执行这些操作,以保证数据是最新的.

如果从节点的操作和主节点的相差很远,从节点就跟不上同步了.跟不上同步的从节点无法一直追赶主节点.因为

主节点oplog的所有操作太新了.从节点发生了宕机或着疲于应付读取时会出现这个情况,也会在执行完完整同步以后

反生类似的事,因为只要同步的时间太长,同步完成时,oplog可能已经操作了很多.

从节点跟不上同步时,复制就会停下来,从节点需要重新做完整的同步.可以用{"resync":1}命令手动执行从新同步,

也可以在启动从节点时使用--autoresync选项让其自动重新同步,重新同步的代价很高,应尽量避免,方法是配置

足够大的oplog,配置足够大的oplog能存放相当长的时间操作记录.大的oplog会占用更多的磁盘空间,则需要权衡一下.

默认的oplog大小是剩余磁盘空间的5%.

 

13.复制状态和本地数据库

本地数据库 用来存储所有内部复制状态,子节点和从节点都有.本地数据库 的名字是local,其内容不会被复制.这样能

确保一个MongoDB服务器只有一个local数据库.local数据库不限于存放MongoDB的内部状态,如果有不想被复制的文档

也可以将其存在local数据库.

主节点上的复制状态还包括从节点的列表(从节点连接主节点时会自行handshake命令进行握手),这个列表存放在

slaves集合中.

从节点也在local数据库中存放状态.在me集合中存放从节点的唯一标识符,在sources集合中存放源或节点的列表.

主节点和从节点都跟中从节点的更新情况,这是通过存放在"syncedTo"中的时间戳来完成的.每次从节点查询主节点

的oplog时,都会用"syncedTo"来确定那些操作需要执行,或者查看是否已经跟不上同步了.

 

14.阻塞复制

开发者可以用gerLastError的"w"参数来确保数据的同步性.这里运行gerLastError会进入阻塞状态,知道n个

服务器复制了嘴型的写入操作为止

db.runCommand({"gerLastError":1,w:N})

如果没有N,或者小于2命令就会立刻返回,如果N等于2,主节点要等到至少一个从节点复制了上个操作才会响应命令

主节点本身也包括在N里面.主节点使用local.slaves中存放的"syncedTo"信息跟踪从节点的更新情况.

指定"w"选项后,还可以使用"wtimeout"选项,表示以毫秒为单位的超时,gerLastError就能在上一个操作复制到N个

节点超时返回错误(默认情况下没有超时)

阻塞复制会导致写操作变慢,尤其"w"的值比较大时.实际上,对重要操作将其值设为2或3就能效率和安全兼备了.

 

15.管理

MongoDB提供了工具来查看复制的状态,当连接到主节点后,使用

> db.printReplicationInfo()
configured oplog size: 944.1375732421875MB//oplog的大小大致为944M
log length start to end: 3395secs (0.94hrs)//最大大约能放置3395秒的操作.
oplog first event time: Thu Jul 19 2012 21:41:58 GMT+0800
oplog last event time: Thu Jul 19 2012 22:38:33 GMT+0800
now: Thu Jul 19 2012 22:38:38 GMT+0800


oplog的长度至少要能满足一次完整的从新同步.

当连接到从节点时,可以用printSlaveReplicationInfo得到从节点的一些信息

> db.printSlaveReplicationInfo()
source: 127.0.0.1:10000
syncedTo: Thu Jul 19 2012 22:42:13 GMT+0800
= 7 secs ago (0hrs)//数据的滞后时间为7秒

 

如发现oplog的大小不合适,最简单的做法就是停掉主节点,删除local数据库中的文件,用新的设置(--oplogsize)

重新启动.为大型的oplog预分配空间很耗时,且可能导致主节点停机时间增加,所以尽可能手动预分配数据文件.

重启主节点后,所有从节点得用--autoresync重启,否则需要手动从新同步.

 

16.复制的认证问题

如果在复制中使用了认证,还要做一些配置,似的从节点能访问主节点的数据.在主节点和从节点上都需要在

local数据库添加用户,每个节点的用户名和口令都是相同的.local数据库的用户类似admin数据库中的用户,

能够读写整个服务器.

从节点连接主节点时,会用存储在local.system.users中的用户进行认证.最此尝试"refactor"用户,如没有此用户,则用

local.system.users中的第一个可用用户.所以,按照如下步骤配置主节点和从节点,用户靠的密码替换password,

就能配置认证复制了:

use local

addUser("refactor","password")

从节点之后就可以复制主节点了.

 

 

posted on 2012-08-13 10:08 refactor 阅读(...) 评论(...) 编辑 收藏

导航

统计