本文从以下几个方面对MongoDB进行介绍

一、分片键组件

二、分片键

三、哈希分片

四、范围分片

五、区间

六、分片部署实例

 

Sharding概述

是分片、或者分区的意思。分片是一个数据库架构,可以通过key 范围拆分数据并且把拆分后的数据分散的存储到两个或多个数据库实例。分片提供了水平扩展的功能。

MongoDB使用分片来支持超大数据集和高操作性能的部署要求。我们可以使用两种方法来支持数据量的大量增加和高性能操作要求:垂直扩展和水平扩展

1、垂直扩展:

通常是增加单机容量,例如、使用性能更高的CPU、增加内存、增加硬盘存储空间。

2、水平扩展(mongodb使用sharding来支持水平扩展):

通常是将数据集进行分割,并将其分布到过个服务器上。通过增加额外的服务器来增加性能、容量的需求。因为每个机器只负责处理所有工作量的一个子集,其中的每一台机器都不会要求特别高的容量和性能,这提供了比高配置的单机服务器更高的数据处理效率。面对部署集性能的扩展需求,只需要增加额外的服务器节点即可,这比使用高端硬件的单机服务器花费更低的成本。

3、分片集群

Mongodb分片集群由以下组件构成:

Shard:每一个分片都包含分片数据的一个子集。每一个分片可以被部署为一个复本集。

Mongos:扮演一个查询路由的角色,在客户端程序和分片集群之间提供了一个路由接口。

Config servers:存储了集群的元数据和配置设置。Mongodb3.4开始,config servers必须要部署为一个复制集。

下图描述了分片集群中各组件之间的相互作用:

 

mongodb 分配账号 mongodb 分区_服务器

MongoDB把数据在表(collection)级别进行分区,将表数据分布到集群的各个分片上面。

4、分片键(shard key)

为了在collection中分布documents,MongoDB使用shard key来分割collection。在目标collection中,分片键由每个document中存在的不可变域(字段)组成。

当对一个collection进行分片的时候选择使用分片键。在分片之后,分片键是不可更改的。一个分片的collection只能有一个分片键。

对一个非空collection做分片,collection必须要设置一个由分片键开始的索引。对一个空的collection做分片,如果collection没有一个可用于分片键的合适的索引,mongodb会创建这个索引。

分片键的选择会影响分片集群的性能、效率和可扩展性。一个拥有高配置硬件环境和基础设施的集群可能会因为分片键的选择而出现较大的瓶颈。

5、Chunks

Mongodb会把分片数据分割成块。每一个块。。。。。。

Mongodb在分片集群中使用分片集群平衡器在多个分片之间进行chunks的迁移。平衡器会尝试在集群中所有分片之间保持chunks的对等与平衡。

注:平衡器是在后台运行的程序,用于管理每一个分片上chunks的数量。

6、分片的优势

读/写

MongoDB把读写工作量分布到集群中的多个分片上,允许每一个分片处理一个集群操作的子集。读/写工作量都可以通过在集群中增加更多的分片来实现水平方向的扩展。

存储容量

集群中的每一个分片包含集群数据总量的一个子集。当数据量增长的时候,额外的分片可以提升集群的数据存储容量。

高可用性

即使一个或者多个分片出现故障而不可用,分片集群仍然可以执行部分的读写操作。虽然,宕机期间故障分片上包含的数据子集是不可访问的,但是指向其它可用分片上的读写操作仍然可以成功执行。

Mongodb3.2开始,可以把config servers(配置服务器,存储分片集群的相关元数据及配置信息)部署为副本集。只要config servers的大部分副本可用,分片集群就可以继续进行读写操作的处理。MongoDB3.4开始,不再支持SCCC(Sync Config Connection Config),仅仅支持CSRS(Config Server Replication Set)。

在生产环境中,每一个单独的分片都应该被部署为一个副本集,以保证数据的冗余和可用性。

分片部署之前应该考虑的问题

分片集群基础设施需要和复杂性要求精心的计划、执行和维护。

