目录

NOSQL - 征服MongoDB

安装MongoDB

基本概念

MongoDBMysql
Databasedatabase
collectiontable
documentrow
Connections

MongoDB的管理

连接到管理数据库

use admin

增加或修改用户密码

db.addUser('admin','pwd')

查看用户列表

db.system.users.find()

用户认证

db.auth('admin','pwd')

删除用户

db.removeUser('mongodb')

客户端验证连接

/usr/local/mongodb/bin/mongo ip_addr -u user -p 'pwd' 

查看所有用户

show users

查看所有数据库

show dbs

查看所有的collection

show collections

查看所有collection的状态

db.printCollectionStats()

查看主从复制状态

db.printReplicationInfo()

修复数据库

db.repairDatabase()

设置记录profiling

db.setProfilingLevel(1)  #0=off 1=slow 2=all

查看profiling

show profile
   

MongoDB数据库连接池

connectionsPerHost:每个主机的连接数
threadsAllowedToBlockForConnectionMultiplier:线程队列数,默认是5
     它以上面connectionsPerHost值相乘的结果就是线程队列最大值。
     如果连接线程排满了队列就会抛出“Out of semaphores to get db”错误。
connectionsPerHost默认是10,也就是线程池有50个连接数可供使用。
     因此只要将这个属性的值加大就可以避免上述错误。
maxWaitTime:最大等待连接的线程阻塞时间
connectTimeout:连接超时的毫秒。0是默认和无限
socketTimeout:socket超时。0是默认和无限
autoConnectRetry:这个控制是否在一个连接时,系统会自动重试

MongoDB的数据操作

MongoDB不需要手动创建db和collectionl,只要有数据插入,就有对应的数据库和表出现。

如我们有一个test数据库,对应的物理文件如下

[root@KVM-SRV1 db]# ls -alSh /data/db/
total 81M
-rw------- 1 root root  64M Jun 28 17:59 test.0
-rw------- 1 root root  16M Jun 28 17:59 test.ns
drwxr-xr-x 3 root root 4.0K Jun 28 18:04 .
drwxr-xr-x 3 root root 4.0K Jun 28 14:16 ..
drwxr-xr-x 2 root root 4.0K Jun 28 18:01 _tmp
-rwxr-xr-x 1 root root    6 Jun 28 14:16 mongod.lock

终端连接控制

[root@KVM-SRV1 db]# mongo
MongoDB shell version: 1.4.3
url: test
connecting to: test
type "help" for help

连接数据库

> use test
switched to db test

创建数据(库)

>for(var i=1;i<20;i++) db.record.save({name:"ranking",value:i})
......空行表示插入成功

存储数组对象

> db.record.save({'uid':123,'email':['aaa@a.com','bbb@b.com']})

删除当前数据库

> db.dropDatabase()

查看指定collection数据的大小

db.record.dataSize()

查看指定collection状态

db.record.stats()

查询指定collection所有索引大小

db.record.totalIndexSize()

删除collection

db.record.drop()

读取数据

方法一:find全部返回

> for(var i=1;i<20;i++) db.record.save({name:"ranking",value:i})
> db.record.find()
{ "_id" : ObjectId("4c2876b808e76380fce80a30"), "name" : "ranking", "value" : 1 }
{ "_id" : ObjectId("4c2876b808e76380fce80a31"), "name" : "ranking", "value" : 2 }
{ "_id" : ObjectId("4c2876b808e76380fce80a32"), "name" : "ranking", "value" : 3 }
.......

方法二:json格式返回

> db.record.find().forEach(printjson)
{
        "_id" : ObjectId("4c2876b808e76380fce80a30"),
        "name" : "ranking",
        "value" : 1
}
{
        "_id" : ObjectId("4c2876b808e76380fce80a31"),
        "name" : "ranking",
        "value" : 2
}
{
        "_id" : ObjectId("4c2876b808e76380fce80a32"),
        "name" : "ranking",
        "value" : 3
}
......

