分类 MongoDB 下的文章

查看MongoDB中Replica Set的状态

查看Replica Set的状态,执行rs.status()即可

rs.status()
{
        "set" : "set1",
        "date" : "Thu Oct 28 2010 10:09:28 GMT+0800 (CST)",
        "myState" : 2,
        "members" : [
                {
                        "_id" : 0,
                        "name" : "192.168.x.x:10000",
                        "health" : 1,
                        "state" : 1,
                        "uptime" : 2486042,
                        "lastHeartbeat" : "Thu Oct 28 2010 10:09:26 GMT+0800 (CST)"
                },
                {
                        "_id" : 1,
                        "name" : "zjm-hadoop-slave217:10000",
                        "health" : 1,
                        "state" : 2,
                        "self" : true
                },
                {
                        "_id" : 2,
                        "name" : "192.168.x.x:10001",
                        "health" : 1,
                        "state" : 7,
                        "uptime" : 2486042,
                        "lastHeartbeat" : "Thu Oct 28 2010 10:09:27 GMT+0800 (CST)"
                }
        ],
        "ok" : 1
}

其中,health为1表明服务器正常,0表明服务器down了

state为1表明是Primary,2表明是Secondary,3是Recovering,7是Arbiter,8是Down

如果想在Secondary上find数据,需要先执行以下命令:

db.getMongo().setSlaveOk();
db.suv.find().count()

要查看某个Collection的信息,可以用db.suv.stats()

{
        "ns" : "suv.suv",
        "count" : 9519581,
        "size" : 573341552,
        "avgObjSize" : 60.2276037149114,
        "storageSize" : 736285696,
        "numExtents" : 21,
        "nindexes" : 3,
        "lastExtentSize" : 129238272,
        "paddingFactor" : 1,
        "flags" : 1,
        "totalIndexSize" : 1612344128,
        "indexSizes" : {
                "_id_" : 462365632,
                "Lt_1" : 790758336,
                "Cl.Cid_1" : 359220160
        },
        "ok" : 1
}

其中:

  1. size即为DataSize,是数据所占的空间大小
  2. storageSize为includes free space allocated to this collection,就是说包括已经分配但还空闲的空间
  3. totalIndexSize为所有索引所占的空间
  4. totalSize为该Collection所占的总空间,它等于storageSize+totalIndexSize

以上几个信息,也可以通过下面命令来查询:

db.suv.dataSize()
db.suv.storageSize()
db.suv.totalIndexSize()
db.suv.totalSize()

修改MongoDB中Replica Set的配置

MongoDB1.6的版本中,向Replica Set中增加成员很简单,如下:

#增加新的成员
rs.add("192.168.x,210:10000");
#增加新的选举成员
rs.addArb("192.168.x,216:10001");

这样配置好,Mongo会自动把数据同步到新的成员上

1.6版本中没有提供remove成员的命令,据说在1.7版本中有这个命令

不过,我们可以通过replSetReconfig来完成此操作

下面我们去掉set中一个成员,并增加一个新的成员,操作如下:

#在remove的成员上停掉MongoDB服务
kill -2 `cat /opt/mongodb_data/mongod.lock`
#将老成员的数据data文件scp到新服务器上,为了加快rs_sync的过程
scp suv.* 10.x.x.x:/pvdata/
#在新成员上启动MongoDB服务
/usr/local/mongodb/bin/mongod --fork --shardsvr --port 10000 --replSet set2 --dbpath /pvdata/mongodb_data  --logpath /pvdata/mongodb_log/mongod.log --logappend
#在该set的Master成员上执行命令
config = {_id: 'set2', members: [
        {_id: 0, host: '192.168.x,218:10000'},
        {_id: 1, host: '10.x.x.x:10000'},
        {_id: 2, host: '192.168.x,216:10001', arbiterOnly: true}
    ]}
    use local
    old_config = db.system.replset.findOne();
    #注意需要设置新config的versin,否则会报错version number wrong
    config.version = old_config.version + 1;
    use admin
    db.runCommand({ replSetReconfig : config })

