第七章:扩展伸缩性 扩展伸缩性(一)-分片扩展MongoDB
可伸缩性多年来一直是一个备受关注的话题。 尽管关于它已经有很多说法了,但这个话题非常重要,在本书中,它肯定也会找到它的位置。 处理涉及数据库可伸缩性的所有概念(尤其是在NoSQL数据库中)并不符合我们的利益,但是要展示MongoDB在处理集合中的可伸缩性时提供的可能性以及MongoDB数据模型的灵活性如何影响我们的选择 。 可以基于简单的基础设施和低成本的分片请求来水平扩展MongoDB。 分片是通过称为碎片的多个物理分区分配数据的技术。 即使数据库是物理分区的,对我们的客户来说,数据库本身也是一个实例。 分片技术对数据库的客户端来说是完全透明的。 亲爱的读者,准备好! 在本章中,您将看到数据库维护的一些重要主题,例如:
使用分片进行扩展
选择分片键
扩展社交收件箱模式设计
7. 1 使用分片扩展MongoDB
当我们谈论数据库可伸缩性时,我们有两种参考方法:
向上缩放或垂直缩放:在此方法中,我们向机器添加更多资源。 例如,为了增加系统的容量,需要一个CPU,磁盘和内存等。
横向扩展或水平扩展:在此方法中,我们向系统添加更多节点并将工作分配到可用节点中。
一方或另一方之间的选择不取决于我们的愿望。 这取决于我们想要扩展的系统。 有必要知道是否可以按照我们想要的方式扩展该系统。 我们还必须记住这两种技术之间存在差异和折衷。 由于我们服务提供商的限制,增加存储容量,CPU或内存可能非常昂贵,有时甚至不可能。 另一方面,增加系统中的节点数量也会在概念和操作上增加复杂性。 但是,考虑到虚拟化技术和云提供商提供的设施的进步,横向扩展正在成为一些应用程序更实用的解决方案。 MongoDB准备横向扩展。 这是在分片技术的帮助下完成的。 这项技术包括对数据集进行分区并在多台服务器之间分发数据。 分片的主要目的是支持能够通过在每个分片之间分配操作负载来处理高吞吐量操作的较大数据库。 例如,如果我们有1 TB的数据库和4个分片配置,每个分片应该有256 GB的数据。 但是,这并不意味着每个分片将处理25%的吞吐量操作。 这只会取决于我们决定构建碎片的方式。 这是本章的一大挑战和主要目标。 下图演示了一个碎片如何在MongoDB上工作:
在编写本书时,MongoDB的3.0版本提供了多种分片策略:基于范围、基于散列和基于位置的分片。
在基于范围的策略中,MongoDB将根据分片键的值对数据进行分区。 分片键值彼此接近的文档将被分配在相同的分片中。
在基于散列的策略中,考虑分片密钥的MD5值分配文档。
在基于位置的策略中,文档将根据将分片分段值与特定分片相关联的配置以分片分发。 这种配置使用标签来完成,这与您在第6章管理数据中看到的非常相似,在那里我们讨论了操作隔离。
分片在集合级别的MongoDB中工作,这意味着我们可以在同一个数据库中使用分片并且不启用分片的集合。 要在集合中设置分片,我们必须配置分片集群。 分片群集的元素是分片、查询路由器和配置服务器
分片是我们的数据集的一部分将被分配的地方。 分片可以是MongoDB实例或副本集
查询路由器是数据库客户端提供的接口,负责将操作指向正确的分片
配置服务器是一个MongoDB实例,负责保持分片的集群配置,换句话说,是集群的元数据。
下图显示了共享群集及其组件:
我们不会深入研究分片群的创建和维护问题,因为这不是我们本章的目标。 但是,知道分片群集的设置取决于场景很重要。 在生产环境中,建议的最低设置是至少三个配置服务器,两个或更多个副本集(这将是我们的分片)以及一个或多个查询路由器。 通过这样做,我们可以确保我们环境的最小冗余和高可用性。
7.1.1 选择分片键
一旦我们确定我们需要分片群集,下一步就是选择分片键。 分片键负责确定文档在集群分片中的分布。 这些也将成为决定我们数据库成败的关键因素。 对于每个写操作,MongoDB将根据分片键的范围值分配一个新文档。 分片键的范围也称为块。 块的默认长度为64 MB,但是如果您希望根据需要自定义此值,可以对其进行配置。 在下图中,您可以看到如何将文档分配到块上,并给定一个数字分片键,从负无穷大到正无穷大:
开始讨论可能影响我们分片键构造的事情之前,MongoDB中存在一些必须尊重的限制。这些限制很重要,并且在某些方面,它们帮助我们消除了在我们的选择中出现一些错误的可能性。 分片键不能超过512字节的长度。 分片键是文档中的索引字段。 这个索引可以是一个简单的字段或一个组合的字段,但它永远不会是一个多键字段。 自2.4版本的MongoDB以后,也可以使用简单哈希字段的索引。 以下信息必须静静地阅读,就像念咒一样,以便你从一开始就不会犯任何错误。
:
http://docs.mongodb.org/manual/reference/limits/#sharded-clusters
但是如果我创建了分片键并且想要更改键呢? 我该怎么办? 我们应该做以下事情,而不是试图改变它:
在磁盘文件中执行数据库转储。
删除集合。
使用新的分片键配置新的集合。
执行块的预分割。
恢复转储文件。
如您所见,我们不会更改分片键。 我们重新创建了几乎所有的东西。 因此,在执行创建分片键的命令时要小心,否则如果需要更改它,您将会头疼。
:
您需要记住的下一条信息是,您无法更新作为分片键一部分的一个或多个字段的值。换句话说,分片键的值也是不可更改的。
尝试在作为分片键一部分的字段中执行update()方法没有用处,不起作用。 在我们继续之前,让我们在实践中看到我们在这一点上讨论的内容。 我们来创建一个分片集群进行测试。 以下分片配置对于测试和开发非常有用。 切勿在生产环境中使用此配置。 给定的命令将创建:
两个分片
一台配置服务器
一个查询路由器
作为第一步,让我们开始一个配置服务器实例。 配置服务器只不过是带有一个初始化参数--configsvr的mongod实例。如果我们没有为参数--port 设置一个值,默认情况下它将从端口27019开始:
下一步是启动查询路由器。 查询路由器是一个mongos MongoDB实例,它使用指示配置服务器的参数--configdb 来路由对分片的查询和写入操作。 默认情况下,MongoDB在端口27017上启动它:
最后,让我们开始分片。 这个例子中的分片只是两个简单的mongod实例。 与mongos类似,默认情况下,mongod实例在端口27017上启动。 由于我们已经在这个端口上启动了mongos实例,我们为mongod实例设置一个不同的端口:
完成! 现在我们拥有测试分片群集的基础架构。 但是,等等!我们还没有分割群集。 下一步是将分片添加到集群。 为此,我们必须将我们已经开始的mongos实例连接到查询路由器:
一旦在mongos shell上,我们必须按照以下方式执行addShard方法:
如果我们想检查前面的操作的结果,我们可以执行status()命令并查看关于创建的分片的一些信息:
在返回的文档中,我们只能看到基本信息,例如主机用于我们的分片群集和我们拥有的数据库。 现在,我们没有任何使用分片的集合。 出于这个原因,信息被大大简化。 现在我们有了分片,配置服务器和查询路由器,让我们在数据库中启用分片。 在对集合执行相同操作之前,首先需要在数据库中启用分片。 以下命令在称为电子商务的数据库中启用分片:
通过查看分片群集的状态,我们可以注意到有关于我们的电子商务数据库的信息:
设想在在电子商务数据库中,我们有一个包含以下文档的客户集合:
我们必须执行shardCollection命令来在这个集合中启用分片,使用集合名称和一个将我们的分片关键字表示为参数的文档。 让我们通过在mongos shell中执行以下命令来启用customers集合中的分片:
正如你所看到的,在命令执行过程中出现了问题。 MongoDB警告我们必须有一个索引,并且分片键必须是前缀。 所以,我们必须在mongos shell上执行以下序列:
不错! 现在我们拥有启用了分片的电子商务数据库的客户集合。
:
如果您正在分割一个空集合,则shardCollection命令将创建分片键的索引。
但是,决定选择address.zip并注册为分片键的因素是什么? 在这种情况下,正如我之前所说的,我选择了一个随机区域来进行说明。现在,我们来考虑哪些因素可以建立一个好的分片键。
7.1. 2 选择分片键的基本问题
选择哪个分片键不是一件容易的事,并且没有配方。 大多数情况下,事先了解我们的领域及其使用是最基本的。 这样做时必须非常小心。 一个不太合适的分片键可能会给我们带来一系列数据库问题,从而影响其性能。 首先是可分性。 我们必须考虑一个分片密钥,它允许我们可视化文档在分片中的分割。 具有有限数量值的分片键可能会导致"无法分离"块。 我们可以说这个领域必须具有很高的基数,比如具有多种值字段且字段唯一。 诸如电子邮件地址,用户名,电话号码,社会安全号码和邮政编码等标识字段是高基数领域的一个很好的例子。 事实上,如果我们考虑到某种情况,它们中的每一个都是唯一的。在电子商务系统中,如果我们有一个与装运有关的文件,我们将有多个具有相同邮政编码的文件。 但是,考虑另一个例子,一个城市美容院的目录系统。 那么,如果一个文件代表一家美容院,那么邮政编码将是一个比上一个例子更独特的编号。 第三个也许是迄今为止最激烈的一点,因为它以某种方式与最后一个矛盾。 我们已经看到,随机性程度高的分片键是尝试提高写操作性能的好实践。现在,我们将考虑创建分片键来针对单个分片。 当我们考虑读取操作的性能时,从单个分片中读取是一个好主意。正如您已经知道的,在分片集群中,数据库复杂性在查询路由器上被抽象化。 换句话说,mongos有责任发现它应该搜索查询中请求的信息。 如果我们的分片密钥分布在多个分片中,那么mongos将搜索分片上的信息,收集并合并它们,然后传递它。 但是,如果分片键计划定位到单个分片,那么mongos任务将搜索此独特分片中的信息,并按顺序传递它。 第四点也是最后一点是关于我们在文档中没有任何字段的情况,这对我们的分片键来说是个不错的选择。 在这种情况下,我们必须考虑一个合成的分片键。 在前面的例子中,我们使用了字段为address.zip和注册的组合分片键。 由于如果分片键的第一个值没有高基数,添加第二个值将增加基数,因此组成分片键还将帮助我们获得更多可分割键。 所以,这些基本问题告诉我们,根据我们想要搜索的内容,我们应该为分片密钥的文档选择不同的方法。 如果我们需要查询隔离,那么可以集中在一个分片上的分片键是一个不错的选择。 但是,当我们需要升级写入操作时,我们的分片键越随机,表现越好。
第七章 第一节就到此,请持续关注,还有下一节。
领取专属 10元无门槛券
私享最新 技术干货