在选择分片键的时候需要做一个仔细的考虑,因为这会直接影响集群的性能和效率。在分片设置之后就不能再改变分片键,你也不能取消已经分片的collection。

分片具有一个确切的操作要求和限制。

如果查询不包含分片键或者复合分片键的前缀,mongos会执行一个广播操作,将在集群中的所有分片进行查询。这种分散性的查询操作会具有一个过长的运行时间。

7、分片collection和非分片collection

一个数据库可以同时拥有分片collection和非分片collection。分片集合被分割到集群中的多个分片上,非分片集合只存储在主分片节点。每一个数据库都有自己的主分片。

mongodb 分配账号 mongodb 分区_数据库_02

 

8、连接一个分片集群

我们必须先连接到mongos路由,在通过路由来和分片集群中的collection进行数据交互。客户端千万不要直接连接到一个单独的分片来执行读写操作。

 

mongodb 分配账号 mongodb 分区_数据_03

我们可以像连接到mongod一样连接到mongos。例如通过mongo shell或者mongodb driver。

9、分片策略

MongoDB支持两种将数据分布到集群各个分片上的分片策略。

1 Hashed sharding(哈希分片)

哈希分片会根据分片键的值计算出一个哈希值。之后每一个chunk(数据块)都被分配到基于分片键哈希值的一个范围。

当使用哈希索引解析查询时,mongodb会自动计算哈希值。

 

mongodb 分配账号 mongodb 分区_服务器_04

有一些分片键可能是“靠近的”,他们的哈希值不太可能在同一个chunk。基于哈希的数据分配可以帮助更加均匀的分配数据,特别是在那些分片键单调改变的数据集中。

但是,哈希分配意味着,分片键上基于范围的查询指向一个单独分片的可能性会更小。导致集群进行广泛的广播操作()。

2 ranged sharding

范围分片是将数据分割成基于分片键值的一个范围。每一个chunk被分配到基于分片键值的一个范围。

 

mongodb 分配账号 mongodb 分区_mongodb 分配账号_05

一些值是相近的“分片键”更可能驻留在相同的chunk上。这允许targeted operations(定向操作)因为mongos只会把操作路由到包含所需数据的分片。

10、分片集群中的区间(Zones in sharded clusters)

在分片集群中,基于分片键(shard key)你可以为分片数据创建区域(一组documents)。在集群中,可以将一个区域和一个或多个分片相互关联。一个分片也可以和多个不相互冲突的zones相关联。在一个平衡的集群中,MongoDB仅仅会在与zone相关联的分片中,迁移被zone所包含的chunks。

每一个区域都会包含一个或多个分片键值区域。每一个zone中所包含的范围总是包括它的下界、不包括它的上界。就是[ 1 , 10 ) :  1<=range<10

 

mongodb 分配账号 mongodb 分区_数据_06

 

如果在zone中定义一个新的范围,必须使用包含在分片键里的域。如果使用混合分片键,那么这个范围必须要包含分片键的前缀。

在选择分片键的时候,要仔细考虑未来使用区域分片的可能性,因为在collection分片之后就不可以再更改分片键了。

Collations in sharding(分片中的字符串比对规则)

使用带有 collation:{locale:”simple”} 选项的shardCollection命令对一个具有默认比对规则的collection做分片。成功的分片又以下要求:

1.collection必须拥有一个前缀是分片键的索引。

2.索引必须具有{ locale : “simple” }比对规则。

若使用比对规则创建了collection,在分片collection之前要确保满足之前的条件。

 

一、分片集群组件

生产环境部署

在一个生产部署环境下,要确保数据的冗余和系统的高可用性。参考以下分片集群生产部署方案:

1 把配置服务器部署为3节点的复制集。

2 把每个分片部署为3节点的复制集

3 部署一个或多个mongos路由

在可能的情况下,在一个适合作为灾难恢复的地点为每一个复制集中部署一个节点。

分片集群要求至少要把数据分布到两个分片上。如果计划在未来需要的时候启动一个分片,但是在部署时并不需要此分片,这时候我们可以部署一个单分片的分片集群。

