本文介绍分片的思想和MongoDB中的实现方法。
首先需要介绍一些基本的概念。


分片

分片,也叫做分区,是一种常用的数据库优化技术。其含义就是将数据拆分,将数据分散到不同机器上的过程。这样就能够使得系统可以存储更多的数据,处于更大的负载。
几乎所有的数据库软件都可以进行手动分片,通过应用程序管理不同服务器上的不同数据,查询也需要寻找正确的服务器。这样虽然可以减轻负载,但是却难以维护,比如我们向集群添加节点或者删除节点,都需要对应的调整数据的分布。
MongoDB在这一点上做得不错,它支持自动分片,集群可以自动切分数据,达到负载均衡,从而使管理人员可以摆脱手动分片。


分片原理

下面说说分片的原理。MongoDB分片的基本思想就是将集合切分成小块,这些块分散到若干片里面,每个片只负责总数据的一部分。
应用程序不需要知道哪些片对应哪些数据,也不需要知道数据是否已经拆分。MongoDB通过另外一个独立的路由进程mongos来实现这个功能。
mongos路由进程知道所有数据的存放位置,所以应用可以连接它来正常发送请求。而对于应用来说,自己只知道连接了一个普通的mongod。也就是说,mongos对应用隐藏了分片的细节
为什么要隐藏了?其实就是为了拓展的时候,不必修改应用程序的代码。

应用场景

说完了原理,那什么时候需要用到分片呢?有以下几种情况:
1. 机器的磁盘不够用了
2. 单个mongodb已经不再满足性能需要
3. 想将大量数据放入内存提高性能

一般来说,先从不分片开始,然后在需要的时候将其转换成分片。

片键

设置分片时,需要从集合里面选一个键,用该键的值作为数据拆分的依据。这个键成为片键
假设有个文档集合表示的是人员,如果选择名字”name”做为片键,第一篇可能会存放名字以A-F开头的文档;第二片存G-P开头的文档;第三篇存Q-Z的文档。
随着增加或删除片,MongoDB会重新平衡数据,使得每片的流量比较均衡,数据量也在合理范围内。

那么我们应该如何选择片键呢?
如果我们选择了时间属性的键作为片键,那么随着时间增长,所有的文档都会以最后一片插入。这就不适合写入操作负载很高的情况,但是查询起来就比较方便。
如果我们选择了分布均匀的片键,就会提高写入操作的负载能力,但是就会影响查询的性能。
我们也可以选择复合片键,将两个属性键结合为一个片键。
其实和索引的原理相似,事实上,片键也是最常用的索引。

说了半天的概率,也累了,下面看看实际操作吧。


建立分片

建立分片有两步:启动服务器,然后决定怎么切分数据。
分片一般由三个部分组成:
1.
片就是保存子集合数据的容器,片可以是单个mongod服务器,也可以是副本集。
2. mongos
路由进程,它接收所有的请求,然后将结果聚合,它本身并不存储数据或者配置信息,但是会缓存配置服务器的信息。
3. 配置服务器
存储集群的配置信息:数据和片的对应关系。配置服务器是帮mongos存放分片的配置信息的,mongos自己不存放数据,直接同步配置服务器中数据即可。

下面介绍详细过程:

首先要启动配置服务器和mongos。
配置服务器需要先启动,因为mongos会用到其上的配置信息。


第一步,启动配置服务器

配置服务器的启动就像普通的mongod一样:

mongod – config d:\mongodb\mongo.config --port 20000

mongodb分片服务器数量 mongodb数据库分片_服务器


第二步,建立mongos进程

建立mongos进程,以供应用程序连接。这种路由服务器连接数据目录都不需要,但一定要指明配置服务器的位置:

mongos --port 30000 --configdb 127.0.0.1:20000

mongodb分片服务器数量 mongodb数据库分片_数据库_02

分片管理通常是通过mongos完成的,完成后效果如下:

mongodb分片服务器数量 mongodb数据库分片_服务器_03


第三步,添加片

添加片,片就是普通的mongod:

mongodb分片服务器数量 mongodb数据库分片_mongodb_04


mongodb分片服务器数量 mongodb数据库分片_mongodb分片服务器数量_05


连接刚才启动的mongos,为集群添加一个片。

启动shell,连接mongos:

确定连接的是mongos而不是mongod,通过addshard命令添加片:

>mongo 127.0.0.1:30000
mongos> use admin
switched to db admin
mongos> db.runCommand(
... {
... "addshard":"127.0.0.1:10000",
... "allowLocal":1
... }
... )
{ "shardAdded" : "shard0000", "ok" : 1 }
mongos> db.runCommand(
... {
... "addshard":"127.0.0.1:10001",
... "allowLocal":1
... }
... )
{ "shardAdded" : "shard0001", "ok" : 1 }

mongodb分片服务器数量 mongodb数据库分片_mongodb_06


mongodb分片服务器数量 mongodb数据库分片_服务器_07


mongodb分片服务器数量 mongodb数据库分片_数据库_08

当在本机运行片的时候,得设定allowLocal键为true。MongoDB尽量避免由于错误的配置,将集群配置到本地,所以得让它知道这仅仅是开发,而且我们很清楚自己在做什么。
如果是生产环境中,则要将其部署在不同的机器上。
想添加片的时候,就运行addshard,MongoDB会负责将片集成到集群


第四步,切分数据

MongoDB不会将存储的每一条数据都直接发布,得先在数据库和集合的级别将分片功能打开。
如果是连接配置服务器,

E:\mongo\bin>mongo 127.0.0.1:20000
MongoDB shell version: 2.0.6
connecting to: 127.0.0.1:20000/test
> use admin
switched to db admin
> db.runCommand({"enablesharding":"test"})
{
"errmsg" : "no such cmd: enablesharding",
"bad cmd" : {
"enablesharding" : "test"
},
"ok" : 0
}

mongodb分片服务器数量 mongodb数据库分片_服务器_09

应该是连接路由服务器,

db.runCommand({"enablesharding":"test"})//将test数据库启用分片功能.

对数据库分片后,其内部的集合便会存储到不同的片上,同时也是对这些集合分片的前置条件。
在数据库级别启用了分片以后,就可以使用shardcollection命令堆积和进行分片:

db.runCommand({"shardcollection":"test.refactor","key":{"name":1}})//对test数据库的lf集合进行分片,片键是name

如果现在对lf集合添加数据,就会依据”name”的值自动分散到各个片上。

这样分片就建立完成啦!


管理分片

分片建立完成后,如何管理分片呢?
分片信息主要存放在config数据库上,这样就能被任何连接到mongos的进程访问到了。
在shell中连接了mongos,并使用了use config数据库。

查看分片

通过db.shards.find()方法:

mongodb分片服务器数量 mongodb数据库分片_数据_10

查看状态

db.printShardingStatus()

mongodb分片服务器数量 mongodb数据库分片_数据_11

删除分片

db.runCommand({"removeshard":"127.0.0.1:10001"})