MongoDB入门,含分布式配置

1、下载

wget http://fastdl.mongodb.org/linux/mongodb-linux-i686-1.6.5.tgz
tar -xzvf mongodb-linux-i686-1.6.5.tgz

2、测试单机环境
下载回来的MongoDB是已经编译好的,直接使用即可。

#首先建立数据库位置
mkdir ~/soft/mongodb/data
cd mongodb-linux-i686-1.6.5
cd bin
#启动mongodb服务器端,注意指定额外的数据库存放位置
./mongod --dbpath=/home/liheyuan/soft/mongodb/data
#启动mongodb客户端
./mongo
#查看当前选定的数据库
> db
test
#保存一个obj
> db.test.save({a:1})
#查看结果
> db.test.find()
{ "_id" : ObjectId("4d6e27081e960da4f8a23518"), "a" : 1 }

3、使用dbshell深入单机环境
mongo提供的dbshell是一个初步学习MongoDB数据库类型的好工具。

#选择其他数据库
> use mydb
switched to db mydb
> db
mydb

#显示所有数据库
> show dbs
admin
local
test
thing
things

#创建对象后再插入,可以注意到每个插入的对象会被自动附一个id(_id字段)
#同时,我们之前并没有定义任何数据表的结构(甚至连数据表的名字我们都没有指定),因此说MongoDB是一个schema-free的。
> j = {name:"mongodb"}
{ "name" : "mongodb" }
> i = {b:3}
{ "b" : 3 }
> db.thing.save(j)
> db.thing.save(i)
> db.thing.find()
{ "_id" : ObjectId("4d6e28911e960da4f8a2351a"), "name" : "mongodb" }
{ "_id" : ObjectId("4d6e28961e960da4f8a2351b"), "b" : 3 }
#如果插入的超过20条,会被自动截屏,我们可以用it命令迭带看下20条。find返回的是一个iterator(cursor)对象
> it

#另外一种方法,我们显示的使用cursor
> var cur = db.thing.find()
> while (cur.hasNext()) printjson(cur.next())
{ "_id" : ObjectId("4d6e28911e960da4f8a2351a"), "name" : "mongodb" }
{ "_id" : ObjectId("4d6e28961e960da4f8a2351b"), "b" : 3 }
#第三中方法,使用foreach
db.things.find().forEach(printjson);

#对于数据:
#{ "_id" : ObjectId("4d6e2c3a0cc156c6903a40fe"), "a" : 1, "b" : 2 }
#{ "_id" : ObjectId("4d6e2c3f0cc156c6903a40ff"), "a" : 2, "b" : 3 }
#{ "_id" : ObjectId("4d6e2c420cc156c6903a4100"), "a" : 3, "b" : 3 }

#查询 SELECT * FROM thing WHERE b=2 (select*)
> db.thing.find({b:2})
{ "_id" : ObjectId("4d6e2c3a0cc156c6903a40fe"), "a" : 1, "b" : 2 }

#查询 SELECT j FROM things WHERE b=2 (只选择b列)
> db.thing.find({b:2},{b:true})
{ "_id" : ObjectId("4d6e2c3a0cc156c6903a40fe"), "b" : 2 }
{ "_id" : ObjectId("4d6e2dec4811e5c557f8fa43"), "b" : 2 }

#使用findOne(),只显示第一行(较为高效)
> db.thing.findOne({b:2})
{ "_id" : ObjectId("4d6e2c3a0cc156c6903a40fe"), "a" : 1, "b" : 2 }

#使用limit,限制返回几行
> db.thing.find({b:2},{b:true}).limit(1)
{ "_id" : ObjectId("4d6e2c3a0cc156c6903a40fe"), "b" : 2 }

#删除
> db.thing.remove({a:3})

4、MongoDB的update

#语法
db.collection.update( criteria, objNew, upsert, multi )

