零、使用经验

问题一:对于一个后续肯定会扩容的分片集群。建议最开始分片数多点后续主要扩机器配置?还是最开始机器配置好点后续主要扩分片?

答:初始分片多点。原因如下:

①纵向扩容相对于横向扩容肯定是更容易的,而且很有可能避免数据的搬迁。如果后续扩分片的话数据搬迁不可避免。

②分片键合理的话,数据写入被均衡到更多的分片上(机器上),集群整体读写性能更优。

③单个分片内的数据少,遇到故障时(机器故障)的回复时间也相对短一些,备份/回档等维护操作也能更充分的利用分片间的并发。

一、mongodb分片与各角色与概念介绍

1、Mongodb的分片机制是mongodb数据库的核心机制,也是其可用性高,扩展性好的原因,分片—sharding 的意思就是将数据库数据分散存贮到不同的服务器上,来缓解高并发访问,均衡负载。 举例来说一下,比如说一个collection有TB级别的数据,在传统方式下如果有两个线程要访问其中的数据,即使这个线程访问的数据是不同的,为保证同步需要排队等待,分片机制可以很好的解决这个问题,分片机制其实就是分布式的集群,比如现在有五台服务器作为集群,mongodb可以将一个collection的数据分割成5个片---chunk 分别存放到5个server并且mongodb还会记录下每一条数据的位置,这样一来当用户访问集合里面的文档时,mongodb可以根据请求条件来查找到对应数据所在的服务器然后返回数据,这样下来可以将多请求的负责分摊到各个服务器的分片上,大大提高数据库系统的吞吐量。

注意:MongoDB在集合维度进行数据的分片,即将集合的数据分布到集群的不同分片上。参见官网

MongoDB shards data at the collection level, distributing the collection data across the shards in the cluster.

关于分片和副本集的含义就是下面这两句话。我们接下来重点看看关于mongodb分片的其他知识。

分片:一份数据被分开保存在N台机器上,N个机器上的数据组合起来是一份数据。

副本集:同一份数据被保存在N台机器上,每台机器上都有一份数据。

2、分片的优点:Sharding — MongoDB Manual

这里相当于是从各个维度在罗列一下,主要还是参考官网。

(1)读写方面。①读写的水平扩展。分片之后mongodb就可以分布这些读写的负载到集群中的不同分片,允许每一个分片去处理集群操作的一个子集。这样不管是读负载还是写负载都可以通过添加更多的分片来实现水平扩展。②读写的针对性路由。对于包含分片键或者复合分片键前缀的查询,mongos可以将查询直接路由到指定的分片或者一组分片上,这种针对性的操作通常是比向集群中每个分片进行广播请求要高效得多。

(2)存储能力。通过分片可以将数据分布在整个集群,这样每个分片只包含整个集群数据的一个子集。随着数据集的增长,通过新增分片就可以加大集群的存储能力。

(3)高可用。Config Server和分片作为副本集的部署提供了更高的可用性。即使一个或多个分片副本集变得完全不可用,分片集群也可以继续执行部分读写。也就是说,虽然无法访问不可用分片上的数据,但针对可用分片的读写仍然可以成功。

3、分片前需要考虑的点:Sharding — MongoDB Manual

(1)分片集群的复杂性要求使用方需要仔细的规划和维护;——维护复杂。

(2)一旦一个集合被shard后,mongodb没有办法对一个sharded集合进行unshard操作;——操作不可逆。

  注:MongoDB5.0支持在业务运行的情况下,通过reshardCollection命令按需更改集合的分片键(Shard key)。整个过程数据库服务无需停机或进行复杂的迁移,操作简单高效。reshardCollection — MongoDB Manual

(3)为了保证集群的性能和效率,分片键的选择需要慎重,可以参见 如何选择分片键 ;——仔细选择分片键。