方法三:指定数据返回

> var items=db.record.find(); printjson(items[3])
{
        "_id" : ObjectId("4c2876b808e76380fce80a33"),
        "name" : "ranking",
        "value" : 4
}

方法四:数据以数组返回

> var array = db.record.find().toArray()
> array[3]
{
        "_id" : ObjectId("4c2876b808e76380fce80a33"),
        "name" : "ranking",
        "value" : 4
}

表索引管理

索引其实就是一张内置在数据库中的特殊的表

通常需要索引的字段

  1. 唯一键 _id 是默认被设置为索引的
  2. 需要被查找的字段应该建立索引,比如在find()里面的字段
  3. 需要被排序的字段应该建立索引。比如在sort()里面的字段
> use test
> show collections
foo
record
system.indexes         <---- here is indexes table
 
> db.record.insert({uid:1,name:"a",addr:"hz"})
> db.record.insert({uid:2,name:"b",addr:"xs"})

创建索引

> db.record.ensureIndex({uid:1})   # 创建uid索引
> db.record.ensureIndex({name:1})  # 创建name索引

查看索引

> db.system.indexes.find()
{ "name" : "_id_", "ns" : "test.foo", "key" : { "_id" : 1 } }
{ "name" : "_id_", "ns" : "test.record", "key" : { "_id" : 1 } }
{ "_id" : ObjectId("4c28b94c7d9d9da79912c0a2"), "ns" : "test.record", "key" : { "uid" : 1 }, "name" : "uid_1" }
{ "_id" : ObjectId("4c28ba2c7d9d9da79912c0a3"), "ns" : "test.record", "key" : { "name" : 1 }, "name" : "name_1" }

删除索引

> db.record.dropIndex({uid:1})    # 删除uid索引

数据输入和导出

mongoimport

该命令用于将 JSON/CSV/TSV 格式的文件 导入到MongoDB数据库 或者 collection

导入JSON格式文件

mongoimport -u username -p passwd -d dbname -c collectionname –file db.collectionname.json

导入CSV格式文件

mongoimport -u username -p passwd -d dbname -c collectionname –type csv -f filed1,filed2 –file db.collectionname.csv

mongoexport

将数据导出为 JSON/CSV格式文件。

导出为JSON格式

mongoexport -u username -p passwd -d dbname -c collectionname -o dbname.collectionname.json

导出为CSV格式:

mongoexport -u username -p passwd -d dbname -c collectionname –csv -f filed1,file2 -o dbname.collectionname.csv

mongodump

备份数据库

mongodump -u username -p passwd -d dbname -o backdirpath

备份collection

mongodump -u username -p passwd -d dbname -c collectionname -o backdirpath

mongorestore

从备份路径恢复 mongodum备份的数据
mongorestore backupdirpath

Mysql与MongoDB语法比较

参考资料

MysqlMongoDB
SELECT * FROM record WHERE name=“ranking”db.record.find({name:“ranking”}).forEach(printjson)
printjson(db.record.findOne({name:“ranking”}))
SELECT * FROM record WHERE x=4db.record.find({value:4})
SELECT name FROM record WHERE x=4db.record.find({value:4},{name:1})
SELECT * FROM record WHERE name=“ranking” order by value descdb.record.find({name:“ranking”}).sort({value:-1})
SELECT count(*) FROM record WHERE name=“ranking”db.record.find({name:“ranking”}).count()
SELECT * FROM record WHERE name=“ranking” and value >= 10 and value < 18 db.record.find({name:“ranking”,value:{$gte:10,$lt:18}})
select * from record where name=“ranking” limit 3db.record.find().limit(3)
select * from record where name=“ranking” limit 3,10db.record.find().skip(3).limit(10)
select distinct(name) from record where value<18db.record.distinct(name,{value:{$lt:18}})
update record set value=“110” where name=“geminis”db.record.update({name:geminis,{$set:{value:110}}})
update record set value=value+3 where name=“geminis”db.record.update({name:geminis,{$inc:{value:3}}})