criteria : update的查询条件,类似sql update查询内where后面的
objNew   : update的对象和一些更新的操作符(如$,$inc...)等,也可以理解为sql update查询内set后面的
upsert   : 这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
multi    : mongodb默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。

例:
db.test0.update( { "count" : { $gt : 1 } } , { $set : { "test2" : "OK"} } ); 只更新了第一条记录
db.test0.update( { "count" : { $gt : 3 } } , { $set : { "test2" : "OK"} },false,true ); 全更新了
db.test0.update( { "count" : { $gt : 4 } } , { $set : { "test5" : "OK"} },true,false ); 只加进去了第一条
db.test0.update( { "count" : { $gt : 5 } } , { $set : { "test5" : "OK"} },true,true ); 全加进去了
db.test0.update( { "count" : { $gt : 15 } } , { $inc : { "count" : 1} },false,true );全更新了
db.test0.update( { "count" : { $gt : 10 } } , { $inc : { "count" : 1} },false,false );只更新了第一条

此外,save()相当于自动判断_id字段的更新(如果没有_id相同的则自动插入新的)
update中第2个参数使用$inc可以给数值类型加一
update中第2个参数使用$set可以添加字段
update中第2个参数使用$unset可以删除字段,如:db.test0.update( { "_id" : 15 } , { $unset : { "test3":"test" } } );

5、MongoDB的分布式配置
参考资料:
http://hi.baidu.com/lzpsky/blog/item/d59af4276c73c50f908f9d5d.html
http://blog.jokry.me/2010/07/mongodb-distributable-slice/
http://www.cnblogs.com/daizhj/archive/2010/09/07/1820528.html
http://www.iwanna.cn/archives/2010/09/17/5313/
http://www.iwanna.cn/archives/2010/09/17/5310/

结点类型及数据:
Shard:Node,存储了若干Chunks(默认大小100MB)
Config Server:Meta Server,存了Shard信息和Chunk信息。
Router(mongos):暂时解释不清楚,它和Config Server放在一个服务器上就可以了。

#在一台机器上模拟2个Shard和1个Config Server
cp -rf mongodb mongodb_1
cp -rf mongodb mongodb_2
cp -rf mongodb mongodb_3

#启动Shard1(注意添加参数)
cd mongodb_1
./bin/mongod --shardsvr --dbpath /home/liheyuan/soft/mongodb_1/data/ --port 20001

#启动Shard2
cd mongodb_2
./bin/mongod --shardsvr --dbpath /home/liheyuan/soft/mongodb_2/data/ --port 20002

#启动Config Server(注意添加参数--configsvr)
cd mongodb_3
./bin/mongod --configsvr --dbpath /home/liheyuan/soft/mongodb_3/data/ --port 20003

#启动mongos(一个Router),这个是所有其他连接的入口,指定config的ip:port,而mogos的启动port是27017
bin/mongos --configdb localhost:20003

#客户端连接Config Server
cd ../mongodb_3
bin/mongo
> use admin
#添加Shard
> use admin
switched to db admin
> db.runCommand({addshard:"localhost:20001"})
{ "shardAdded" : "shard0000", "ok" : 1 }
> db.runCommand({addshard:"localhost:20002"})
{ "shardAdded" : "shard0001", "ok" : 1 }
#查看已经添加的Shard
> db.runCommand({listshards:1})
{
        "shards" : [
                {
                        "_id" : "shard0000",
                        "host" : "localhost:20001"
                },
                {
                        "_id" : "shard0001",
                        "host" : "localhost:20002"
                }
        ],
        "ok" : 1
}
#在指定的数据库上开启Sharding
> db.printShardingStatus()
--- Sharding Status ---
  sharding version: { "_id" : 1, "version" : 3 }
  shards:
      { "_id" : "shard0000", "host" : "localhost:20001" }
      { "_id" : "shard0001", "host" : "localhost:20002" }
  databases:
        { "_id" : "admin", "partitioned" : false, "primary" : "config" }