(4)分片有一定的操作要求和限制,这里 有分片集群的一些操作限制;——分片后有些功能会受限。(验证下

(5)4.4及之后才支持多字段作为分片键,之前版本都仅支持单字段用做分片键。这里  腾讯云到目前为止还只是支持到4.2版本,唉!!

唯一索引(Unique Indexes)之于分片集群:MongoDB不支持跨分片的唯一索引,除非唯一索引包含完整的分片键作为索引的前缀。这种情况下,mongodb将强制整个key的唯一性,而不是单个字段。

举个例子:如果kfuin被用作分片键那么要求必须要建立一个( { kfuin: 1, unique_id: 1}, { unique: true } )的复合字段唯一索引。验证ing

注:如果是两个字段的唯一索引,这个索引也是能加速搜索性能的(很好理解)。

例如{key:1,subkey:1},{unique:true}即能用于保证唯一性,也能用于db.coll_0.find({key:"aaa",subkey:"bbb"})

(5)如果查询操作不包括分片键或复合分片键的前缀,mongos将执行广播操作,查询shard集群中的所有shard。这些分散/聚集查询可以是长时间运行的操作;——查询要包括分片键。(验证下

如果分片了,该怎么查数据了呢?

关于第四点比较重要,有必要测一下看看实际效果。

测试一:

#首先往shardtest集合中插入一条数据()
db.shardtest.insert({"unique_id":"11111111", "name" : "shuozhuo", "age" : 28, "gender" : "female", "friend" : "null"})

#查看一下这个集合是没有分片的
db.shardtest.stats().sharded

#查看一下索引是只有默认的_id索引
db.shardtest.getIndexes()

#这个时候我们对unique_id字段创建唯一索引是ok的
db.shardtest.createIndex({"unique_id":1},{unique:true})

#查看一下果然有我们新建的唯一索引
db.shardtest.getIndexes()

#先删除这个唯一索引
db.shardtest.dropIndex("unique_id_1")

#check下确实删掉了
db.shardtest.getIndexes()

#然后我们跳转到admin数据库对上面shardtest库表以_id为分片键进行了范围分片
db.runCommand({shardcollection: "db_msg_track.shardtest", key: { _id: 1}})

#check一下这个时候确实为true了
db.shardtest.stats().sharded

#这个时候再尝试对unique_id字段创建唯一索引发现不行了.截图如下:
db.shardtest.createIndex({"unique_id":1},{unique:true})

测试二:然后我们drop掉这个shardtest集合,然后以unique_id字段作为分片键重新测试下发现就实现了我们想要的效果了。

注意:执行分片指令前要对分片键字段创建索引(注:_id不用创建是因为已经有了)。这里直接就对unique_id字段创建了唯一索引:db.shardtest.createIndex({"unique_id":1},{unique:true})。

也就是说能够达到预期效果(以unique_id作为唯一键同时作为分片的分片键)的流程是:首先对shardtest集合的unique_id字段创建了唯一索引,然后我们再以unique_id为分片键对shardtest这个集合进行分片。

测试三:能不能投机取巧一波。即先创建关于unique_id字段的唯一索引,然后我们再以_id作为分片键来进行分片。

结果:显然是不行的。而且告诉你“不能够以被用于唯一索引的字段作为分片键,唯一性不能够保持,除非分片键是前缀。”

4、首先看一下mongodb分片集合的一张示意图:

   

  关于以上各个角色介绍如下:     

(1)Client:最上面的小人就是客户端。对于客户端来说你数据库分不分片和我没关系,我只关心存取数据别的没什么好说的。

(2)mongos:即最上面的Router,mongos作为分片集群的入口所有的请求都由mongos来路由、分发、合并,这些动作对客户端驱动都是透明的。用户连接mongos就像是连接mongod一样使用。mongos通过缓存config server里面的元数据(metadata)确定每个分片有哪些数据,然后将读写请求分发到相应的某个或者某些shard。

1)mongos的数量与部署。

①为保证集群的高可用,在集群中一般不只一个mongos入口。②一种常用的模式是在每个应用服务器上部署一个mongos;这样可以减少应用程序和Router之言的网络延迟 ③另外还有一种更适应于大型集群的模式。 即将mongos router放到专用的主机上,这样带来的好处是可以将应用服务器的数量与mongos实例的数量分离,进而可以更好的控制mongod实例所服务的连接数。④一般来讲集群中的mongos数量没有什么数量上的限制。但是由于mongos经常会与Config Severs通信,因此在增加路由服务mongos的时候应该密切关注Config Servers的性能。如果发现性能有明显下降,在集群中适当限制mongos的数量可能是有益的。

注:mongos应该是只有分片集群才会有的,一个普通的不分片的数据库实例客户端会直接连上mongod即可。

(3)Config Servers:配置服务器是保存集群中元信息的特殊mongod。换句话说就是给路由器(mongos)提供分片线索(理解为不同分片的索引表)。mongos通过查询configserver就知道当前存取的数据究竟在哪个或哪些分片(shard),然后直接去访问对应的shard就好了。

从3.4开始config server必须部署为一个副本集。

(4)mongod:一个服务器上的mongodb数据库实例通常我们称为mongod,在分片集群中一个mongod其实就对应一个分片(shard).

(5)Shard:数据库真正的数据就存放于shard上面,在分片集群中一个分片(shard)可以是一个单独的mongod或者一个副本集(replica set)。

1)注意mongos和mongod之间的关系,这是两个不同的入口。mongos可以统筹管理集群中的所有数据,mongod则是代表了“当前”数据库。举个例子,对于一个有5个服务器的mongo集群,通过mongos入口可以访问5个服务器的全部数据,通过mongod则只能访问到当前服务器的数据。

