三、主从复制
重要:大多数情况下,副本集代替了主从(master-slave)复制。在产品实施时,尽可能使用副本集而不是主从复制。本文档主要目的是支持遗留的部署、归档。
副本集不仅具有主从架构所有功能,还能提供产品的健壮性。主从复制可以的拥有更大数量的non-master节点,也能限定对单个数据库的复制操作;然而,主从复制,提供了更少的信息冗余,没有自动故障转移。
1.基本操作
a.初始化部署
先启动2个mongod实例,一个用master模式,一个用slave模式。
master启动指令为:
mongod --master --dbpath /data/masterdb/
使用- -master选项,mongod将会创建一个local.oplog.$mani集合,即“operation log”顺序记录数据操作,以便slave复制应用。- -dbpath是可选项。
slave启动指令为:
mongod --slave --source <masterhostname><:<port>> --dbpath /data/slavedb/
指定master实例的hostname和port到- -source参数中。- -dbpath是可选项。对于slave实例,mongodb存储master的信息于local.sources集合中。
b.在线更改- -source参数
你可以在local.sources集合中添加一个文档来指定master实例,步骤如下:
use local
db.sources.find()
db.sources.insert( { host: <masterhostname> <,only: databasename> } );
即切换到local数据库,然后判断source集合中是否有数据,最后插入一个带有master信息的文档到集合中。
2.主从复制的注意事项
Master实例用oplog来存储操作信息,这导致了,如果一个slave落后与Master太远,那么slave就不能追上Master,这时,必须从头开始进行同步。以下情况发生时,slave将脱离对master的同步:
· slave落后与master太远
· slave已停止,在master已经覆盖了最近的操作后才重启
当slave脱离同步后,复制停止。管理员必须手动干涉来重新复制,使用resync指令。或者,使用- -autoresync参数来允许一个slave在10s后自动重新复制。使用- -autoresync参数时,slave在一个10分钟的周期内,只会重新同步一次。
为了防止这种情况的发生,你可以在master实例启动时指定一个更大的oplog,通过使用mongod --oplogsize参数。如果你不指定--oplogsize,mongod会自动分配5%的可用磁盘空间来创建oplog(在64位操作系统上最少1GB,32位操作系统上最少50MB)。
3.运行中的主从状态参数
MongoDB在mongod实例中提供了一些指令行参数。
在一个master实例上,确认以下的操作能返回master的复制状态:
rs.printReplicationInfo()
在一个slave实例上,使用以下操作来返回slave的复制状态:
rs.printSlaveReplicationInfo()
4.使用副本集,模拟一个类似于主从复制的架构
如果你想使用副本集,模拟一个类似于主从复制的架构,考虑使用以下副本集参数文档来部署。部署时,主机和提供了一个大致等同于双实例的主从复制架构。
{
_id : 'setName',
members : [
{ _id : 0, host : "<master>", priority : 1 },
{ _id : 1, host : "<slave>", priority : 0, votes : 0 }
]
}
5.将主从架构转变为副本集
为了将一个主从架构转变为副本集,将当前的master作为副本集的一个成员来重启。然后删除之前的slave成员的数据目录,并将slave新增作为副本集的secondary成员。
a.确认当前实例为master,执行:
db.isMaster()
该指令会返回一个类似文档:
{
"ismaster" : true,
"maxBsonObjectSize" : 16777216,
"maxMessageSizeBytes" : 48000000,
"localTime" : ISODate("2013-07-08T20:15:13.664Z"),
"ok" : 1
}
b.停止master和所有的slave进程,使用以下的指令:
db.adminCommand({shutdown : 1, force : true})
c.备份你的数据目录,以防你需要恢复到主从架构
d.将之前的master,使用- -replset参数启动,指令为:
mongod --replSet <setname>
e.使用mongo shell连接mongod实例,然后初始化副本集:
rs.initiate()
通过以下指令检查你的副本集状态:
rs.status()
6.其他维护
a.将slave提升为master
· 假设A为master,B为slave,此时A发生故障,B为正常
· 关闭A
· 关闭B
· 备份B上的dbpath的local数据文件,然后将B用- -master参数启动。
· 此时A无法成为B的slave,直到你能保证A上的数据是和B的数据一致
b.将master、slave反向
· 假设A为master,B为slave,此时A发生故障,B为正常
· 关闭A
· 关闭B
· 备份B上的datapath的local数据文件,并删除掉local.source文件(此处仅作为备份,关键是要删除掉local.source文件)
· 将B用--master参数启动
· 在B上使用write操作,此时会在B上产生oplog
· 关闭B
· 复制B上的datapath下的local数据文件到A对应的目录下
· 将B用--master参数启动
· 将A用--slave --fastsync参数启动(--dbpath参数可选)
c.通过现有的master磁盘镜像,创建一个slave
· 假设A为master,C为一个新的slave
· 关闭A
· 拷贝A上的datapath下的local数据文件到C对应的目录下
· 将A用--master参数启动
· 将C用--slave --fastsync参数启动(--dbpath参数可选)
d.slave重新同步
· 假设A为master,B为slave,此时B的数据已经不一致
· 方法一,在线操作:
use admin
db.runCommand( { resync: 1 } )
· 方法二,离线操作:即关闭B,然后清空B的数据文件,最后启动
e.复制链
slave不能做为slave的复制源,意味着所有slave的复制源均为master
f.修改slave的复制源
· 方法一,在线修改:单机启动mongod,
mongod
使用mongo shell连接后,更新local.source集合
use local
db.sources.update( { host : "prod.mississippi" },
{ $set : { host : "prod.mississippi.example.net" } } )
成功后,使用mongod --slave启动(此时不需要--source参数,即使输入了source参数效果也会被覆盖)。
mongod --slave
· 方法二,离线修改:即重新启动mongod,使用目标的 source
mongod --slave --source prod.mississippi