分片
分片是一种把数据分散到许多台计算机中的方法,MongoDB 使用分片技术来部署非常大的数据集,同时支持高吞吐量的数据操作。
大数据库系统与高吞吐量系统对于单机服务器提出了严峻的挑战。比如说高频查询会榨干一台服务器上的CPU时间,而大于单机内存容量的数据集将会占满磁盘的读写吞吐量。
一般寻址系统有两种扩展方式,一种是垂直扩展,一种是水平扩展。
垂直扩展指的是增加单台计算机的性能,例如使用更强劲的CPU、插入更多内存条、或者增加本地存储空间。可用技术中的限制可能会限制单台机器运行给定负载的能力。此外,基于云的提供商根据可用的硬件配置有严格的上限。 因此,垂直扩展有一个实际的最大值。
水平扩展指的是切分系统的数据集,把它们分散到多台服务器组成的集群上,根据日益增长的容量需求来增加服务器的数量,虽然集群每台机器的性能可能不会太高,但他们只需要负责处理总负载的一小部分,将其组织起来后便能提供强劲的数据存取能力,并以此胜过单台高性能高容量的服务器。扩展这种集群的存储性能仅仅需要增加更多的服务器。这样的成本远比把单台服务器升级成一台超级计算机。不过代价就是基础设施和部署维护方面的复杂性增加。
MongoDB 通过分片技术来支持水平扩展。
分片集群
一个分片集群,由以下组件组成:
- shard: 分片,每个分片都包含一个切分的数据子集,并且可以作为复制集部署。
- mongos: 路由,每个路由作为数据分片和应用程序之间的数据接口,对应用程序来说它可被视为一个单机 MongoDB 服务器。从MongoDB 4.4开始,mongos可以支持对冲读取,以最小化延迟。
- config server: 配置服务器,配置服务器存储集群的元数据和配置设置。
下图描述了分片集群内各组件的交互。
这是一个用于生产目的分片集群示例图。包含正好3个配置服务器(由复制集组成),1个或多个mongos
查询路由,以及至少2个shard。这些shard内部是由复制集组成。
MongoDB在集合层对数据进行分片,将集合数据分布在集群中的各个shard上。
片键(Shard Key)
MongoDB使用片键将集合的文档分布在不同的分片上。片键由文档中的一个字段或多个字段组成。
从 4.4 版本开始,分片集合中的文档可以缺少片键字段。缺少片键字段的文档在跨分片分发时将被视为具有空值,但在路由查询时则不会。有关更多信息,请参阅缺失的片键。
在 4.2 及更早的版本中,片键字段必须存在于分片集合的每个文档中。
在对集合进行分片时,你需要选择一个片键(比如 _id
)。
从MongoDB 4.2开始,您可以更新文档的片键值,除非您的片键字段是不可更改的 _id
字段。更多信息请参见更改文档的片键值。
在MongoDB 4.0和更早的版本中,文档的片键字段值是不可改变的。
片键索引
要对一个非空集合分片,该集合必须有一个以片键开始的索引。当对一个空的集合分片时,如果该集合还没有对应指定片键的索引,MongoDB 会自动创建对应的索引。请参阅片键索引。
选择片键
片键的选择会影响分片集群的性能、效率和可扩展性。一个拥有最佳硬件和基础架构的集群可能会因为片键的选择而陷入瓶颈。片键及其支持索引的选择也会影响您的集群可以使用的分片策略。
分块
MongoDB 将分片内的数据分区为chunks。每个分块都有一个基于片键的包含性下限和排他性上限范围(即左闭右开)。
平衡器和均匀分块分布
为了在集群中的所有分片上实现均匀分布的分块,一个平衡器在后台运行,以在分片上迁移分块。
分片的优势
读写速度
MongoDB将读写工作负载分布在分片集群中的各个分片上,允许每个分片处理集群操作的一个子集。读和写工作负载都可以通过添加更多的分片在集群中水平扩展。
对于包含片键或复合片键前缀的查询,mongos可以将查询锁定在特定的分片或分片集合上。这些有针对性的操作通常比向集群中的每个分片广播更有效率。
从 MongoDB 4.4 开始,mongos可以支持对冲读取,以最小化延迟。
存储容量
Sharding将数据分布在集群中的各个分片上,允许每个分片包含集群总数据的一个子集。随着数据集的增长,额外的分片会增加集群的存储容量。
高可用性
将配置服务器和分片部署为副本集,可以提高可用性。
即使一个或多个分片副本集变得完全不可用,分片集群仍可继续执行部分读写。也就是说,虽然无法访问不可用的分片上的数据,但针对可用分片的读或写仍然可以成功。
分片前的考虑因素
分片集群基础架构的要求和复杂性需要仔细规划、执行和维护。
一旦一个集合被分片,MongoDB 不提供任何方法来解除分片的集合。
为了确保集群的性能和效率,在选择片键时必须仔细考虑。请参阅选择片键。
分片有一定的操作要求和限制。请参阅分片集群中的操作限制了解更多信息。
如果查询不包括片键或复合片键的前缀,mongos会执行广播操作,查询分片集群中的所有shard。这些散布/收集查询可能是长期运行的操作。
注意:
如果您与MongoDB签订了有效的支持合同,请考虑联系您的客户代表,以获得分片集群规划和部署方面的帮助。
分片式和非分片式集合
一个数据库可以有混合的分片和未分片集合。分片集合被分割并分布在集群中的各个分片上。未分片的集合存储在一个主片上。每个数据库都有自己的主片。 主片的示意图。主片服务器上包含未分片的集合以及来自分片集合的文档块。图中 Shard A 是主片。
连接到分片 Cluster
您必须连接到 mongos 路由才能与分片集群中的任何集合进行交互。这包括分片和未分片的集合。客户端永远不应该连接到一个单一的分片服务器来执行读或写操作。 应用程序/驱动程序向 mongos 发出对未分片集合以及分片集合的查询的示意图。图中未显示配置服务器。
你可以像连接mongod一样连接到mongos,比如通过mongo shell或MongoDB驱动。
分片策略
MongoDB支持两种分片策略,用于在分片集群之间分发数据。
哈希分片
哈希分片涉及计算片键字段的哈希值。然后,根据散列的片键值为每个分块分配一个范围。
小贴士 MongoDB 在使用哈希索引解析查询时自动计算哈希值。应用程序不需要计算哈希值。
基于哈希的分割图
虽然一系列文档的片键值可能是 "接近" 的,但它们的哈希值不可能在同一个chunk上。基于哈希值的数据分布有利于数据分布更加均匀,尤其是在片键单调变化的数据集中。
然而,散列分布意味着基于范围的对片键的查询不太可能针对单个shard,从而导致更多的集群范围的广播操作。
更多信息请参见左边目录哈希分片。
范围分片
范围分片涉及根据片键值将数据划分为范围。然后根据片键值为每个分块分配一个范围。 片键值空间划分为更小的范围或块的示意图。
在范围分片中,取值"相近" 的一系列片键更有可能驻留在同一个chunk上。这样就可以进行有针对性的操作,因为 mongos 可以只将操作路由到包含所需数据的分片上。
范围分片的效率取决于选择的片键。考虑不周的片键会导致数据分布不均,这会失去分片的一些好处,或者会造成性能瓶颈。请参阅[基于范围分片的片键选择]。
更多信息请参见左边目录 "范围分片"。
分片集群中的区域
对于跨越多个数据中心的分片集群,区域可以帮助提高数据的定位性。
在分片集群中,您可以根据片键创建划分分片数据的区域。您可以将每个区域与集群中的一个或多个分片相关联。一个分片可以关联任意数量的区域。在平衡集群中,MongoDB仅将一个区域所覆盖的块迁移到与该区域相关联的分片上。
每个区域覆盖一个或多个片键值的范围。一个区域所覆盖的每个范围总是包含它的下边界,而不包含它的上边界。 基于分片集群中区域的数据分布图
为要覆盖的区段定义新范围时,必须使用片键中包含的字段。如果使用复合片键,则范围必须包括片键的前缀。更多信息请参见区块中的片键。
在选择片键时,应考虑到将来可能使用的区域。
小贴士 从MongoDB 4.0.3开始,设置区域和区域范围可以更快地铲除一个空的或不存在的集合。
更多信息请参见分片集群中的区域。
分片中的集合
使用 shardCollection 命令和 collation: { locale: "simple"} 选项,可以对一个有默认collation的集合进行分片。成功的分片需要以下条件。
- 这个集合必须有一个前缀是片键的索引。
- 索引必须有集合 { locale: "simple" }
在创建具有整理功能的新集合时,请确保在保护集合之前满足这些条件。
注意事项 对分片集合的查询继续使用为集合配置的默认整理方式。要使用片键索引的简单整理,请在查询的整理文档中指定{locale: "simple"}。
请参阅shardCollection了解更多关于sharding和co的信息。
关于分片和整理的更多信息,请参见shardCollection。
变化流
从MongoDB 3.6开始,变化流可用于复制集和分片集群。变化流允许应用程序访问实时数据变化,而无需引入尾随oplog的复杂性和风险。应用程序可以使用变化流来订阅一个或多个集合上的所有数据变更。
事务
从MongoDB 4.2开始,随着分布式事务的引入,多文档事务在分片集群上可以使用。 在一个事务提交之前,事务中所做的数据变化在事务外部是不可见的。
但是,当一个事务向多个分片写入时,并不是所有的外部读操作都需要等待提交的事务的结果在各分片中可见。例如,如果一个事务已提交,并且写1在A分片上可见,但写2在B分片上还不可见,那么在读关注 "本地 "的外部读可以在不看到写2的情况下读取写1的结果。
参见
- 事务
- 生产方面的考虑
- 生产方面的考虑因素(分片集群)。
参见
原文 - Sharding
译者:雪星 (snomiao@gmail.com) 于 2020 秋
校对:征集中!