2)注意mongos路由不止一个。原因很简单,一个高可用的分布式集群方案必须保证服务时刻都可以正常高效运行,这里配置多个同样的mongos路由是为了预防当前路由出现故障而备用的。同样configserver也需要完全相同的副本分布在不同的服务器上;shard也一样可以设置多副本。

3)在生产环境中所有的分片都应该是一个副本集(Replica Set).

二、几个重要概念

1、chunk(块) —— 参见 这里

(1)对于一个shard mongodb也将数据划分成了更小的chunk()。每个chunk都唯一独占分片键的某段范围,片键值落在这个范围的文档也就落在这个chunk上。

①mongodb会把片键的值(或者hash过后的片键值)分割成互不重叠的若干个区段,每个区段都对应一个chunk。②mongodb会尽可能的把这些chunk均分到集群的不同shards中。③一个chunk默认的大小是64M,其范围在1-1024M之间,用户是可以设置的,不过不推荐。④mongodb会对超过配置大小的chunk进行分割,插入和更新操作都有可能触发chunk分割。

(2)用户可以设置chunk的大小,但是不推荐这么做。

MongoDB 允许你对 chunk 的大小进行设置,你也可以把一个 chunk 切分成若干个小 chunk,或者合并多个 chunk。一般不建议手动操作 chunk 的大小或者在 mongos 层面切分或合并 chunk。原因主要是两点:①在数据不断插入到我们的集群中时,mongodb 中的 chunk 大小会发生很大的变化。当一个 chunk 的大小超过了最大值,mongo 会根据 shard key 对 chunk 进行切分,必要时一个 chunk 可能会被切分成两个甚至多个小 chunk。大多数情况下这种自动行为已经满足了我们日常的业务需求,无需进行手动操作。②另一点原因是当进行 chunk 切分后,直接的结果会导致数据分配的不均匀,此时 balancer 会被调用来进行数据重新分配,很多时候这个操作会运行很长时间,对负载和性能都有一定程序的影响

(3)chunk 是 MongoDB 在多个 shard 集群中迁移数据的最小单元。

Balancer(均衡器)会在数据分配不均匀的时候自动运行。Balancer 是如何决定什么情况下需要进行数据迁移呢?答案是 Migration Thresholds,当 chunk 的数量在不同 shard replica 之间超过一个定值时,balancer 会自动运行,这个定值根据你的 shard 数量不同而不同。而chunk就是mongodb在shard间迁移数据的最小单元。

