经过上篇的学习,我们搭建了自己的分片系统(通俗点就是MongoDB数据库集群系统),我们通过如下命令将两个mongod的服务作为“片”添加到系统中,并且让数据库“mydb”的分片功能打开,指定集合“users”的片键为“name”:

C:\Users\liuxj>mongo localhost:30000/admin
MongoDB shell version: 2.0.6
connecting to: localhost:30000/admin
mongos> db.runCommand({"addshard" : "localhost:10001", "allowLocal" : true });
{ "shardAdded" : "shard0000", "ok" : 1 }
mongos> db.runCommand({"addshard" : "localhost:10002", "allowLocal" : true });
{ "shardAdded" : "shard0001", "ok" : 1 }
mongos> db.runCommand({"enablesharding" : "mydb" });
{ "ok" : 1 }
mongos> db.runCommand({"shardcollection" : "mydb.users", "key" : {"name" : 1}});
{ "collectionsharded" : "mydb.users", "ok" : 1 }
mongos>

【管理分片--查询配置信息】

分片的相关信息都会保存在分片系统的配置服务器中,具体在config数据库下,我们可以连接到mongos,查看这个数据库的相关信息:

1》 片信息

mongos> use config
switched to db config
mongos> db.shards.find();
{ "_id" : "shard0000", "host" : "localhost:10001" }
{ "_id" : "shard0001", "host" : "localhost:10002" }
mongos>

片信息保存在集合shards中。

2》 数据库

mongos> use config;
switched to db config
mongos> db.databases.find();
{ "_id" : "admin", "partitioned" : false, "primary" : "config" }
{ "_id" : "mydb", "partitioned" : true, "primary" : "shard0000" }
{ "_id" : "testdb", "partitioned" : false, "primary" : "shard0001" }
mongos>

集合databases中含有已经在片系统上的数据库列表,我们看这个集合中的键:

--------1)“_id” :数据库名称

--------2)“partitioned”:布尔,表明该库是否开启分片功能

--------3)  “primary”:表明这个数据库的大本营在哪个片上,每个数据库刚创建时会随机定位到一个片上!分片的数据 库会在后期分布到很多数据库服务其上,但会从这个片开始!

3》块

mongos> use config;
switched to db config
mongos> db.chunks.find();
{ "_id" : "mydb.users-name_MinKey", "lastmod" : { "t" : 1000, "i" : 0 }, "ns" : "mydb.users", "min" : { "name" : { $minKey : 1 } }, "max" : {
 { $maxKey : 1 } }, "shard" : "shard0000" }
mongos>

块信息保存在chunks集合中,从这里我们可以看出数据到底是怎么切分到集群的!

【管理分片--分片命令】

前面我们提到了一些基本命令,如添加块、启动分片等。我们再提供管理分片系统(集群)的常用命令:

1》printShardingStatus:给出整个分片系统的一些状态信息:

mongos> db.printShardingStatus();
--- Sharding Status ---
  sharding version: { "_id" : 1, "version" : 3 }
  shards:
        {  "_id" : "shard0000",  "host" : "localhost:10001" }
        {  "_id" : "shard0001",  "host" : "localhost:10002" }
  databases:
        {  "_id" : "admin",  "partitioned" : false,  "primary" : "config" }
        {  "_id" : "mydb",  "partitioned" : true,  "primary" : "shard0000" }
                mydb.users chunks:
                                shard0000       1
                        { "name" : { $minKey : 1 } } -->> { "name" : { $maxKey : 1 } } on : shard0000 { "t" : 1000, "i" : 0 }
        {  "_id" : "testdb",  "partitioned" : false,  "primary" : "shard0001" }

mongos>

其集中上面配置集合的所有信息。

2》删除片,通过removeshard命令(admin数据库下执行),会从集群中删除片,removeshard会把给定片上的所有块都挪到其他片上!我们做个试验,我们通过mongos往mydb.user集合中插入两条数据:

mongos> use mydb;
switched to db mydb
mongos> db.users.insert({"name" : "tom"});
mongos> db.users.insert({"name" : "jimmy"});
mongos>

mydb的大本营是第一个片,即localhost:10001,我们通过shell连接到localhost:10001,查看该集合:

> use mydb;
switched to db mydb
> db.users.find();
{ "_id" : ObjectId("5045f5e5c2f66c42c6f6a6fb"), "name" : "tom" }
{ "_id" : ObjectId("5045f5ecc2f66c42c6f6a6fc"), "name" : "jimmy" }
>

数据在这里。我们再查看locahost:10002:

> use mydb;
switched to db mydb
> db.users.find();
>

没有任何数据。然后我们将片1从集群中删除:

mongos> use admin;
switched to db admin
mongos> db.runCommand({"removeshard" : "localhost:10001"});
{
        "msg" : "draining started successfully",
        "state" : "started",
        "shard" : "shard0000",
        "ok" : 1
}
mongos>

此时,我们再查询localhost:10002:

> db.users.find();
{ "_id" : ObjectId("5045f5e5c2f66c42c6f6a6fb"), "name" : "tom" }
{ "_id" : ObjectId("5045f5ecc2f66c42c6f6a6fc"), "name" : "jimmy" }
>

数据已经被转移到片2上了。片删除成功。

【生产配置】

MongoDB分片系统(集群系统)如果应用在生产环境中,就需要一些更加健壮的方案,我们现在就讨论一下如何让集合更稳定。通常,我们的做法为:

1》 使用多个配置服务器

2》 多个mongos路由服务器

3》 每个片都是一个副本集

(一)使用多个配置服务器,上面,我们启动mongos路由服务只指定了一个配置服务器,我们现在指定3个:

C:\Users\liuxj>mongos --port 30000 --configdb localhost:20000,localhost:20001,localhost:20002
Wed Sep 05 20:02:38 mongos db version v2.0.6, pdfile version 4.5 starting (--help for usage)
Wed Sep 05 20:02:38 git version: e1c0cbc25863f6356aa4e31375add7bb49fb05bc
Wed Sep 05 20:02:38 build info: windows sys.getwindowsversion(major=6, minor=1, build=7601, platform=2, service_pack='Service Pack 1') BOOST_LIB_VERSI
ON=1_42
Wed Sep 05 20:02:38 SyncClusterConnection connecting to [localhost:20000]
Wed Sep 05 20:02:38 SyncClusterConnection connecting to [localhost:20001]
Wed Sep 05 20:02:38 SyncClusterConnection connecting to [localhost:20002]

这里需要注意的是,这3个配置服务器初始内容得一致(刚开始要同为空),否则无法再这3个服务器上启动路由服务。多个配置服务器为维护集群状态的一致性,其数据同步没有采用前面所讲的异步复制机制,而是采用了更加严谨的两步提交机制(关系型数据库的分布式事务的机制),这就意味着,如果这3台配置服务器有一台宕掉的话,这个集群系统的配置信息将是只读的(写操作都会因为一台无法进行而回滚);客户端仍然可以读写数据信息,但写入的数据不会进行片之间的均衡分配,只会保存在某一片上。

(二)多个mongos路由服务器,mongos的数量是不受限制的!但建议一个MongoDB集群系统只需一个mongos进程即可(这点,我还需考证,生产环境中没使用过,也请使用过的给点点评)。

(三)采用副本集做“片”!这是生产环境中必须的!一个片中一台机器出问题了,不能导致整个片的失效!我们将一个副本集加入到集群中的方法和将当个mongod服务加入集群的方法是一致的。使用addshard命令,这里我们要指定副本集的名称和活跃节点即可:db.runCommand("addshard" : "yy/test.example.com:27017"),我们副本集的名称为“yy”,目前的活跃节点为:“test.example.com:27017”。

生产环境中,我们必须谨记:不可把所有鸡蛋放在同一个篮子里!如上面我们提到的,不能把所有的配置服务器放到一个服务器上,不能把一个副本集放到一个服务器上。