可以为每一个应用服务器部署一个mongos路由来确保每个服务器都可以始终如一的访问分片集群。可选的,也可以在应用程序和mongos组中间部署一组mongos路由,并且使用一个代理或者负载平衡器。

开发环境部署

如果只是用于测试和开发,可以部署一个具有最小数量组件的分片集群。参考以下开发环境部署:

1 具有一个成员的配置服务器复制集

2 至少一个配置为单节点复制集的分片

3 一个mongos实例

 

分片

所有的分片在一起组成了集群的整个数据集。

用户、客户端、应用程序都应该只连接到一个单独的分片来执行本地管理和维护操作。

在单独分片上的查询只会返回数据的一个子集。要连接到mongos才能执行集群级别的查询(包括读、写操作)。

注:mongodb不能保证两个连续的chunks会驻留在同一个分片上。

1 主分片

分片集群上的每一个数据库都有一个主分片,主分片持有了所有没有分片的collection。主分片和复制集中的主节点没有任何关系。

在创建一个新的数据库的时候,Mongos通过选择集群中具有最小数据量的那个分片作为主分片。Mongos使用由listDatabase 命令返回的totalSize域作为选择标准的一部分。

    

mongodb 分配账号 mongodb 分区_服务器_07

使用movePrimary命令来改变数据库的主分片。主分片的迁移过程可能会话费大量的时间才能完成,在处理完成之前都不应该访问collection中的数据。

当使用之前部署为复制集的服务器来作为分片配置为分片集群的时候,所有之前存在的数据都继续驻留在之前所在的位置。接下来创建的数据库可能驻留在集群上的任何一个分片上。

2 分片状态

在mongo shell中使用sh.status()方法查看集群的信息报告。这个报告包含:哪个分片是主分片、chunk(数据库)在所有分片上的分布。

分片集群安全

可以使用内部认证来阻止没有通过认证的组件进入集群。

分片的本地用户

每个分片都支持role-baseed access control,从而限制weigh未认证的用户访问分片数据(通过--auth选项来开启)。另外,也可以使用Internal authentication(内部认证)来进行访问控制。

每个分片都有其自己的本地分片用户。这些用户不能用于其它分片,也不能用于通过mongos来连接分片集群。

 

配置服务器(metadata)

存储分片集群的元数据。元数据包含所有集群中数据和组件的状态和阻止形式,包含了每一个分片上的chunks列表和定义在chunk里的范围。

Mongos缓存这些数据,并且用它们把读写操作路由到正确的分片上。当集群的元数据由于chunk分裂、新增分片而发生改变时,mondos也会更新想这些缓存。

配置服务器也会存储权限配置信息(如,基于角色的访问控制、内部认证)。

MongoDB也会使用配置服务器来管理分布式锁。

配置服务器复制集

MongoDB3.2开始,使用配置服务器复制集来提高一致性,因为MongoDB可以采取标准配置服务器复制集读写协议。另外,可以使分片集群可以有3个以上的配置服务器,因为每一个复制集都可以最多配置50个。要将配置服务器部署为复制集,必须使用WireTiger存储引擎。

限制:

1 不能有arbiters成员

2 不能有延时成员

3 必须构建索引

配置服务器上的读写操作

1 写

Admin数据库包含了与认证、授权相关的colletion,另外还有一些用于内部使用的system.* colletion。

Config数据库中的collection包含了分片集群的元数据。当metadata变化时,mongodb向config数据库写入数据。

在正常数据库操作和维护的过程中,用户不要直接向config数据库直接写入数据。

当对config进行写入时,mongodb使用majority级别的写入确认(write concern)

2 读

MongoDB从admin数据库读认证、授权数据和其它内部使用的数据。

当启动mongos或者metadata改变之后,MongoDB都会从config数据库读数据。分片也会从config服务器读取数据库元数据。

读数据的时候,会使用majority级别的read concern。

配置服务器可用性