(4)chunk的大小会影响那些东西?

1)如果chunk过小可能会导致chunk数量的激增。他可以保证你的数据均匀的分布在 shard 集群中但是可能会导致频繁的数据迁移。这将加重 mongos 层面上的操作。

2)大的 chunk 会减少数据迁移,减轻网络负担,降低在 mongos 路由层面上的负载,但弊端是有可能导致数据在 shard 集群中分布的不均匀。

(5)块划分(Chunk Splits)

Data Partitioning with Chunks — MongoDB Manual

Spliting是一个防止块(chunk)过大的进程。当块(chunk)增长超过指定的块大小(chunk size)时,或者如果块中的文档数超过上限,MongoDB将根据块表征的分片键值分割块。必要时可以将一个块拆分为多个块。插入和更新可能会触发拆分。Spliting是一种有效的metadata更改。

拆分(Spliting)可能会导致集合的块在分片上的分布不均匀。在这种情况下,均衡器会在分片之间重新分配块(chunk)。有关跨分片平衡的更多详细信息,请参阅群集平衡器。

注:某些情况下即使块的大小已经超过了限制但是依然不能被划分,最常见的场景就是整个chunk只代表了一个shard key(即所有的数据片键值相同),显然这个是无法划分的。那么他就会称为一个Jumbo chunk(大象chunk),随着数据量的增长,这个chunk将会称为性能瓶颈。

这意味着分片键选取的时候要注意分片键取值是否足够的“散”,这一点非常重要!!!

按照一个chunk默认64M、一条数据占用500字节,这意味着一个chunk只能存放13.4万条数据(64M×1024×1024/500=13.4万条数据);也就是说你的分片键单个取值下对应的数据量最好不要超过13.4万条。极端情况偶尔超过貌似也问题不大,但是超过太多就不好了。我们可以通过getShardDistribution()指令查看每个chunk对应的数据量的情况。

db.collection_event_track_986.getShardDistribution()

注:chunk split是写操作触发的!!!!

注:4.4+版本之后也是可以通过设置允许一定jumbo chunk了  这里

2、zones(分区)

我们可以按照 shard key 对数据进行分组,每一组称之为一个 Zone,之后把 Zone 在分配给不同的 Shard 服务器。一个 Shard 可以隶属于一个或多个 Zone,前提是其关联的 Zone 之间没有数据冲突。Balancer 在运行的时候会把在 Zone 里的 chunk 迁移到关联这个 Zone 的 shard 上。

之所以这么做的原因是有时候数据的分配不会按照我们希望的方向进行。有了zone之后我们就可以更加自主地控制数据分配了。

3、MongoDB balancer(mongodb 均衡器)

官网 这里 这里

①Balancer一个监视各个shard上的chunk数的后台进程;②他运行在Config Server副本集的primary节点上③当给定分片上的chunk数达到特定的 migration thresholds(迁移阈值) 时,均衡器会尝试在分片之间自动进行chunk迁移,以使得每个分片上的chunk数“相同”(注:也并非完全的一个不差)。④分片集群的平balance过程对用户和应用程序层都是完全透明的,只不过在执行该过程时可能会对数据库性能产生一些影响。默认情况下balanced进程是一直开启的。

(1)chunk迁移会对数据库性能产生影响

chunk迁移会在带宽和工作负载方面会带来一定的开销,这两方面都会影响数据库性能。均衡器通过以下方式将影响降至最低:1)限制分片在任何给定时间最多只有一个迁移;也就是说一个shard不能同时参与多个块迁移。举个例子:为了从一个shard迁移多个块,均衡器会一次迁移一个块进行多次迁移,而不是多个块同时迁移。2)仅当分片集合中块数最多的分片与该集合中块数最少的分片之间的块数差异达到迁移阈值时,才触发平衡操作。

注:从MongoDB 3.4开始,MongoDB可以执行并行chunk迁移。观察到一个shard一次最多只能参与一次迁移的限制,对于一个有n个shard的shard集群,MongoDB最多可以同时进行n/2(向下舍入)块迁移。