这样就完成了对Replica Set的重新配置,移走了一台旧服务器,并增加了15.39的新服务器

我们查看新服务器mongod.log,可以看到:

Wed Oct 27 14:24:19 done allocating datafile /pvdata/mongodb_data/local.ns, size: 16MB,  took 0.049 secs
...
Wed Oct 27 17:55:12 [rs_sync] replSet initialSyncOplogApplication 66500000
Wed Oct 27 17:58:02 [rs_sync] replSet initial sync finishing up
Wed Oct 27 17:58:02 [rs_sync] replSet set minValid=4cc7f49a:7b
Wed Oct 27 17:58:02 [rs_sync] building new index on { _id: 1 } for local.replset.minvalid
Wed Oct 27 17:58:02 [rs_sync] done for 0 records 0.052secs
Wed Oct 27 17:58:02 [rs_sync] replSet initial sync done
Wed Oct 27 17:58:04 [rs_sync] replSet SECONDARY

最后,说明新的Server已经sync完成,并作为secondary成功启动了

我们用rs.status()也能看到新的set的状态:

{
        "set" : "set2",
        "date" : "Wed Oct 27 2010 17:57:39 GMT+0800 (CST)",
        "myState" : 1,
        "members" : [
                {
                        "_id" : 0,
                        "name" : "zjm-hadoop-slave218:10000",
                        "health" : 1,
                        "state" : 1,
                        "self" : true
                },
                {
                        "_id" : 1,
                        "name" : "10.x.x.x.x:10000",
                        "health" : 1,
                        "state" : 3,
                        "uptime" : 1231,
                        "lastHeartbeat" : "Wed Oct 27 2010 17:57:39 GMT+0800 (CST)"
                },
                {
                        "_id" : 2,
                        "name" : "192.168.x,216:10001",
                        "health" : 1,
                        "state" : 7,
                        "uptime" : 1237,
                        "lastHeartbeat" : "Wed Oct 27 2010 17:57:39 GMT+0800 (CST)"
                }
        ],
        "ok" : 1
}

搭建MongoDB Sharding集群

从1.6版本起,MongoDB开始正式支持Sharding

同时,MongoDB也推出了Replica Sets,用以替代之前版本的Replica Pairs

通过把Sharding和Replica Sets相结合,我们可以搭建一个分布式的,高可用性,自动水平扩展的集群

一个典型的集群结构如下:

集群由以下3个服务组成:

  1. Shards Server: 每个shard由一个或多个mongod进程组成,用于存储数据
  2. Config  Server: 用于存储集群的Metadata信息,包括每个Shard的信息和chunks信息
  3. Route   Server: 用于提供路由服务,由Client连接,使整个Cluster看起来像单个DB服务器

另外,Chunks是指MongoDB中一段连续的数据块,默认大小是200M,一个Chunk位于其中一台Shard服务器上

下面,搭建一个Cluster,它由4台服务器组成,包括2个Shard,3个Config,1个Route

其中每个Shard由一个Replica Set组成,每个Replica Set由2个Mongod节点,1个vote节点组成

以下是搭建配置的过程:

1. 四台服务器分别启动相应的Mongod进程:

192.168.x.216
/usr/local/mongodb/bin/mongod --fork --shardsvr --port 10000 --replSet set1 --dbpath /pvdata/mongodb_data  --logpath /pvdata/mongodb_log/mongod.log
/usr/local/mongodb/bin/mongod --fork --shardsvr --port 10001 --replSet set2 --dbpath /pvdata/mongodb_data1  --logpath /pvdata/mongodb_log/mongod1.log

192.168.x.217
/usr/local/mongodb/bin/mongod --fork --shardsvr --port 10000 --replSet set1 --dbpath /pvdata/mongodb_data  --logpath /pvdata/mongodb_log/mongod.log