如果配置服务器丢失了主节点,并且无法成功选举一个新的主节点,集群元数据变成只读模式。这时,仍然可以对分片进行读写,但是不可以进行chunk的迁移、分割。如果所有的配置服务器都不可以,集群也是不可操作的。

Mongos缓存了配置服务器的元数据。所有配置服务器不可用的时候,如果mongos实例没有重启,仍然可以使用集群,直到配置服务器回恢复使用。如果重启了mongos,mongos将不能再对读写进行路由操作。

没有元数据,集群就是不可操作的。保证配置服务器的完整、可用、备份是非常重要的。与存储在集群分片上的其它数据相比,配置服务器数据量很小,而且具有相对更低的活动负载。

分片集群元数据

访问config数据库,需要连接mongos实例,然后使用:

Use config

通常情况下,不应该对config服务器中的数据进行直接的更改。Config数据库包含的collections:

changelog
chunks
collections
databases
lockpings
locks
mongos
settings
shards
Version

分片集群的安全性

使用内部认证来设置集群内的安全,防止未授权的集群组件访问集群。为了设置内部认证,必须启动集群中的每一个mongod并且进行合适的安全设置。

路由(mongos)

Mongos负责将查询和写操作路由到一个分片上。从应用程序看来mongos只提供了到分片集群的接口。

Mongos通过使用缓存的metadata来追踪哪些数据在哪一个分片上。

最常见的做法是和应用程序服务器同一个系统上运行mongos实例,而在其它专用服务器或者分片上来维护mongos实例。

路由和结果处理

路由查询步骤

1 确定必须接收查询的分片列表。

2 在所有目标分片上建立一个指针。

Mongos从每一个目标分片中合并数据并返回document。像sorting等这样的查询修饰符,会在monogos实例检索结果之前,在一个分片上先执行查询过滤。

从3.2版本开始,如果操作不要求在主分片上执行,在多个分片上运行聚合操作的时候,这些操作可以将结果路由到任何分片以合并结果,并避免重载该数据的主分片。

当查询包含分片键或者分片键的前缀,mongos会执行目标操作(将查询路由到集群的分片子集)。

对于不包含分片键的查询,mongos执行一个广播查询(到所有的分片检索数据)。但是,有些包含分片键的查询仍然会进行广播式查询,这取决于数据在集群中的分布和查询的选择性。

Mongos如何处理查询修饰符

1 sorting

如果使用sort()指针函数,则主分片会合并据结果并对其进行sort排序,最后通过mongos将数据返回给客户端。

2 limits

Mongos将limit发送给所有分片,在将数据返回给客户端之前,对结果集重新执行limit。

3 skips

Mongos不会将skip参数发送给分片,而是从分片上检索未经跳过的结果,在结果全部组合后再跳过指定数量的documents。

但是,当skip和limit一起使用的时候,mongos会将它们一起发送给分片,用以提高操作的执行效率。

 

确认连接到mongos实例

使用isMaster命令来确定是否连接到mongoss。例如:

{
   "ismaster" : true,
   "msg" : "isdbgrid",
   "maxBsonObjectSize" : 16777216,
   "ok" : 1
}

如果连接到mongodd,返回结果里不会有isdbgrid这个字符串。

查询隔离

通常,分片环境中最快速的查询是:使用分片键和来自config server的元数据,将操作路由到一个单独的分片上。这些目标操作使用分片键来定位满足查询要求的documents所在的分片或者分片子集。

不包含分片键的查询必须查询所有分片,这是一种比较耗时的操作。

1 广播操作

Mongos对所有分片上的collection进行广播查询。除非其可以确定哪一个或几个分片储存了要查询的数据。

    

mongodb 分配账号 mongodb 分区_服务器_08

一旦mongos收到所有分片的相应,它会合并数据并返回结果documents。 广播操作的性能取决于集群的总体负载,以及网络延迟、单个分片负载和每个分片返回的文档数量等变量。 只要有可能,都有利于有针对性地进行广播操作的操作。

多更新操作(updateMany() 、deleteMany())总是执行广播操作

尽可能的使用可以出发目标操作的操作,而不是导致广播操作的操作。