另外用户可以暂时停用平衡器进行维护。有关详细信息,请参阅禁用平衡器。

(2)chunk迁移流程

①平衡器进程将moveChunk命令发送到源分片。
②源分片使用内部moveChunk命令启动移动。在迁移过程中,对于chunk的操作路由到对应的分片。即分片负责外部对于该chunk的写入操作。
③目标分片构建源分片所需的但目标不存在的索引。
④目标分片开始请求chunk中的文档,并开始接收数据的拷贝。另请参见区块迁移和复制。
⑤在接收到chunk中的最终文档后,目标分片将启动同步进程来确保其具有迁移过程中发生的对迁移文档的更改。
⑥完全同步后,源分片将连接到Config Server,并使用chunk的新位置更新集群metadata。
⑦在源分片完成metadata的更新之后,一旦chunk上没有打开的游标,源碎片将删除其文档副本。

(3)迁移阈值。

为了将平衡对集群的影响降至最低,均衡器仅在分片集合的块分布达到特定阈值后才开始平衡。阈值适用于集合中块数最多的碎片与集合中块数最少的碎片之间的块数差异。平衡器具有以下阈值:

当目标集合的任意两个碎片上的块数之差小于2时,或者块迁移失败时,均衡器将停止在该集合上运行。

三、如何分片 

1、片键(shard key)

mongodb使用片键在分片之间分布文档,片键应当由文档中的一个字段或者多字段组成。

从4.4版本开始分片集合中的文档可以缺失(Missing)片键字段。片键字段缺失会被当成null value在分片之间分配文档记录,但是路由查询的时候不会。关于片键字段缺失的更多信息可以参见官网这里

其实在4.2及以前的版本,对于分片集合片键字段必须存在于集合的每个文档中。

译者注:这里的意思应该是说如果文档缺失片键字段的话在4.4及以后版本也是可以的,只不过在数据分片分布的时候这些文档都会被当成一类文档(having null values)被分片;但是路由查询的时候并不会这样。

如何选择好的片键: 这个问题非常重要

MongoDB 分片片键如何选择 – 运维生存时间

建议首先考虑作使用数据文档_id的哈希作为片键。这个方案能够使得读和写都相对平均的分布,并且它能够保证每个文档都有不同的片键所以数据块能够很精细。虽然这样也不能做到完美,因为这样的话对多个文档的查询必将命中所有的分片。虽说如此,这也是一种比较好的方案了。

2、片键索引

为了对一个集合进行分片,集合必须有一个以片键为开头的索引。当对一个空集合进行分片的时候,如果这个集合并没有针对这个片键合适的索引mongodb会创建相应的支持索引。这里 这里

这里 详细的说明了一下规则。大致来讲就是。所有的分片集合都必须有一个支持片键的索引,即可以是一个关于片键字段的索引也可以是一个复合索引但是片键必须是这个复合索引的前缀(prefix)。

3、两种分片方式

Mongodb为我们提供了两种分片方式,分别是 范围分片(Range based sharding)Hash分片(hash based sharding)。如下图分别为范围分片和hash分片,从图中很容易理解中两种分片方式的含义。

  

两种分片方式的优缺点对比:

范围分片(Range based sharding):根据片键值所处的范围将一众数据存储到不同的分片上;实际上在shard内部这些数据又会不同chunk上。chunk存储在哪个shard、每个chunk存储数据范围的信息会存储在config server中。

优点: 提供更高效的范围查询。例如查找x的值在100~200之间的数据,mongos就可以根据config server中存储的元数据直接定位到指定shard的指定chunk,将请求直接转发到响应分片,一步到位。

缺点:数据分布不平衡。 如果片键所在字段是线性的(递增or递减),一定时间内所有请求都会落到某个固定的chunk(亦shard)中。其状况就是一个分片承载了集群几乎所有的数据,并没有起到写扩展的效果。

Hash分片(hash based sharding):对key(片键值)进行hash然后决定其存放于哪个分片,这种方式又称为随机分片。

