转载说明:如果您喜欢这篇文章并打算转载它,请私信作者取得授权。感谢您喜爱本文,请文明转载,谢谢。
目录导读
-
什么是MongoDB分片
-
MongoDB分片集群介绍
2.1 MongoDB分片集群架构
2.2 MongoDB分片集群优势
- 分片键的选择
3.1 选择基数大的分片键
3.2 选择分布均匀的分片键
3.3 避免单调增加或减少的分片
3.4 分片键涵盖最常用的查询模式
- 分片的策略
4.1 哈希分片
4.2 范围分片(远程分片)
4.3 分区分片
- 分片前的注意事项
1. 什么是MongoDB分片
分片是一种将数据分布在多个机器,MongoDB使用分片来支持具有非常大数据的部署集和高吞吐量操作。
具有大型数据集或高吞吐量应用程序的数据库系统会给单个服务器的容量带来挑战。例如,高查询率可以耗尽服务器的 CPU 容量;工作集大小大于系统的 RAM 会给磁盘驱动器的 I/O 容量带来压力。
有两种方法可以解决系统增长问题:垂直和水平缩放。
垂直扩展: 增加单个服务器的容量,例如 如使用更强大的 CPU、添加更多 RAM 或增加 存储空间。但单个服务器的CPU、RAM终有天花板值,不能无限扩张。因此,垂直缩放有一个实际最大值。
**水平扩展:**划分系统数据集并加载多台服务器,根据需要增加服务器节点数量以增加容量。虽然单台机器的整体速度或容量可能不高,但每台机器处理整体工作负载的子集,可能提供更好的比单个高速高容量服务器的效率。扩展部署容量只需要根据需要添加额外的服务器, 这可能比单台机器的高端硬件更低的总成本。代价是基础设施和维护的复杂性增加部署。
2. MongoDB分片集群介绍
2.1 MongoDB分片集群架构
一个MongoDB分片集群由以下组件组成:
shard **:**每个分片包含一个分片数据的子集。每个分片都可以部署为副本集。
**mongos:**查询路由器,是个无状态应用。负责接收客户端的请求并将其路由到正确的分片上,进行读写合并多个数据节点的返回。本身不存储数据,也不维护任何与客户数据相关的状态信息。建议部署2个及以上节点。从MongoDB4.4开始,可以支持hedged reads 以最大程度地减少延迟。
**config servers:**confi服务器负责存储和管理分片集群的元数据信息,如分片键范围、分片集群配置等。官方建议最少部署3个config服务器且部署为副本集。另外,因投票选举机制,config服务器数量建议为奇数。
hedged reads技术是一种优化读取操作的方式,以最小化延迟。hedged reads技术是通过同时向多个分片服务器发出查询请求,然后使用最先返回结果的服务器来响应查询请求,从而实现最小化延迟的。这种技术通常用于高负载的环境中,以提高查询性能和响应时间。
MongoDB在collection级别对数据进行分片,通过集群中的分片分发collection数据。
2.2 MongoDB分片集群优势
1)读写
MongoDB 在分片集群中的分片之间分配读写工作负载,允许每个分片处理集群操作的子集。读取和写入工作负载都可以通过添加更多分片在集群中水平扩展。
对于包含shard key或复合shard key前缀的查询,mongos可以针对特定的shard或shard集合进行查询。这些有针对性的操作通常比广播到集群中的每个分片更有效。
从MongoDB4.4开始,可以支持hedged reads 以最大程度地减少延迟。
2)存储容量
分片将数据分布在集群中的多个分片上,允许每个分片包含集群总数据的一个子集。随着数据集的增长,额外的分片会增加集群的存储容量。
3)高可用性
config server服务器和副本集式部署的分片提供了高可用性:
即使一个或多个分片复制集完全不可用,分片集群也可以继续执行部分读写操作。也就是说,当不可用分片上的数据不能被访问时,对可用分片的读写仍然可以成功。
**注意:**不是所有的集群都适用于分片集群。比如数据量小的场景,就完全没必要用分片集群了
3. 分片键的选择
MongoDB 使用分片键来跨分片分发collection的文档。分片键由文档中的一个或多个字段组成。
在版本 4.2 及更早版本中,分片集合的每个文档中都必须存在分片键字段。
从版本 4.4 开始,分片集合中的文档可以是缺少分片键字段。在跨分片分布文档时,缺少的分片键字段将被视为具有空值,但在路由查询时则不被视为具有空值。
例如一条分片语句:
sh.shardCollection("your_database_name.your_collection_name", { "shard_key": "hashed" })
#如:
sh.shardCollection("dbtest.collectiontest", { "shard_key": "hashed" })
选择分片键(shard_key)要考虑的几个因素:
分片键的基数;
分片键值出现的频率,尽可能被更多的业务场景使用;
潜在的分片键是否单调增长/减小;
分片查询模式;
Shard Key限制;
在对集合进行分片时,选择合适的分片键:
在 MongoDB 4.2 及更早版本中,一旦对一个集合进行了分片,那么分片键的选择是不可变的。
从 MongoDB 4.4 开始,可以通过refineCollectionShardKey命令来优化分片键;通过refineCollectionShardKey命令向现有键添加一个或多个后缀字段,以创建新的分片键。
从MongoDB 5.0开始,可以通过使用reshardCollection命令更改分片键来重新分片collection。
文档的分片键value值决定了它在分片中的分布
在MongoDB 4.0及更早版本中,文档的分片键字段value值是不可变的。
从MongoDB 4.2开始,可以更新文档的分片键value值,除非使用的分片键字段是不可变的_id字段。
3.1 选择基数大的分片键
几个概念及关系:
1)集群 Cluster: 一个cluster 包含 n 个shard
**2)分片 Shard:**一个shard 包含 n 个 chunk
**3)块 Chunk :**一个chunk 包含 n 个doc
**4)文档 doc :**一个doc包含一个 shard key,该值决定了文档所属的Chunk及存储该文档的Shard。
**5)分片键 shard key:**文档中的一个字段
在任何给定时间,每个唯一的shard键值只能存在于一个块中。分片键的基数决定了平衡器可以创建的最大块数量。因为备选值有限,那么块的总数量就有限,随着数据增多,块的大小会越来越大,水平扩展时移动块会非常困难。因此,建议选择基数大的分片键。如果当前的数据模型需要对基数低的键进行分片,可考虑使用索引复合字段来增加基数。
例如:
如果根据性别来进行分片,则分片的基数为2。基数为2意味着在分片集群中不能有超过2个块(chunk),每个块存储一个唯一的分片键值。这也将集群中有效分片的数量限制在2个,添加更多的分片也不会带来更多的效用。
选择基数小的分片键,插入数据可能会产生这种效果:
3.2 选择分布均匀的分片键
分片键的频率代表了给定的分片键值在数据中出现的频率。如果这个频率分布不均匀,存储具有这些值的文档的块的数据量可能会急剧增大,这些块的压力随之增大。而数据均衡又以 chunk 为单位,这些压力巨大的chunk没有办法被别的chunk分担,所以可能成为集群中的瓶颈。
因此建议选择在数据中出现频率分布均匀的分片键。如果当前的数据模型需要对具有高频次出现的键进行分片,可考虑使用使用唯一值或低频值的复合索引。
例如:
存储一个城市所有小学5年级学生的数据,数据范围是9-16岁,以年龄整数进行分片,分片基数为8,有8个chunk。但根据我国小学入学条件规定,大部分小学五年级学生的年龄绝大部分集中在10岁和11岁,就会导致10岁的chunk和11岁的chunk的读写压力增大,成为瓶颈。而别的chunk可能一个数据都没有,没有读写压力。
选择频率出现高低不均的分片键,插入数据可能会产生这种效果:
3.3 避免单调增加或减少的分片键
分片键避免使用单调增加或减少的分片键。如果当前数据模型需要对单调变化的键进行分片,可考虑使用哈希分片。
一个值单调增加或减少的分片键更有可能将写入的数据分发到集群中的单个块上。
这是因为每个集群都有一个块,它捕获一个具有maxKey上限的范围。maxKey总是比所有其他值高。类似地,有一个块捕获minKey下界的范围。minKey总是比所有其他值低。
如果分片键值一直在增加,那么所有新的插入数据都将以maxKey为上界路由到捕获maxKey上限的块中。如果分片键值一直在减小,那么所有新的插入数据都将以minKey作为下界路由到捕获minKey下界的块中。包含该块的分片就将成为写入操作的瓶颈。
为了优化数据分布,包含全局maxKey(或minKey)的块不会留在同一个分片上。当分割块时,具有maxKey(或minKey)块的新块位于不同的分片上。
下图展示了一个使用字段X作为分片键的分片集群。如果X的值单调增加或减小的场景下,则插入的分布可能类似于以下情况:
3.4 分片键涵盖最常用的查询模式
理想的分片键在整个分片集群中均匀分布数据,同时还支持通用查询模式。因此在选择分片键时,先考虑整个数据集中最常见的查询模式有哪些,给定的分片键是否涵盖了这些模式。
在分片集群中,如果查询包含shard key, mongos只会将查询路由到包含相关数据的shard。当查询不包含分片键时,查询将广播到所有分片进行评估。这些类型的查询称为分散-收集查询。对于每个请求涉及多个分片的查询效率较低,并且当向集群添加更多分片时不能线性扩展。这不适用于对大量数据进行操作的聚合查询。
在某些特殊情况下,分散-收集可能是一种有用的方法,它允许查询在所有分片上并行运行。
4. 分片的策略
MongoDB支持两种分片策略,用于跨分片集群分发数据。
4.1 哈希分片
哈希分片将数据通过哈希函数计算得到哈希值,然后根据哈希值为每个块分配一个范围。MongoDB在使用哈希索引解析查询时自动计算哈希值。应用程序不需要计算哈希值。
基于哈希值的分片有助于更均匀的进行数据分布,特别是在分片键单调变化的数据集中。比较适用于高并发场景。
然而,哈希分布意味着对分片键的查询不太可能针对单个分片,而是在更多的集群范围内进行广播操作,降低查询操作效率。
4.2 范围分片(远程分片)
范围分片(远程分片)根据分片键值将数据划分为不同的范围。然后根据分片键值为每个块分配一个范围:
一组分片键值接近的分片键更有可能分配在同一个块上。这就允许有某些针对性的操作,因为mongos可以将操作路由到包含所需数据的分片。
范围分片的效率取决于所选择的分片键。范围分片将数据按指定的范围进行划分,使得在进行范围查询时能够只在涉及的分片上执行查询操作,不需要访问整个分片集群,减少了数据在网络中的传输,提高了范围查询的性能。
但考虑不当的分片键可能导致数据分布不均匀,容易出现热点,可能导致性能瓶颈。
4.3 分区分片
分片集群跨多个数据中心时,区域可以帮助提高数据的本地性。
在分片集群中,可以根据shard key创建分片数据分区。可以将每个分区与集群中的一个或多个分片关联,一个shard可以与任意数量的zone相关联。
在balance集群时,MongoDB只会将一个区域覆盖的块迁移到与该区域关联的那些分片上。
每个区域包含一个或多个分片键值范围。一个区域覆盖的每一个范围总是包括它的下边界而不包括它的上边界。
5. 分片前的注意事项
分片集群基础设施的需求和复杂性需要仔细规划、执行和维护。如分片集群架构、服务器数量、配置等相关事项。
一旦对一个集合进行了分片,MongoDB目前没有任何方法来对这个被分片的集合进行反分片。虽然可以重新对集合进行切分,但务必仔细考虑切分键的选择,以避免出现可伸缩性和性能问题。
一个数据库(如db:test)可以混合使用分片集合(collection)和非分片集合(collection)。分片集合(collection)在集群中的多个分片之间进行分区和分布。未分片的集合(collection)存储在主分片上。每个数据库都有自己的主分片。
连接到分片集群:
连接到mongod的方式有两种:通过mongosh连接或者MongoDB驱动连接。这两种方式同样适用于连接到mongos。
以上即MongoDB分片集群的简要梳理总结。