在之前的 《MongoDB分布式部署》 中已经提到,同一组数据库服务器上的数据是支持复制的。mongodb支持两种方式的数据复制,简单的主从配置和互为主从的配置。

MongoDB分布式部署之分片配置可见 http://hi.baidu.com/lzpsky/blog/item/644e083d6bbd920cbaa16793.html

   一、主从配置 (Master Slave)

主从数据库需要两个数据库节点即可,一主一从(并不一定非得两台独立的服务器,可使用--dbpath参数指定数据库目录)。
$ bin/mongod --master [--dbpath /data/masterdb/]   

于是,主服务器进程就会创建一个 local.oplog.$main数据集,即 "transaction log",以记录从服务器需要的操作队列信息。

配置一个从数据库节点:

$ bin/mongod --slave --source <masterhostname>[:<port>] [--dbpath /data/slavedb/]

主节点的信息会存放在从节点的  local.sources 数据集中,也可以不指定--source参数,而是往 local.sources中增加一条包含主节点信息的记录。

$ bin/mongo <slavehostname>/local 
> db.sources.find();      // confirms the collection is empty. then:
> db.sources.insert( { host: <masterhostname> } ); 
host:<masterhostname> 主节点的ip地址或域名全称,可跟上:port指定端口。

如果指定了 only: databasename  (optional) ,表示只有指定的数据库才复制,注:v1.2.1+修复了only的一个bug。

一个从节点可以有多个主节点,这种情况下, local.sources中会有多条配置信息。

  一台服务器可以同时即为主也为从。如果一台从节点与主节点不同步,比如从节点的数据更新远远跟不上主节点或者从节点中断之后重启但主节点中相关的数据更新日志却不可用了。这种情况下,复制操作将会终止,需要管理者的介入,看是否默认需要重启复制操作。管理者可以使用 { resync:1 } 命令 重启复制操作,可选命令行参数   --autoresync 可使从节点在不同步情况发生10秒钟之后,自动重启复制操作。如果 指定了--autoresync参数,从节点在10分钟以内自动重新同步数据的操作只会执行一次。

--oplogSize命令行参数 (与 --master一同使用 )配置用于存储给从节点可用的更新信息占用的磁盘空间(M为单位),如果不指定这个参数,默认大小为当前可用磁盘空间的5%(64位机器最小值为1G,32位机器为50M)。

安全性方面:

$ dbshell <slavehostname>/admin -u <existingadminusername> -p<adminpassword>
> use local 
> db.addUser('repl', <replpassword>);
^c 
$ dbshell <masterhostname>/admin -u <existingadminusername> -p<adminpassword> 
> use local 
> db.addUser('repl', <replpassword>); 
   
二、互为主从( Replica Pairs

数据库自动协调某个时间点上的主从关系。开始的时候,数据库会判断哪个是从哪个是主,一旦主服务器负载过高,另一台就会自动成为主服务器。

$ ./mongod --pairwith <remoteserver> --arbiter <arbiterserver>

remoteserver 组中的其他服务器host,可加:port指定端口。
arbiterserver  仲裁(arbiter )的host,也可指定端口。仲裁是一台mongodb服务器,用于协助判断某个时间点上的数据库主从关系。如果同组服务器在同一个交换机或相同的ec2可用区域内,就没必要使用仲裁了。如果同组服务器之间不能通信,可是使用运行在第三方机器上的仲裁,使用“抢七”方式有效地敲定主服务器,也可不使用仲裁,这样所有的服务器都假定是主服务器状态,可通过命令人工检测当前哪台数据库是主数据库:

$ ./mongo 
> db.$cmd.findOne({ismaster:1});
{ "ismaster" : 0.0 , "remote" : "192.168.58.1:30001" , "ok" : 1.0 } 

一致性:故障转移机制只能够保障组中的数据库上的数据的最终一致性。如果机器L是主服务器,然后挂了,那么发生在它身上的最后几秒钟的操作信息就到达不了机器R,那么机器R在机器L恢复之前是不能执行这些操作的。

安全性:同主从的操作相同。

数据库服务器替换。当一台服务器失败了,系统能自动在线恢复。但当一台机器彻底挂了,就需要替换机器,而替换机器一开始是没有数据的,怎么办?以下会解释如何替换一组服务器中的一台机器。

假设nodes(n1,n2)中的n2挂了,需要变成nodes(n1,n3)。
1、假设n2彻底挂了下线了,不能在线恢复。
2、需要告诉n1,你的搭档已经不是n2了而是n3。可使用 replacepeer  命令,检测该操作的返回值以确保操作成功。

n1> ./mongo n1/admin
> db.$cmd.findOne({replacepeer:1});
{
"info" : "adjust local.sources hostname; db restart now required" 
"ok" : 1.0


3、使用以下命令重启n1。
n1> ./mongod --pairwith n3 --arbiter <arbiterserver> 

4、启动n3。
n3> ./mongod --pairwith n1 --arbiter <arbiterserver> 

注意的是,n3在与n1数据完全同步之前不能接收作为主节点的任何操作。
如果从节点设置了ok标志(db.getMongo().setSlaveOk() ),就可以查询从节点了。

三、配置案例

《MongoDB分布式部署之分片配置》 的第六个模块——案例部分,有详解。

四、java案例

1、链接mongodb:
ServerAddress right = new ServerAddress("10.13.127.212", 18020);
ServerAddress left = new ServerAddress("10.13.127.211", 18020);
Mongo mongo = new Mongo(right, left);

DB db = mongo.getDB("test");
db.authenticate("test", "test".toCharArray());
2、插入:
BasicDBObject dbObject = new BasicDBObject();
dbObject.put("id", i);
dbObject.put("time", System.currentTimeMillis());

coll.insert(dbObject);
3、更新
coll.update(new BasicDBObject("_id", id),  getDBObjectByLabel(mongoLabel));
4、查询, 查询条件的表达式文档
BasicDBObject dbObject = new BasicDBObject();
dbObject.put("id", 1);    //增加查询条件
BasicDBObject sortObject = new BasicDBObject(LabelConstant.ORDER_BY,LabelConstant.ORDER_DESC);

DBCursor dbCursor = coll.find(dbObject);  //不分页不排序
//cursor =  coll.find(doc).skip((pageNo - 1) * pageSize).limit(pageSize).sort(sortObject) ;  //分页排序
DBObject result = dbCursor.next();  //取数据