优点:可以选用任何字段作为hash key理论上讲无论是有序的字段、string,还是自动生成的_id最后的分片效果都很不错,能将数据均匀的分散到各个服务器上。这样就很好的实现了写扩展。

缺点:不能支持高效的范围查询。哈希值的随机性使得数据近乎随机的分布在不同的chunk/shard中,正是由于这种随机性为了返回范围查询的结果需要针对每个值分别请求不同的分片。

总结:总的来说范围分片和hash分片正好是互补的。范围分片支持更高效的范围查询,但存在数据分布不均匀的问题。hash分片则恰恰相反,它以牺牲范围查询为代价保证了数据的均衡。这里要提一下的是范围分片这种数据分布不均衡所带来的问题很有可能会大于其带来的积极作用。

4、分片集合、未分片集合的存储  

mongodb的一个数据库允许分片的集合和不分片的集合混合存在。对于这种情况,分片的集合会按照分片的设置分布在集群的不同的shard中;未分片的集合将会存储在主分片(primary shard)中。每个库都会有一个自己的主分片(primary shard),这个主分片就是用来存储所有未分片集合数据的。这个主分片和副本集里面的主节点没任何关系。  这里  这里

注:也就是说对于从没分片的数据库/集合中的数据实际上都只是存在于主分片中,这相当于是没设置分片情况下的默认状态。

注:“每个db都会有一个自己的主分片”,注意这里是db维度。即不同的db的主分片可能是不同分片主分片的产生过程如下:mongos在创建新数据库时通过在集群中选取数据量最少的shard作为这个数据库(db)的主shard。mongos使用listDatabases命令返回的totalSize字段作为选择条件的一部分。

5、查看信息

(0)查看分片状态(集群维度/实例维度)

#1、全局层面查看分片状态(shard stats);可以看到所有集合的分片情况/balance情况/chunks情况
sh.status()

 

(1)查看数据库的信息(db维度):

#1、查看数据库信息(首先切换到指定db)——如下图左右分片为为分片和已分片的db的查看情况截图。
#可以看到这个db总共的文档数、占用存储、索引数、分片的情况(哪些分片/每个分片的集合数、文档数、索引数、存储)等信息。
db.stats()

db开启分片和未开启分片db.stats()对比: 

  

(2)查看集合是否分片(集合维度):

#这里直接指定查看的是“是否分片”
db.collection_2852199356.stats().sharded

#如果想要查询分片的状态可以直接指定shards
db.collection_2852199356.stats().shards

#如果想要查看全面信息直接stats就好了
db.collection_2852199356.stats()


#直接查看数据分布
db.collection_2852199356.getShardDistribution()
Shard cmgo-7pjee7vx_1 at cmgo-7pjee7vx_1/9.100.108.209:7046,9.11.32.233:7012,9.11.37.199:7004
 data : 2.91GiB docs : 10298912 chunks : 93
 estimated data per chunk : 32.05MiB
 estimated docs per chunk : 110740

Shard cmgo-7pjee7vx_2 at cmgo-7pjee7vx_2/100.121.156.55:7005,100.122.26.223:7002,100.122.26.249:7008
 data : 2.92GiB docs : 10353848 chunks : 94
 estimated data per chunk : 31.88MiB
 estimated docs per chunk : 110147

Shard cmgo-7pjee7vx_0 at cmgo-7pjee7vx_0/100.121.150.233:7035,100.121.159.28:7015,100.122.27.99:7022
 data : 2.94GiB docs : 10409654 chunks : 94
 estimated data per chunk : 32.05MiB
 estimated docs per chunk : 110741

Totals
 data : 8.77GiB docs : 31062414 chunks : 281
 Shard cmgo-7pjee7vx_1 contains 33.15% data, 33.15% docs in cluster, avg obj size on shard : 303B
 Shard cmgo-7pjee7vx_2 contains 33.33% data, 33.33% docs in cluster, avg obj size on shard : 303B
 Shard cmgo-7pjee7vx_0 contains 33.51% data, 33.51% docs in cluster, avg obj size on shard : 303B

  

