官方说明:
Sharding is a method for distributing data across multiple machines. MongoDB uses sharding to support deployments with very large data sets and high throughput operations.
分片就是一种把数据分布在多台机器上的方法。mongodb使用分片来支持大数据量、高吞吐量的布署。
一个分片集群的结构见图:
shard server:用于存储实际的数据块,每个分片存储部分分片数据,每个分片都可以布署成其他分片的副本集(replica set)。实际生产环境中一个shard server角色可由几台机器组个一个replica set承担,防止主机单点故障。 config server:顾名思义为配置服务器,存储所有数据库元信息(路由、分片)的配置。 mongos server:协调中心。数据库集群请求的入口,所有的请求都通过mongos进行协调,不需要在应用程序添加一个路由选择器,mongos自己就是一个请求分发中心,它负责把对应的数据请求请求转发到对应的shard服务器上。在生产环境通常有多mongos作为请求的入口,防止其中一个挂掉所有的mongodb请求都没有办法操作。
关注之后文章或参考官网:https://docs.mongodb.com/manual/sharding/
mongodb是通过一个个collection来做数据存储的,可以类比关系型数据库的表。
mongodb是通过分片键来对collection进行分区的,也就是通过分片键来决定一个document如何分布式存入collection中。分片键是每个存放在collection中的document都持续拥有的不可缺少的一个字段或多个字段的组合。 分片键有下面几个要求:
sh.shardCollection( namespace, key )
分片键必须有索引,索引可以是分片键上的索引,当分片键是索引前缀时,也可以是复合索引。 注意:分片键索引必须是横向(正向),比如用id做索引时定义为key{id:1} 参考:https://docs.mongodb.com/manual/core/sharding-shard-key/#sharding-shard-key-indexes
分片键的基数(散列度)决定了balancer创建的块(chunks)的最大数量。如果一个分片键只有一个值,那么它最多只会存放在一个区块(chunks)中。如果一个分片键有四个取值,那么分片集群中至多有四个区块(chunks),每个区块保存唯一的的个分片键对应的值。 对于一个以字段X做为分片键的集群,如果X的散列度比较低,那么数据分布大至如下图:
一个分片键的散列程度很高时,并不能保证在集群中是均匀分布的,但是一个高散列度的分片键更易于水平扩展。如果你的分片键有较低的散列度,最好考虑使用组合索引,用这个字段与另一个有相对比较高散列度的字段一起组合。
分片键的频率是指,一个数据值重复出现的频率。如果主要的document中重复的数据大量出现,那么保存这些数据的区块(chunks)会变成集群中的瓶颈。之后,当这些区块越来越大时,它们会变成不可分割开的区块,这将很大程度上影响集群的可拓展性。
如果X为分片键,当某些数据出现频率比较高时,数据分布大致如下图:
还有一点就是当分片键出现频率低时是不能保证集群数据的均匀分布的。如果你的数据模型要求数据分片键要建立在一个高频率出现的数据上,考虑使用组合索引,与唯一的或者低频率的值进行组合。
参考:https://docs.mongodb.com/manual/core/sharding-shard-key/#sharding-shard-key-creation
分片键的数据值单调递增或单调递减时就比较像是把数据插入集群的一个单一分片里面了。这是因为集群中的区块有一个最大值(maxKey)和一个最小值(minKey)的临界点,也就是说有一个区块的上界是maxKey,也会有一个区块的下界是minKey。 如果数据是单调递增的,会导致所有新插入的数据都进入以maxKey为上界的区块中去。如果单调递减,会导致新插入数据进入以minKey为下界的区块中去。 比较形象的见下图(以X为分片键时):
如果分片键X上的数据是单调递减的,所有的数据都会进入Chunk A。
如果你的数据模型要求分片键上的值单调变化,考虑使用Hashed Sharding分片策略,见下面介绍。
mongodb有两种分片策略,分片策略是根据分片键的选择来定的:
如果要使用hash分片键,首先分片键数据散列度必须要高,拥有很多不同的值。hash散列键对单调变化的数据比如ObjectId和时间戳是比较好的方案。一个好的例子就是_id。 使用hash分片键:
sh.shardCollection("<database>.<collection>", { <shard key> : "hashed" } )
参考:https://docs.mongodb.com/manual/tutorial/deploy-sharded-cluster-hashed-sharding/
通过分片键的值来将数据分成不同的范围。它可以提供比较快的范围查询,但是当分片键选择不好的时候,也会降低读写性能 。 如果没有配置Hashed Sharding或者zones(https://docs.mongodb.com/manual/core/zone-sharding/#zone-sharding)它是默认的分片键方法。
sh.shardCollection( "database.collection", { <shard key> } )
大致分布见下图:
The following image illustrates a sharded cluster with three shards and two zones. The A zone represents a range with a lower boundary of 1 and an upper bound of 10. The B zone represents a range with a lower boundary of 10 and an upper boundary of 20. Shards Alpha and Beta have the A zone. Shard Beta also has the B zone. Shard Charlie has no zones associated with it. The cluster is in a steady state and no chunks violate any of the zones.
For example, given a shard key { a : 1, b : 2, c : 3 }, creating or updating a zone to cover values of b requires including a as the prefix. Creating or updating a zone to covers values of c requires including a and b as the prefix. 创建shard tag:
sh.addShardTag("shard0000", "NYC")sh.addShardTag("shard0001", "NYC")sh.addShardTag("shard0002", "SFO")sh.addShardTag("shard0002", "NRT")
创建zone rang:
sh.addTagRange("records.users", { zipcode: "10001" }, { zipcode: "10281" }, "NYC")sh.addTagRange("records.users", { zipcode: "11201" }, { zipcode: "11240" }, "NYC")sh.addTagRange("records.users", { zipcode: "94102" }, { zipcode: "94135" }, "SFO")
参考:https://docs.mongodb.com/manual/tutorial/manage-shard-zone/
与hashed shard key一起使用时,zone的范围一般要覆盖minKey和maxKey才可以。 参考:https://docs.mongodb.com/manual/core/zone-sharding/#zone-sharding
主要在单调数据的场景,不使用hash时:
数据会集中放入一个chunks中。 使用hash时:
db.collection.aggregate( [ { $count: "myCount" }])
或
db.collection.aggregate( [ { $group: { _id: null, count: { $sum: 1 } } } { $project: { _id: 0 } }] )
参考:https://docs.mongodb.com/manual/reference/method/db.collection.count/