在生产环境中,MongoDB极力推荐使用其复制功能!数据库管理员的一个十分重要的工作就是确保复制设置正确且运转良好!复制可以用来应对故障切换、数据集成、读扩展和离线批处理的数据源!马上就来讲一下复制的用法和其基本原理。
【主从复制】
主从复制是MongoDB中最常用的复制方式,这种方式非常灵活,常见的搭配方式为:一主一从、一主多从。
具体操作方式就是,通过mongod --master启动主服务器,通过mongod --slave --source master_address启动从服务器,其中master_address就是主节点的地址!实际应用中会在不同机器上实现主从服务器,我们这里在一台机器上进行演示:
启动主服务器:
E:\mongodb\mongodb-win32-x86_64-2.0.6\bin>mongod --dbpath E:\master\mongodata --logpath E:\master\mongolog\log.txt --port 10000 --master
all output going to: E:\master\mongolog\log.txt
启动第一个从服务器:
E:\mongodb\mongodb-win32-x86_64-2.0.6\bin>mongod --dbpath E:\slave1\mongodata --logpath E:\slave1\mongolog\log.txt --port 10001 --slave --source local
host:10000
all output going to: E:\slave1\mongolog\log.txt
启动第二个从服务器:
E:\mongodb\mongodb-win32-x86_64-2.0.6\bin>mongod --dbpath E:\slave2\mongodata --logpath E:\slave2\mongolog\log.txt --port 10002 --slave --source local
host:10000
all output going to: E:\slave2\mongolog\log.txt
以上就是创建了一个一主二从的主从复制系统,我们来操作一下,看看效果吧:
我们在主服务器中创建一个数据库一个集合,并插入了两个文档:
E:\mongodb\mongodb-win32-x86_64-2.0.6\bin>mongo localhost:10000
MongoDB shell version: 2.0.6
connecting to: localhost:10000/test
> show collections;
> use mylearndb;
switched to db mylearndb
> db
mylearndb
> db.users.insert({"name":"jimmy", "age":30});
> db.users.insert({"name":"tom", "age":32});
>
我们到从服务器1上查看结果为:
E:\mongodb\mongodb-win32-x86_64-2.0.6\bin>mongo localhost:10001
MongoDB shell version: 2.0.6
connecting to: localhost:10001/test
> use mylearndb;
switched to db mylearndb
> show collections;
system.indexes
users
> db.users.find();
{ "_id" : ObjectId("503a10a1a613fb3c0b49f704"), "name" : "jimmy", "age" : 30 }
{ "_id" : ObjectId("503a10a9a613fb3c0b49f705"), "name" : "tom", "age" : 32 }
>
从服务器2上的结果为:
E:\mongodb\mongodb-win32-x86_64-2.0.6\bin>mongo localhost:10002
MongoDB shell version: 2.0.6
connecting to: localhost:10002/test
> show dbs;
local 0.078125GB
mylearndb 0.078125GB
> use mylearndb;
switched to db mylearndb
> show collections;
system.indexes
users
> db.users.find();
{ "_id" : ObjectId("503a10a1a613fb3c0b49f704"), "name" : "jimmy", "age" : 30 }
{ "_id" : ObjectId("503a10a9a613fb3c0b49f705"), "name" : "tom", "age" : 32 }
>
看样我们的一主二从的复制系统已经搭配成功了。那么主从复制的原理是什么呢?
【主从复制的原理--oplog】
在主从结构中,主节点的操作记录成为oplog(operation log)。oplog存储在一个系统数据库local的集合oplog.$main中,这个集合的每个文档都代表主节点上执行的一个操作。我们重新向主数据库服务器中插入一条数据,然后查看这个集合可以看到:
> db.oplog.$main.find().sort({"$natural":-1});
{ "ts" : { "t" : 1345983979000, "i" : 1 }, "op" : "n", "ns" : "", "o" : { } }
{ "ts" : { "t" : 1345983969000, "i" : 1 }, "op" : "n", "ns" : "", "o" : { } }
{ "ts" : { "t" : 1345983959000, "i" : 1 }, "op" : "n", "ns" : "", "o" : { } }
{ "ts" : { "t" : 1345983949000, "i" : 1 }, "op" : "n", "ns" : "", "o" : { } }
{ "ts" : { "t" : 1345983939000, "i" : 1 }, "op" : "n", "ns" : "", "o" : { } }
{ "ts" : { "t" : 1345983929000, "i" : 2 }, "op" : "n", "ns" : "", "o" : { } }
{ "ts" : { "t" : 1345983929000, "i" : 1 }, "op" : "i", "ns" : "mylearndb.users", "o" : { "_id" : ObjectId("503a15b9a613fb3c0b49f707"), "name" : "tim",
"age" : 23 } }
{ "ts" : { "t" : 1345983919000, "i" : 1 }, "op" : "n", "ns" : "", "o" : { } }
在这个集合中,键“ts”表示时间戳,键“op”表示操作类型,“ns”表示操作的集合名,“o”表示具体操作的文档!这里主要注意的是,存储在oplog中的操作有时可能和主节点操作并不一致,因为存储操作前要进行等幂变换,也就是这些操作必须可以再从服务器上多次执行,只要顺序一致,结果就一致。因此比如更新器$inc的操作,最后会被变换为$set操作!并且这个集合中只会存储影响数据的操作,查询这类不影响数据的操作不会以oplog的形式进行存储!
从服务器会定期从主服务器中获取oplog记录,然后在本机上执行!
对于存储oplog的集合,MongoDB采用的是固定集合,也就是说随着操作过多,新的操作会覆盖旧的操作!这样做也是有道理的,不然,这个集合占用的空间就无法估算了!我们在启动服务时,可以通过选项--oplogSize来指定这个集合的大小,单位是MB,在Windows平台下,默认MongoDB会使用数据库安装分区可用空间的5%作为这个集合的大小!