192.168.x.218
/usr/local/mongodb/bin/mongod --fork --shardsvr --port 10000 --replSet set2 --dbpath /pvdata/mongodb_data  --logpath /pvdata/mongodb_log/mongod.log
/usr/local/mongodb/bin/mongod --fork --shardsvr --port 10001 --replSet set1 --dbpath /pvdata/mongodb_data1  --logpath /pvdata/mongodb_log/mongod1.log

192.168.x.137
/usr/local/mongodb/bin/mongod --fork --shardsvr --port 10000 --replSet set2 --dbpath /opt/mongodb_data  --logpath /opt/mongodb_log/mongod.log

2. 分别配置2组Replica Sets:

192.168.x.216
mongo --port 10000
    config = {_id: 'set1', members: [
        {_id: 0, host: '192.168.x.216:10000'},
        {_id: 1, host: '192.168.x.217:10000'},
        {_id: 1, host: '192.168.x.218:10001', arbiterOnly: true}
    ]}
    rs.initiate(config)
    rs.status()


192.168.x.218
mongo --port 10000
    config = {_id: 'set2', members: [
        {_id: 0, host: '192.168.x.218:10000'},
        {_id: 1, host: '192.168.x.137:10000'},
        {_id: 1, host: '192.168.x.216:10001', arbiterOnly: true}
    ]}
    rs.initiate(config)
    rs.status()

注意:2台Server上的10001对应的Mongod,它们只负责在某个node down掉后,进行vote选举新的master,它们本身并不存储数据备份

3.配置3台Config Servers:

mongod --configsvr --fork --logpath /pvdata/mongodb_log/config.log --dbpath /pvdata/mongodb_config_data --port 20000

4.配置1台Route Server:

192.168.x.216
/usr/local/mongodb/bin/mongos --fork --chunkSize 1 --configdb "192.168.x.216:20000,192.168.x.217:20000,192.168.x.218:20000" --logpath /pvdata/mongodb_log/mongos.log

chunkSize参数用来设置chunk块的大小,这里为了测试,设置成1M

5..配置2组Shard:

192.168.x.216
mongo
    use admin
    db.runCommand({addshard:'set1/192.168.x.216:10000,192.168.x.217:10000'})
    db.runCommand({addshard:'set2/192.168.x.218:10000,192.168.x.137:10000'})
    db.runCommand({enablesharding:'test'})
    db.runCommand({listshards:1})
    printShardingStatus()
    db.runCommand({shardcollection:'test.test', key:{_id:1}, unique : true})

这样整个配置就完成了,下面可以用pymongo来进行测试:

con = pymongo.Connection("192.168.x.216", 27017)
db = con.test
collection = db.test
for i in xrange(10000):
    name = ''.join(random.choice(string.letters) for i in xrange(10))
    collection.save({'_id':name})

然后,进入mongo的命令行,可以在2组的shard中分别查看count值,会发现collection记录被平均的分布到了2组shard server上了

下面,我们再来测试一下automated failover:

将x.218的mongod进程kill -2杀掉后,在x.137的log中,可以看到:

Wed Sep 29 10:51:04 [ReplSetHealthPollTask] replSet info 192.168.x.218:10000 is now down (or slow to respond)
Wed Sep 29 10:51:04 [rs Manager] replSet info electSelf 1
Wed Sep 29 10:51:04 [rs Manager] replSet PRIMARY

说明,新的vote已经完成,x.137变成了新的primary master了

此时,我们再往db中继续写入数据,然后启动x.218,会发现:

Wed Sep 29 10:52:56 [ReplSetHealthPollTask] replSet 192.168.x.218:10000 SECONDARY

说明,x.218此时又作为secondary来运行了

同时,在218 down掉时,137上写入的数据也会继续同步到218上

整个配置过程还是比较简单的,测试也挺正常

但整个Cluster的稳定性,还有待于应用上线后的观察...