2 目标操作

Mongos使用分片键值来定位chunk(它的范围包括分片键值)并把查询指向抱哈chunk的分片。

    

mongodb 分配账号 mongodb 分区_mongodb 分配账号_09

例如,分片键如下:

{ a: 1, b: 1, c: 1 }
Mongos会把包含完整分片键或者如下所示的分片键前缀的查询路由到一个指定的分片或者分片子集:
{ a: 1 }
{ a: 1, b: 1 }
所有的insertOne()会指向一个分片。insertMany()的每一个document数组会指向一个单独的分片,但是不能保证数组中的所有documents都插入到一个分片中。
所有updateOne()、replaceOne()、deleteOne()操作必须包含分片键或者_id。否则MongoDB会返回错误。
Depending on the distribution of data in the cluster and the selectivity of the query, mongosmay still perform a broadcast operation to fulfill these queries.

3 索引使用

如果查询不包含分片键,mongos会将查询发送到所有分片。相应的,每一个分片会使用分片键索引或者其它更有效的索引来完成查询。

如果查询包含由分片键和辅助索引索引的字段的多个子表达式,则可以将查询路由到特定的分片,并且分片将使用能够最有效地执行的索引。

分片集群安全性(RBAC和内部认证机制)

 

二、分片键

分片键确定集合中documents的分布。分片键是存在于集合中每个文档的索引字段或者索引的复合字段。

MongDB键值的范围对集合中的数据进行分区。 每个范围定义了不重叠的分片键值范围,并与一个块相关联。

MongoDB尝试在群集中的碎片之间均匀分配块。 分片键与块分布的有效性有直接的关系。

 

mongodb 分配账号 mongodb 分区_mongodb 分配账号_10

一旦分割了一个集合,分片键和分片键值是不可变的;即

您不能为该集合选择不同的分片键。

您不能更新分片键字段的值。

分片键规格

要分割一个集合,必须为sh.shardCollection()方法指定目标集合和分片键:

Sh.shardCollection(namespance,key)

Namespace参数有字符串<database>.<collection>来指定。

Key参数由一个包含该字段的文档和该字段的索引遍历方向组成。

分片键索引

所有分片的集合必须具有一个支持分片键的索引;即索引可以是分片键上的索引或分片键是索引的前缀的复合索引。

如果集合为空,则sh.shardCollection()在分片键上创建索引,因为此索引尚不存在。

如果集合不为空,则必须先使用sh.shardCollection()创建索引。

如果删除分片键的最后一个有效索引,则通过在分片键上重新创建索引进行恢复。

1、唯一索引

对于分片集合,只有_id字段索引和分片键上的索引或分片键是前缀的复合索引可以是唯一的:

1 您不能在其他字段上分割具有唯一索引的集合。

2 您无法在分片集合的其他字段上创建唯一索引。

通过使用分片键上的唯一索引,MongoDB可以在分片键值上强制执行唯一性。 MongoDB在整个组合键上强制执行唯一性,而不是分片键的单个组件。 要在分片键值上强制执行唯一性,请将唯一参数作为true传递给sh.shardCollection()方法:

1 如果集合为空,这样的索引页不存在,sh.shardCollection()则在分片键上创建唯一的索引。

2 如果集合不为空,则必须先使用sh.shardCollection()创建索引。

虽然您可以使用分片键是前缀的唯一组合索引,如果使用唯一参数,则该集合必须在分片键上具有唯一的索引。

您不能在哈希索引上指定唯一约束。

分片键的选择(影响chunk在集群上的分布)

理想的分片键允许MongoDB在整个集群中均匀分布文档。

 

mongodb 分配账号 mongodb 分区_数据库_11

1、集合大小

当分割不为空的集合时,分片键只能限制初始分片操作支持集合的最大值。

2、分片键基数

分片键的基数决定了平衡器产生chunks的最大值。这会降低或者消除集群的水平扩展效用。