> db.runCommand({enablesharding:"test"})
> db.printShardingStatus()
--- Sharding Status ---
  sharding version: { "_id" : 1, "version" : 3 }
  shards:
      { "_id" : "shard0000", "host" : "localhost:20001" }
      { "_id" : "shard0001", "host" : "localhost:20002" }
  databases:
        { "_id" : "admin", "partitioned" : false, "primary" : "config" }
        { "_id" : "test", "partitioned" : true, "primary" : "shard0000" }
注:一旦enable了个数据库,mongos将会把数据库里的不同数据集放在不同的分片上。除非数据集被分片(下面会设置),否则一个数据集的所有数据将放在一个分片上。

#在Mongodb中,一个服务器可以又多个数据库,一个数据库可以又多个Collection(相当于表),Collection中存放多个文档

#开启数据集分片(test数据库的post Collection)
db.runCommand({shardcollection:"test.post",key:{_id:1},unique:true})
#查看开启情况
> use test
switched to db test
> show collections
post
system.indexes
> db.post.stats()
{
        "sharded" : true,
        "ns" : "test.post",
        "count" : 0,
        "size" : 0,
        "avgObjSize" : NaN,
        "storageSize" : 8192,
        "nindexes" : 1,
        "nchunks" : 1,
        "shards" : {
                "shard0000" : {
                        "ns" : "test.post",
                        "count" : 0,
                        "size" : 0,
                        "avgObjSize" : NaN,
                        "storageSize" : 8192,
                        "numExtents" : 1,
                        "nindexes" : 1,
                        "lastExtentSize" : 8192,
                        "paddingFactor" : 1,
                        "flags" : 1,
                        "totalIndexSize" : 8192,
                        "indexSizes" : {
                                "_id_" : 8192
                        },
                        "ok" : 1
                }
        },
        "ok" : 1
}

可以从上面的post的Collection看出,分片已经开启成功!

6、MongoDB的c客户端使用
上面为止,我们只是完成了对MongoDB的配置,使用的是dbshell,在日常场景中,显然要从c/c++/python/java等编程语言中直接存取MongoDB,下面使用c客户端完成这个工作。

#编译
sudo apt-get -y install git-core
git clone git://github.com/mongodb/mongo-c-driver.git

4 thoughts on “MongoDB入门,含分布式配置

  1. omar

    你好,能简单说说为什么配它的分布式而不是它速度不如mysql呢?我自己测的速度不如mysql…当然安装等等确实方便了很多…简单交流下

    Reply
  2. coder4 Post author

    @omar:
    你的数据规模又多大?多少个字段,多少记录?
    首先,有很多参数需要调优,这个我还没有做过。
    MongoDB的Replication和Shard主要解决两个问题:
    1、横向拓展问题,比如现在速度课接受,但数据大了后怎么办?一种选则是换更NB的机器,第二种就是两台机器一起跑。MongoDB就是第2种,可拓展行较好。
    2、读密集写不密集情况。即单点写入,多点读出可大大缓解读取压力,提升系统性能。而很多系统中,确实写的很少。当然代价就是不同步。
    你确定你的机器内存够么?
    你不会是在vps上什么的跑吧?我自己测试,最慢每秒写都可达到10000/秒,比mysql好很多了。

    Reply
  3. coder4 Post author

    @omar: 内存不够的时候,MongoDB性能会下降很快,毕竟他是内存数据库,性能的提升都是靠存在内存中(定期dump到硬盘持久化)获得的。Mongo很吃内存的,一般100w个记录(每个记录1k)就能搞到500MB了。

    Reply
  4. omar

    谢谢回复。
    我是简单的测试,使用jdbc连mysql,然后用mongo的驱动连mongo,然后对几万条数据进行读取,简单比对了时间使用。
    我通常是mysql负责存储,memcached负责缓存,数据过大之后将其分布式配置。
    所以不太了解monogo的优势。

    Reply

Leave a Reply to coder4 Cancel reply

Your email address will not be published. Required fields are marked *