MongoDB中MapReduce的应用

在MongoDB中可以使用MapReduce进行一些复杂的聚合查询


Map函数和Reduce函数可以使用JavaScript来实现


可以通过db.runCommand或mapReduce命令来执行一个MapReduce的操作:



折叠复制代码




  1. db.runCommand(

  2. { mapreduce : <collection>,

  3. map : <mapfunction>,

  4. reduce : <reducefunction>

  5. [, query : <queryfilter object>]

  6. [, sort : <sortthe query. useful for optimization>]

  7. [, limit : <numberof objects to return from collection>]

  8. [, out : <output-collectionname>]

  9. [, keeptemp: <true|false>]

  10. [, finalize : <finalizefunction>]

  11. [, scope : <objectwhere fields go into javascript global scope>]

  12. [, verbose : true]

  13. }

  14. );

  15. #或者使用一个包装后的Helper命令

  16. db.collection.mapReduce(mapfunction,reducefunction[,options]);




如果没有定义out,则它执行后默认生成一个临时的collection,当client连接断开后,该collection会自动被清除


一个简单的列子,有一个user_addr的collection,结果如下:



折叠复制代码




  1. db.user_addr.find({'Uid':'test@sohu.com'})

  2. { "_id" : ObjectId("4bbde0bf600ac3c3cc7245e3"), "Uid" : "yangsong@sohu.com", "Al" : [

  3. {

  4. "Nn" : "test-1",

  5. "Em" : "test-1@sohu.com",

  6. },

  7. {

  8. "Nn" : "test-2",

  9. "Em" : "test-2@sohu.com",

  10. },

  11. {

  12. "Nn" : "test-3",

  13. "Em" : "test-3@sohu.com",

  14. }

  15. ] }




存储了一个用户(Uid)对应的联系人信息(Al),现在要查询每个Em联系人对应的数目,则建立如下的MapReduce



折叠复制代码




  1. m=function() {

  2. for (index in this.Al) {

  3. emit(this.Al[index].Em, 1);

  4. }

  5. }

  6. r=function(k, vals) {

  7. var sum=0;

  8. for (index in vals) {

  9. sum += vals[index];

  10. > }

  11. return sum;

  12. }

  13. res=db.user_addr.mapReduce(m,r)

  14. {

  15. "result" : "tmp.mr.mapreduce_1272267853_1",

  16. "timeMillis" : 29,

  17. "counts" : {

  18. "input" : 5,

  19. "emit" : 26,

  20. "output" : 26

  21. },

  22. "ok" : 1,

  23. }

  24. db[res.result].find()




MongoDB中的group函数实际上也需要借助MapReduce来实现


如:按照uid来group,计算出每个uid有多少个联系人



折叠复制代码




  1. r=function (obj,prev) {  

  2.     prev.sum += obj.Al.length;  

  3. }  

  4. db.user_addr.group({key:{'Uid':1},reduce:r,initial:{sum:0}})  






 