6、开启集合分片

方法同样参见官网:Deploy a Sharded Cluster — MongoDB Manual

这里主要是三步:①允许数据库分片(enableSharding);②设置相应分片键索引  ③对某个确定的集合指定分片(shardCollection)。

注意:(1)如果不进行第一步,直接对指定的集合进行分片会报错(下图)(2)以上两个指令都必须要切到admin数据库下通过mongos实例才能执行。

(1)enableSharding:  指定数据能够分片  这里

#db.runCommand()的“enableSharding“命令
db.runCommand( { enableSharding: "<database name>"} )


#也可以使用mongo shell的方法sh.enableSharding(),它封装了enableSharding命令
sh.enableSharding("db_msg_track")

执行前后对比——执行sh.status()指令查看:

(2)设置片键索引(shard key index):


        对一个集合涉及分片的前提条件是这个集合必须要有一个以这个分片键为开头的索引。分两种情况:①对于已经有很多数据的集合,必须要设一个以这个分片键为开头的索引;②对于一个空集合,如果这个集合没有针对这个分片键的合适的索引,那么mongodb会自动为其创建一个支持索引。

(3)shardCollection:对一个集合进行分片   这里

#db.runCommand({})的”shardcollection“方法,格式如下:
{
   shardCollection: "<database>.<collection>",
   key: { <field1>: <1|"hashed">, ... },
   unique: <boolean>,
   numInitialChunks: <integer>,
   presplitHashedZones: <boolean>,
   collation: { locale: "simple" }
}
//一个实例如下:
db.adminCommand( {shardcollection: "db_msg_track.collection_2852199356", key: { _id:1}})
db.adminCommand( { shardCollection: "db_shuozhuo.test", key: {kfuin: "hashed"}})


(1)shardCollection:集合的命令空间组成为 <database>.<collection>.
(2)key:指定被用作片键的字段(字段们)。{<field1>:<1|"hashed">}:field的value为1表示范围分片;"hashed"表示哈希分片。

#shell命令方法

sh.shardCollection("<database>.<collection>", { <shard key field> : "hashed" } )

注:范围分片是可以直接创建的;但是hashed分片会要求你先创建这个字段的hash索引(即使是_id)——"Please create an index that starts with the proposed shard key before sharding the collection"。

具体参见官网:Hashed Sharding — MongoDB Manual

7、设置分片举例

案例一:以kfuin为分片键对集合进行hash分片,同时将unique_id字段设为primarykey,用此字段实现写入的幂等性。

(1)首先,以kfuin字段进行hash分片就要求必须对kfuin字段建立一个hash索引,如下:

db.test.createIndex( { kfuin: "hashed" } )

(2)将unique_id设为primarykey就是说要建立关于unique_id字段的唯一索引;但是我们又要以kfuin进行分片,故要求必须建立一个以kfuin为前缀字段的唯一索引(即复合字段唯一索引),如下:

db.test.createIndex( { kfuin: 1, unique_id: 1}, { unique: true } )

(3)然后以kfuin作为分片键对集合进行hash分片,如下:

db.runCommand({shardcollection: "db_shuozhuo.test", key: { kfuin:"hashed"}})

注:尝试kfuin不是唯一唯一的前缀发现确实是不行的{经过验证}。比如说已经先设置好分片方式了,然后不以kfuin为前缀字段创建唯一索引就会如下报错。明确告诉你“对于{kfuin:"hashed"}”分片模式下你不能创建“( {unique_id:1, kfuin:1}, {unique:true})”这样的索引。

注:对于被用作分片键的kfuin字段,其字段值为数字or字符串经过hash都能够近乎均等地分布到各个分片上。

8、分片集群不设置分片键会怎么样?

总的来讲如果不设置分片键的话相当于分片集群并没有被利用起来,相当于说是仅仅用到了主分片(primary shard)。

https://segmentfault.com/q/1010000016251665

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