MongoDB 界面管理程序

MongoDB 可以使用多种界面管理程序进行管理:

Fang of Mongo
Futon4Mongo
Mongo3
MongoHub for OS X
Myngo
Opricot
PHPMoAdmin
Mongui

Mongo Profiler

Mongo Profiler 是Mongodb自带的一款用于分析数据库操作性能的工具。

Enableing profiler

启用profiler 功能,需要在Mongo Shell 中调用如下命令。

    
           > db.setProfilingLevel(2);
           {"was" : 0 , "ok" : 1}
           > db.getProfilingLevel()
           2

profiler level:

           0   关闭profiler。
           1   记录慢查询操作。
           2   记录所有操作。
           

Viewing

profiler 记录的数据存放在当前数据库的 system.profile collection中,可以使用find()方法查看这些记录数据。

    > db.system.profile.find()
    {"ts" : "Thu Jan 29 2009 15:19:32 GMT-0500 (EST)" , "info" : "query test.$cmd ntoreturn:1 reslen:66 nscanned:0 
    \\ query: { profile: 2 }  nreturned:1 bytes:50" , "millis" : 0}
 

在记录输出结果中剔除$cmd:

    db.system.profile.find( function() { return this.info.indexOf('$cmd')<0; } )
 

查看指定collection的操作记录: for example: 查看test.foo 这个collection中产生的操作:

  > db.system.profile.find( { info: /test.foo/ } )
  {"ts" : "Thu Jan 29 2009 15:19:40 GMT-0500 (EST)" , "info" : "insert test.foo" , "millis" : 0}
  {"ts" : "Thu Jan 29 2009 15:19:42 GMT-0500 (EST)" , "info" : "insert test.foo" , "millis" : 0}
  {"ts" : "Thu Jan 29 2009 15:19:45 GMT-0500 (EST)" , "info" : "query test.foo ntoreturn:0 reslen:102 nscanned:2 
  \\ query: {}  nreturned:2 bytes:86" , "millis" : 0}
  {"ts" : "Thu Jan 29 2009 15:21:17 GMT-0500 (EST)" , "info" : "query test.foo ntoreturn:0 reslen:36 nscanned:2  
  \\ query: { $not: { x: 2 } }  nreturned:0 bytes:20" , "millis" : 0}
  {"ts" : "Thu Jan 29 2009 15:21:27 GMT-0500 (EST)" , "info" : "query test.foo ntoreturn:0 exception  bytes:53" ,
  "millis" : 88}

查看超过 指定时间 的慢操作记录:
for example: 查看操作时间超过5 毫秒的 慢操作:

            
            > db.system.profile.find( { millis : { $gt : 5 } } )
            {"ts" : "Thu Jan 29 2009 15:21:27 GMT-0500 (EST)" , "info" : "query test.foo ntoreturn:0 exception
            bytes:53" , "millis" : 88}

理解输出结果

   ts: 时间戳
   millis:  执行操作花费的时间,单位:毫秒。
   

info 字段信息:

   query: 表示当前为查询操作,后面附带详细查询信息。
         nreturned  匹配查询的对象数量。
   ntoreturn: 限制查询返回对象的数量,如果未做限制则为0,该结果于limit()有关,例如limit(5),则ntoreturn的值为5。
   nscanned: 操作执行时扫描过的对象数量。
   reslen:    查询结果长度,单位:byte.
   update: 更新操作
          fastmod: 表示当前为快速更新。
          fastmodinsert: 表示当前为快速更新的upsert操作。
          upsert:   表示当前为upsert操作。
          moved :    表示当前操作从磁盘上清楚对象。
   insert:   数据库插入操作
   getmore: 表示只显示了部分信息。

Configuring "Slow"

有两种方法可以记录慢操作。

  1. 在启动Mongod Server 时,添加 –slowms 参数

    mongod –slowms=10 #将会记录执行时间超过 10ms 的操作。
    2. db.setProfilingLevel( level , slowms )
    db.setProfilingLevel(1,10)


    优化性能

    查询性能优化

    * 如果当前为查询操作,且nscanned 的数量远远超过 nreturned,说明数据库大多数的时间都花费在扫描对象上
    此时可以考虑对其创建索引,用以加快对象扫描速度。 * 当reslen 的值非常大到时候,要考虑优化查询语句。

    Profiler Performance

启用 profiler 会对数据库的性能造成轻微影响。profiler 数据存放在 system.profile 中,它是一个 capped collection. 由于存储空间很小, 因此只能存储最近的操作记录。

Shard Cluster

shard Introduction

MongoDB 支持数据自动分片。这样做可以在多个节点之间按照水平比例来存放数据,当存储的数据超过单点数据库的极限时。
MongoDB 可以转换为shard cluster,它会自动管理多节点间的 故障转移 和 负载均衡,这些对于上层应用来说是透明的,它仍然将
shard cluster当做单点MongodDB,而不需要更改应用代码。

MongoDB's Auto-Sharding

架构概览

一个MongoDB shard cluster 由两个 或 多个的 shards ,一 或多个 config servers ,再加上若干 mongos 路由进程组成。

shards

Shard 由一或多台启用了Mongod 进程的 Server组成。在生产环境中,每个shard 包含多台mongod server ,
由shard 中的多台Mongod server 构成一个副本集用于保证数据可靠性和故障转移。

Shard Keys

为了分割一个 collection ,需要要指定一个 shard keys pattern ,类似于创建索引时使用 key pattern,它由被分割的collection
中的 fields 决定.
shard keys parttern 示例:

          { state : 1 }
          { name : 1 }
          { _id : 1 }
          { lastname : 1, firstname : 1 }
          { tag : 1, timestamp : -1 }

MongoDB 是按照保序分片,相邻的分片数据往往在同一台Server上,
config server 存储用于指示分片数据location的元数据。

chunks

Chunk 就是 collection 中一段连续范围的数据, collection,minkey,maxkey 用于描述一个chunk,
它介于minkey 和 maxkey 之间。
chunks 的maxsize 一般为200M,一旦超出这个范围, chunk将会被切分为两个新的chunk .
当一个shard 数据过量时,chunk将会迁移到其他shard,此外添加一个新的shard将会影响到chunk的迁移

Config server

config server 存储着 shard server 以及 shard server所包含的 chunks 的相关信息的元数据。
config server 主要存储 chunk 信息,每台config server 都包含chunk信息的完整拷贝 。
双向提交用于确保config server 之间的数据一致性。
一旦某台config server 发生故障,元数据将变成只读状态,然而,即使是在这种情况下,shard cluster 的数据仍旧可以读写。

Routing Processes

mongos 进程用于协调shard cluster的多个组件,使其看起来是一个单点系统。
当接收client 的请求时,Mongos 进程将请求转发到合适的server ,并合并请求结果然后返回给client.
Mongos process 的状态并不持久,mongos 启动时从config server 获取状态信息,config server 上发生的任何更改都会传播给 mongos进程。

mongos 进程可以在任何服务器上部署,它没有数量上的限制。建议方法是在每台应用服务器上部署mongos进程,
这样的话,单台应用服务器发生故障后,并不会影响整个shard cluster 。

operation types

shard 系统中的操作可以被分为两类 global 和 targeted,
targgerd 操作通常在单个 shards 中进行查询,更新,写入 ,因此效率十分高效。
global 操作通常在大部分 甚至所有的shards中进行查询,更新,写入, 因此效率低下。

Operation 的分类于 shard key 有关, 可将shard key想象成类似于 索引。 以{x:1}作为shard key 为例,下表中列出了targged 和 global操作的一些例子。

Operation Type Comments
db.foo.find( { x : 300 } ) Targeted 在单个shard中查询
db.foo.find( { x : 300, age : 40 } ) Targeted 在单个shards中查询
db.foo.find( { age : 40 } ) Global 遍历所有shards查询
db.foo.find() Global 连续的查询
db.foo.find(…).count() Variable 类似于find()操作
db.foo.find(…).sort( { age : 1 } ) Global 并行操作
db.foo.find(…).sort( { x : 1 } ) Global 连续的查询
db.foo.count() Global 并行操作
db.foo.insert( <object> ) Targeted
db.foo.update( { x : 100 }, <object> )
db.foo.remove( { x : 100 } )
Targeted
db.foo.update( { age : 40 }, <object> )
db.foo.remove( { age : 40 } )
Global
db.getLastError()
db.foo.ensureIndex(…) Global

Server 布局设计

Configuring Sharding

shard cluster 最少由以下三部分构成。

1. Sharding Components

Shard Servers
Mongod server 作为shard server 运行,在启动添加 –shardsvr 参数

     $ mongod --shardsvr  &

Config Servers
Mongod server 作为config server 运行,在启动添加 –configsvr 参数

     $ mongod --configsvr &

mongos Router
启动mongos 进程 需要添加–configdb 参数,host:port 为config server 的主机地址:端口

             $ mongos --configdb host:port
             

2. Configuring the Shard Cluster

connect monogs

当所有的shard cluster 组件都运行之后,可以使用mongo shell 连接上 mongos process
通过mongos 连接至admin 数据库

    ./mongo <mongos-hostname>:<mongos-port>/admin
    > db
    admin

Adding shards

每个shard 由一或多个 server 组成,作为演示,每个shard 又单台server构成,使用多台server 请参考replica set 在shard cluster中添加shard :

        > db.runCommand( { addshard : "<serverhostname>[:<port>]" } );
        {"ok" : 1 , "added" : ...}

改命令只对集群中的每个shard 执行一次

当shard中的有多台server 时,使用逗号分隔 serverhostname:port
for example:

       > db.runCommand( { addshard : "<serverhostname1>[:<port1>],<serverhostname2>[:<port2>] ......" } );
       
可选参数

maxsize : 用于设置shard cluster 在shard 中使用多少磁盘空间,默认使用全部。

As an example

       > db.runCommand( { addshard : "sf103", maxSize:100000 } );
  

list shards

查看已经添加到集群中的shard

 > db.runCommand( { listshards : 1 } );     
 

Enabling Sharding on a Database

一旦shard cluster中添加了多个shard, 就可以在database 上启用sharding 功能。
这点十分重要,否则的话,database的数据只会存放在单个shard 中

 > db.runCommand( { enablesharding : "<dbname>" } );
 

3. Sharding a Collection

shardcollection 命令用于对 collection 进行分片,对collection分片 需要指定一个shard key,
cluster 会自动对指定的shard key 创建索引。

           > db.runCommand( { shardcollection : "<namespace>",
           key : <shardkeypatternobject> })
           

举个例子,对GridFS 的chunks collection进行分片 ,指定filesid 作为shard key,执行如下命令: > db.runCommand( { shardcollection : “test.fs.chunks”, key : { filesid : 1 } } )

            {"ok" : 1}

Sharding Administration

以下这些命令用于获取 shard cluster的信息

Identifying Shard Cluster

        > db.runCommand({ isdbgrid : 1})
        { "errmsg" : "no such cmd", "bad cmd" : { "isdbgrid" : 1 }, "ok" : 0 } #返回结果表示,当前连接的是monogd server.
        
        > db.runCommand({ isdbgrid : 1})
        { "isdbgrid" : 1, "hostname" : "v3-centos-5.5", "ok" : 1 } #返回结果表明,当前连接的是mongos process.
                            
        > db.runCommand({ismaster:1});
        { "ismaster" : 1, "msg" : "isdbgrid", "ok" : 1  #表明当前连接的是mongos process。
        

List Existing Shards

查看已shard cluster中的shard 列表

          > db.runCommand({ listshards : 1});
          {"servers" :
          [{"_id" :  ObjectId( "4a9d40c981ba1487ccfaa634")  ,
          "host" : "localhost:10000"},
          {"_id" :  ObjectId( "4a9d40df81ba1487ccfaa635")  ,
          "host" : "localhost:10001"}
          ],
          "ok" : 1
          }

List Which Databases are Sharded

查看已经启用sharding 功能的 Database

        > use admin
        > db.printShardingStatus();

        // A very basic sharding configuration on localhost
        sharding version: { "_id" : 1, "version" : 2 }
        shards:
        { "_id" : ObjectId("4bd9ae3e0a2e26420e556876"), "host" : "localhost:30001" }
        { "_id" : ObjectId("4bd9ae420a2e26420e556877"), "host" : "localhost:30002" }
        { "_id" : ObjectId("4bd9ae460a2e26420e556878"), "host" : "localhost:30003" }
  
        databases
        { "name" : "admin", "partitioned" : false, 
        "primary" : "localhost:20001", 
        "_id" : ObjectId("4bd9add2c0302e394c6844b6") }
	    my chunks
	
        { "name" : "foo", "partitioned" : true,
        "primary" : "localhost:30002", 
        "sharded" : { "foo.foo" : { "key" : { "_id" : 1 }, "unique" : false } },
        "_id" : ObjectId("4bd9ae60c0302e394c6844b7") }
        my chunks
        foo.foo { "_id" : { $minKey : 1 } } -->> { "_id" : { $maxKey : 1 } } 
        on : localhost:30002 { "t" : 1272557259000, "i" : 1 }

首先在shards 部分,可以看到构成shard Cluster的shard 分布位置。

Database 部分可以看到 shard cluster中包含的数据库,parttioned字段表示数据库是否启用的sharding 功能primary 表示数据库数据所存放的位置

Chunk Operations

movechunk 用于移动chunk的存放位置

             db.runCommand( { movechunk : "test.blog.posts" , 
             find : { author : "eliot" } , 
             to : "192.168.1.2" } )

Mongo shard cluster 配置实验

实验环境

shard cluster 所有的组件都运行在同一台 物理机上。

server type listen port
shard1 10000
shard2 10002
config server 10003
mongos process 10004

code1 启动shard cluster组件。

  $ mkdir -p /data/db/{configsvr,shard1,shard2}     # 创建数据目录
  $ mongod --shardsvr  --port 10001 --dbpath=/data/db/shard1 &  # 启动shard1
  $ mongod --shardsvr  --port 10002 --dbpath=/data/db/shard2 &  # 启动shard2
  $ mongod --configsvr  --port 10003 --dbpath=/data/db/configsvr  & #启动config server
  $ mongos --port 10004 --configdb localhost:10003 & 启动mongos process.

code2 配置shard cluster

  $ mongo localhost:10004/admin      # 通过 mongos process连接至admin数据库
  > db.runCommand({addshard:"192.168.1.243:10001", allowLocal : true }) # 添加shard1
  > db.runCommand({addshard:"192.168.1.243:10002", allowLocal : true }) # 添加shard2
  > db.runCommand({listshards:1})                   #查看已添加到cluster的shards
  {
      "shards" : [
              {
                      "_id" : ObjectId("4c109cc7ccd58762b9403c17"),
                      "host" : "192.168.1.243:10001"
              },
              {
                      "_id" : ObjectId("4c109d3accd58762b9403c18"),
                      "host" : "192.168.1.243:10002"
              }
      ],
      "ok" : 1
  }
   
  > db.test.insert({test:1})   #创建test数据库
  > db.runCommand({ enablesharding : “test” })  #在数据库test上启用分片功能。
  
  > db.printShardingStatus()             #查看test是否启用shard功能

       { "name" : "test", "partitioned" : true, "primary" : "192.168.1.243:10002", "_id" : 
      ObjectId("4c10a23c674edb9bf73bc56e") }
              my chunks
                                         # parttined 字段表明 test 数据库已经启用了sharding功能

Replication

Mongodb支持使用Replication实现 故障转移 和 数据冗余。

configuration type

Replication 主要有四种配置类型。

在MongoDB 1.4版本中主要使用 master/slave 。

replica sets

Master/slave

配置MogoDB 主从复制数据库,需要运行两个数据库实例,一台以Master 模式运行,另外一台以slave 模式运行。

start master

         $ bin/mongod --master [--dbpath /data/masterdb/]

master server 会创建 local.oplog.$main collection, 它类似于事务日志,slave将会按照它进行队列操作以达到数据复制的目的。
–oplogSize 可以指定事务日志的大小,默认情况下使用%5的硬盘空间, 但是64位系统最小必须大于 1G ,32位系统必须大于50M

start slave

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

source的详细信息存储在 slave server 的 local.sources collection 内。 可以在 local.sources
插入master server 的信息用以代替在slave启动时添加 –sources 参数。

           $ bin/mongo <slavehostname>/local
           > db.sources.insert( { host: <masterhostname:port>,only:<databasename> } 

host: 指定master server 的主机名或者IP地址,若master 没有侦听在 27017 端口,则需要添加 “hostname:port”.
only: 指定master中的某个数据库名。slave 只对该数据库进行数据同步。
slave 可以从多个master 同步数据,只需要在db.sources中添加多个master 的信息。

mongodb 能够同时以 master 和 slave 模式运行。
当slave 从master同步数据无法获得响应,或者slave被终止重新启动。slave将会进入out of sync 状态
需要执行 db.runCommand{rsync:1}: 重新进入数据同步状态。
–autoresync : slave 启动时添加此参数,当slave无法从 master 同步数据时,每十秒钟会执行一次{rsync:1}

security

在master 和 slave的local 数据上添加用户名密码,就可以实现master 和slave之间的安全验证。

 $ 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>);
 

--fastsync

对master 的数据创建一份快照,然后拷贝到 slave 上,这时启动slave 是添加 –fastsync 参数,可以将master的拷贝中的
metadata 格式转化成 slave 格式。 从而无需按照事务日志,进行数据记录创建。

Replica Pairs

MongoDB 支持Replica Pairs,它包含一对 mongod server 实例 .默认情况下只能对master 进行读写操作。
replica pairs 中的数据库在启动时会协商 谁将成为master ,谁将成为slave. 在运行过程中,一旦 replica paris 中的
master 出现故障。 slave将会自动升级为master ,原master 的状态数据将会传给新的master进行处理,从而实现故障转移。

Setup of Replica Pairs

以pair 模式启动mongod 执行以下命令:

    $ ./mongod --pairwith <remoteserver> --arbiter <arbiterserver> 
                                 
    remoteserver:  replica pairs中的另外一台server 
    arbiterserver:  仲裁SERVER ,不属于replica pairs 运行于第三台服务器上。
 

检测当前Mongo server 是否为master:

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

Consistency

replica 的成员仅仅只在最终进行failover时保持一致。假设replica pairs中的L server 为master ,当它发生故障
前的几秒钟的操作将不会被 新的master R server 所执行,这些操作会直到L server 恢复后,才会被应用。

Security

在 master 和 slave 上配置 ‘repl’ 用户来启用master 和 slave 之间的安全验证。

 $ ./mongo <lefthost>/admin -u <adminusername> -p<adminpassword>
 > use local
 > db.addUser('repl', <replpassword>);
 ^c
 $ ./mongo <righthost>/admin -u <adminusername> -p<adminpassword>
 > use local
 > db.addUser('repl', <replpassword>);

替换replica pairs 成员

当replica pairs中的某台 server 遭受物理上不可修复的损坏 ,我们需要将其替换出来。以保证replica pairs的运行。
假设replica pairs 包含 n1,n2 两台server , n2 遭受了无法修复的损坏。 需要用n3 将其替换。

1.在n1 上执行如下命令:

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

2.配合n3 重新启动n1:

                 
       n1> ./mongod --pairwith n3 --arbiter <arbiterserver>
    

3.启动 n3:

        n3> ./mongod --pairwith n1 --arbiter <arbiterserver>
    

Querying the slave

默认情况下 slave 无法执行任何读写操作, 若要使slave可以被查询,可执行。

        db.getMongo().setSlaveOk()

Working with an existing databas

假设有 L 和 R 两台 SERVER ,R 原先是一台 single server ,上面保存着一些datafile.
要使用L 和 R 组建一个replica pairs。

1 先附加–withpair 参数 启动 R SERVER .
2 附加–withpair 参数启动 L Server

master-master replication

由于Mongodb 对 master-master replication 支持不是很好。
不推荐使用使用 master-master replication 。

maste-master configuration

 $ nohup mongod --dbpath /data1/db --port 27017 --master --slave --source
 localhost:27018 > /tmp/dblog1 &
 $ nohup mongod --dbpath /data2/db --port 27018 --master --slave --source 
 localhost:27017 > /tmp/dblog2 &

master-master 执行以下操作时安全的:

 
  插入操作
  所有查询
  基于_id字段的删除
  

不安全的操作:

  更新单个对象
  
  

example

 $ # terminal 1, we run a mongod on default db port (27017)
 $ ./mongod --slave --master --source localhost:10000
                
 $ # terminal 2, we run a mongod on port 10000
 $ ./mongod --slave --master --dbpath /data/slave --port 10000 --source localhost
                    
 $ # terminal 3, we run the shell here
 $ ./mongo
 > // 'db' is now connected to localhost:27017/test
 > z = connect("localhost:10000/test")
 > // 'z' is now connected to localhost:10000/test db
                 
 > db.foo.insert({x:7});
 > z.foo.find()
 {"_id" :  ObjectId( "4ab917d7c50e4c10591ce3b6")  , "x" : 7}
 > db.foo.find()
 {"_id" :  ObjectId( "4ab917d7c50e4c10591ce3b6")  , "x" : 7}
                      
 > db.foo.insert({x:8})
 > db.foo.find()
 {"_id" :  ObjectId( "4ab917d7c50e4c10591ce3b6")  , "x" : 7}
 {"_id" :  ObjectId( "4ab9182a938798896fd8a906")  , "x" : 8}
 > z.foo.find()
 {"_id" :  ObjectId( "4ab917d7c50e4c10591ce3b6")  , "x" : 7}
 {"_id" :  ObjectId( "4ab9182a938798896fd8a906")  , "x" : 8}
                 
 > z.foo.save({x:9})
 > z.foo.find()
 {"_id" :  ObjectId( "4ab917d7c50e4c10591ce3b6")  , "x" : 7}
 {"_id" :  ObjectId( "4ab9182a938798896fd8a906")  , "x" : 8}
 {"_id" :  ObjectId( "4ab9188ac50e4c10591ce3b7")  , "x" : 9}
 > db.foo.find()
 {"_id" :  ObjectId( "4ab917d7c50e4c10591ce3b6")  , "x" : 7}
 {"_id" :  ObjectId( "4ab9182a938798896fd8a906")  , "x" : 8}
 {"_id" :  ObjectId( "4ab9188ac50e4c10591ce3b7")  , "x" : 9}
                        
 > z.foo.remove({x:8})
 > db.foo.find()
 {"_id" :  ObjectId( "4ab917d7c50e4c10591ce3b6")  , "x" : 7}
 {"_id" :  ObjectId( "4ab9188ac50e4c10591ce3b7")  , "x" : 9}
 > z.foo.find()
 {"_id" :  ObjectId( "4ab917d7c50e4c10591ce3b6")  , "x" : 7}
 {"_id" :  ObjectId( "4ab9188ac50e4c10591ce3b7")  , "x" : 9}
                        
 > db.foo.drop()
 {"nIndexesWas" : 1 , "msg" : "all indexes deleted for collection" , "ns" : 
    "test.foo" , "ok" : 1}
 > db.foo.find()
 > z.foo.find()
 >