MongoDB常用的操作命令


  1. 超级用户相关:

    折叠复制代码




    1. use admin

    2. #增加或修改用户密码

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

    4. #查看用户列表

    5. db.system.users.find()

    6. #用户认证

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

    8. #删除用户

    9. db.removeUser('mongodb')

    10. #查看所有用户

    11. show users

    12. #查看所有数据库

    13. show dbs

    14. #查看所有的collection

    15. show collections

    16. #查看各collection的状态

    17. db.printCollectionStats()

    18. #查看主从复制状态

    19. db.printReplicationInfo()

    20. #修复数据库

    21. db.repairDatabase()

    22. #设置记录profiling,0=off 1=slow 2=all

    23. db.setProfilingLevel(1)

    24. #查看profiling

    25. show profile

    26. #拷贝数据库

    27. db.copyDatabase('mail_addr','mail_addr_tmp')

    28. #删除collection

    29. db.mail_addr.drop()

    30. #删除当前的数据库

    31. db.dropDatabase()





  2. 客户端连接

    折叠复制代码




    1. /usr/local/mongodb/bin/mongo user_addr -u user -p 'pwd'





  3. 增删改

    折叠复制代码




    1. #存储嵌套的对象

    2. db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})

    3. #存储数组对象

    4. db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})

    5. #根据query条件修改,如果不存在则插入,允许修改多条记录

    6. db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)

    7. #删除yy=5的记录

    8. db.foo.remove({'yy':5})

    9. #删除所有的记录

    10. db.foo.remove()





  4. 索引

    折叠复制代码




    1. #增加索引:1(ascending),-1(descending)

    2. db.things.ensureIndex({firstname: 1, lastname: 1}, {unique: true});

    3. #索引子对象

    4. db.user_addr.ensureIndex({'Al.Em': 1})

    5. #查看索引信息

    6. db.deliver_status.getIndexes()

    7. db.deliver_status.getIndexKeys()

    8. #根据索引名删除索引

    9. db.user_addr.dropIndex('Al.Em_1')





  5. 查询

    折叠复制代码




    1. #查找所有

    2. db.foo.find()

    3. #查找一条记录

    4. db.foo.findOne()

    5. #根据条件检索10条记录

    6. db.foo.find({'msg':'Hello 1'}).limit(10)

    7. #sort排序

    8. db.deliver_status.find({'From':'yushunzhi@sohu.com'}).sort({'Dt',-1})

    9. db.deliver_status.find().sort({'Ct':-1}).limit(1)

    10. #count操作

    11. db.user_addr.count()

    12. #distinct操作

    13. db.foo.distinct('msg')

    14. #>操作

    15. db.foo.find({"timestamp": {"$gte" : 2}})

    16. #子对象的查找

    17. db.foo.find({'address.city':'beijing'})





  6. 管理


  7. 折叠复制代码




    1. #查看collection数据的大小

    2. db.deliver_status.dataSize()

    3. #查看colleciont状态

    4. db.deliver_status.stats()

    5. #查询所有索引的大小

    6. db.deliver_status.totalIndexSize()





 

郁闷的mongoexport导出工具

MongoDB提供了mongoexport工具,可以把一个collection导出成json格式或csv格式的文件

 

原以为,这个工具会像mysql中的select into out file那样,导出比较方便

 

没想到,测试之后,结果很郁闷

 

测试环境如下:

 

Linux 2.6.18-128.el5 x86_64

 

8G内存,2个4核cpu

 

mongodb中6000多万条数据,data和共占用40G空间

 

在一个建立索引的字段上,条件执行mongoexport后,似乎它并没有用到索引特性

 

导出花费的时间很长,而且占用的cpu和内存巨高,尤其是内存,最高时达到了7.6G

 

把我的心整的一闪一闪的,别把服务器给整成内存溢出了

 

还好,最好结果还是出来了,不过Mongod占的内存空间却一直没有释放

 

一直维持在7.6G左右,无奈,只好重启mongod了...

 

所用的命令如下:

 


折叠复制代码





  1. mongoexport -h 127.0.0.1:27017 -d mail_addr -c user_addr -u addr -p 'test' -q {'uid':'aaaaaa@sohu.com'}


 

显然,mongoexport没用使用索引,因为uid我建立的有索引

 

直接用mongo的client执行,结果返回很快

 


折叠复制代码





  1. db.user_addr.find({'uid':'aaaaaa@sohu.com'})


 

不知道是我命令用的有问题,还是说是mongoexport实现的有问题?

 

MongoDB配置Master和Slave模式

MongoDB是一个可扩展,高性能、开源、模式自由、面向文档的数据库


它并不是我们通常用的RDBMS,属于最近比较热门的"NoSql"的数据库范畴


它和一般的基于key-value的db还是不大一样的,因为它本身的功能很强大


它已经实现了类似于SQL的很多功能,如index,limit,skip,group....