一个唯一分片键值只能存在任意给定的一个chunk里。如果分片键基数为4,那么分片集群中不会超过4个chunks,并且每一个chunk存储了一个唯一分片键的值。这会把有效分片的数量限制为4个,并且扩展额外的分片是没有意义的。

下图,描述了将字段X设置为分片键。如果X基数很小,新数据的插入将如下方式分布到各个分片:

 

mongodb 分配账号 mongodb 分区_mongodb 分配账号_12

上例中的集群不能够水平扩展,因为所有写入操作都会被路由到当前分片的子集。

设置有很高基数的分片键也不能保证数据在分片集群中的均匀分布,但是可以更好的支持水平扩展。分片键的变化频率和比率也会有助于数据的分布。选择分片键的时候要把每个因素都考虑进去。

如果数据模型要求分片键使用一个较小基数,那么考虑使用组合索引,使用一个具有相对较高基数的字段。

分片键频率

考虑一个表示分片键值范围的集合-分片键频率代表给定值在数据中出现的频率。如果大多数documents只包含这些值的一部分,那么存储这些document的块(chunks)将成为集群中的瓶颈。此外,随着这些块 的增长,它们会变得不可分割,因为它们不能再被进一步的分裂。这会降低或者消除集群的水平扩展效用。

下图,描述了将字段X设置为分片键。如果X值的子集以高频的方式发生,则插入数据的分布如下所有:

 

mongodb 分配账号 mongodb 分区_数据_13

分片键的基数和变化率都有助于数据的分布。

如果必须使用分片键的高频值,考虑使用组合索引,并使用唯一索引或者低频值。

单调变化的分片键

单调递增或递减的分片键值更可能导致大部分数据都进入同一个分片。

这是因为,每一集群中都有一个上限为maxKey的块,maxkey比任何值都高。Minkey也类似。

如果,分片键值一直增加,所有新插入的数据都将路由到上限为maxkey的块。同理,一直递减的也是一样。

单调递增分片键值的数据插入,如下图:

 

mongodb 分配账号 mongodb 分区_数据库_14

如果必须使用单调变化的分片键值,考虑使用哈希分片。

 

三、哈希分片

介绍见概述

 

四、范围分片

介绍见概述 

 

五、区域/区间

区间概念见shard概述。

使用三个分片、两个区间的分片集群如下:

 

mongodb 分配账号 mongodb 分区_shell_15

Behavior and Operations

1、Ranges

每个区间包含一个或多个分片键值范围。区间形式:[ )

2、Balancer

在所有分片上均匀的分布数据。

对于每个标记为迁移的chunk,平衡器会检查每个可能目标分片的配置区间。如果chunk的范围落在某个区间内,平衡器会把chunk迁移到这个区间所在的分片。不包含在任何区间内的chunk可能被融合到集群中的任意一个分片。

在为分片集群配置区间,并分配到各个分片之后,集群会花费一些时间来融合受配置影响的数据。这依赖于集群中区块的分割和当前的数据分布。当平衡调整结束之后,所有包含在区间内的读写操作都会被路由到相应的分片上。

3、Shard key

当定义zone的新范围时,必须使用分片键中包含的字段。如果使用复合分片键,则范围必须包含分片键的前缀。

例如,给定一个分片键{a:1,b:2,c:3},创建或更新一个区域来覆盖b的值需要包括a,将a作为前缀。创建或更新区域以覆盖c的值需要包括a和b,将a和b作为前缀。

您不能使用分片键中不存在的字段创建zone。例如,如果要根据地理位置对数据进行分区,则分片键至少需要一个包含地理数据的字段。

为集合选择分片键时,请考虑可能要用于配置区域的字段。分片后,将不能再更改分片键。

4、Hashed shard keys and zones

若使用哈希分片键,zone区间为a :  [ 1 , 5 ) 范围中1代表的是a的哈希值,而不是a的实际值。因此mongodb不能保证将a值在1到5之间的documents查询都路由到分片上的同一个区间。

5、Shard Zone Boundaries

分片区域的范围始终包含下界、不包含上界。

 

六、分片部署实例

待完善 。。。。