当应用的数据量达到海量级,传统的Mysql,Oracle不能满足我们的性能要求


而对于数据还有一定的查询需求时,也许可以考虑一下使用MongoDB


安装很简单:



折叠复制代码




  1. wget "http://downloads.mongodb.org/linux/mongodb-linux-x86_64-1.2.4.tgz"

  2. tar zxvf mongodb-linux-x86_64-1.2.4.tz

  3. ln -s /opt/mongodb-linux-x86_64-1.2.4/ /usr/local/mongodb

  4. mkdir /opt/mongodb_data




MongoDB有2个版本的,官方推荐使用mongodb-linux-x86_64-1.2.4.tgz,只有在linux是老系统,mongodb无法启动时,才使用"legacy static“版


MongoDB里提供了简单的Auth功能,如果要开启认证,则在启动之前,需要首先增加用户



折叠复制代码




  1. /usr/local/mongodb/bin/mongo admin

  2. db.addUser('admin','manager')

  3. db.auth('admin','manager')

  4. show dbs

  5. use address

  6. db.addUser('mongodb','test')




其中,admin是一个特殊的数据库,只有在admin上db.auth通过后,才能给其它的数据库增加权限


如上,我们为address数据库增加了一个mongodb的用户


另外,如果我们要启用Master/Slave模式,而且开启了Auth功能,则需要同时在Master和Slave上的local数据库上增加一个repl的用户



折叠复制代码




  1. use local

  2. db.addUser('repl','replication')




否则,当我们启动slave时,会报错:


replauthenticate: no user in local.system.users to use for authentication


replauthenticate: can't authenticate to master server, user:repl


然后,我们使用如下脚本来分别启动Master和Slave即可,注意--oplogSize选项,它指定了master往slave同步时,更新日志保存的最大大小,默认64位机器,最大1G,如果太小,slave没有及时跟上的话,有可能会数据不一致



折叠复制代码




  1. nohup /usr/local/mongodb/bin/mongod run--dbpath=/data/mongodb_data/--logpath=/data/mongodb_data/mongodb.log--oplogSize=10000M--logappend --auth --master &

  2. nohup /usr/local/mongodb/bin/mongod run --dbpath=/opt/mongodb_data/--logpath=/opt/mongodb_data/mongodb.log --logappend --auth --slave--source=192.168.10.10:27017 &




在python中,可以使用pymongo模块



折叠复制代码




  1. frompymongo.connectionimportConnection


  2. connection = Connection("127.0.0.1",27017)

  3. db = connection.mail_addr

  4. db.authenticate('mongodb','test')

  5. ......

  6. db.address.save(user_addr,safe=True)




使用save来保存某个记录,如果我们已经使用find()查处了某个记录,则修改后也可以使用save来进行update操作


如果要实现某条记录不存在就insert,存在就update,则可以使用



折叠复制代码




  1. db.foo.update({'yy'}:5,{'$set':{'xx':2}},upsert=true)




MongoDB的功能很强大,可以像Mysql那样建立索引,且支持多字段索引、支持unique索引...


今后有空继续研究....

最新文章

最近回复

  • feifei435:这两个URI实际是不一样的
  • zsy: git push origin 分支 -f 给力!
  • 冼敏兵:简单易懂,good fit
  • Jack:无需改配置文件,看着累! # gluster volume se...
  • Mr.j:按照你的方法凑效了,折腾死了。。。。
  • zheyemaster:补充一句:我的网站路径:D:\wamp\www ~~菜鸟站长, ...
  • zheyemaster:wamp2.5(apache2.4.9)下局域网访问403错误的...
  • Git中pull对比fetch和merge | 炼似春秋:[…] 首先,我搜索了git pull和git fe...
  • higkoo:总结一下吧, 性能调优示例: gluster volume s...
  • knowaeap:请问一下博主,你维护的openyoudao支持opensuse吗

分类

归档

其它