第七章:扩展伸缩性 扩展伸缩性-分片扩展MongoDB
Posted 3T教学技术派
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第七章:扩展伸缩性 扩展伸缩性-分片扩展MongoDB相关的知识,希望对你有一定的参考价值。
第七章:扩展伸缩性 扩展伸缩性(一)-分片扩展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开始:
mongod --fork --configsvr --dbpath /data/configdb --logpath /log/configdb.log
下一步是启动查询路由器。 查询路由器是一个mongos MongoDB实例,它使用指示配置服务器的参数--configdb <configdb hostname或ip:port>来路由对分片的查询和写入操作。 默认情况下,MongoDB在端口27017上启动它:
mongos --fork --configdb localhost --logpath /log/router.log
最后,让我们开始分片。 这个例子中的分片只是两个简单的mongod实例。 与mongos类似,默认情况下,mongod实例在端口27017上启动。 由于我们已经在这个端口上启动了mongos实例,我们为mongod实例设置一个不同的端口:
mongod --fork --dbpath /data/mongod1 --port 27001 --logpath /log/mongod1.logmongod --fork --dbpath /data/mongod2 --port 27002 --logpath /log/mongod2.log
完成! 现在我们拥有测试分片群集的基础架构。 但是,等等!我们还没有分割群集。 下一步是将分片添加到集群。 为此,我们必须将我们已经开始的mongos实例连接到查询路由器:
mongo localhost:27017
一旦在mongos shell上,我们必须按照以下方式执行addShard方法:
mongos> sh.addShard("localhost:27001")mongos> sh.addShard("localhost:27002")
如果我们想检查前面的操作的结果,我们可以执行status()命令并查看关于创建的分片的一些信息:
mongos> sh.status()--- Sharding Status ---sharding version: {"_id" : 1,"minCompatibleVersion" : 5,"currentVersion" : 6,"clusterId" : ObjectId("54d9dc74fadbfe60ef7b394e")
}
shards:
{ "_id" : "shard0000", "host" : "localhost:27001" } { "_id" : "shard0001", "host" : "localhost:27002" } databases: { "_id" : "admin", "partitioned" : false, "primary" : "config" }
在返回的文档中,我们只能看到基本信息,例如主机用于我们的分片群集和我们拥有的数据库。 现在,我们没有任何使用分片的集合。 出于这个原因,信息被大大简化。 现在我们有了分片,配置服务器和查询路由器,让我们在数据库中启用分片。 在对集合执行相同操作之前,首先需要在数据库中启用分片。 以下命令在称为电子商务的数据库中启用分片:
mongos> sh.enableSharding("ecommerce")
通过查看分片群集的状态,我们可以注意到有关于我们的电子商务数据库的信息:
mongos> sh.status()--- Sharding Status ---sharding version: {"_id" : 1,"minCompatibleVersion" : 5,"currentVersion" : 6,"clusterId" : ObjectId("54d9dc74fadbfe60ef7b394e")
}
shards:
{ "_id" : "shard0000", "host" : "172.17.0.23:27017" } { "_id" : "shard0001", "host" : "172.17.0.24:27017" } databases: { "_id" : "admin", "partitioned" : false, "primary" : "config" } { "_id" : "ecommerce", "partitioned" : true, "primary" : "shard0000" }
设想在在电子商务数据库中,我们有一个包含以下文档的客户集合:
{"_id" : ObjectId("54fb7110e7084a229a66eda2"),"isActive" : true,"age" : 28,"name" : "Paige Johnson","gender" : "female","email" : "paigejohnson@combot.com","phone" : "+1 (830) 484-2397","address" : {"city" : "Dennard","state" : "Kansas","zip" : 2492,"latitude" : -56.564242,"longitude" : -160.872178,"street" : "998 Boerum Place"},"registered" : ISODate("2013-10-14T14:44:34.853Z"),"friends" : [
{"id" : 0,"name" : "Katelyn Barrett"},
{"id" : 1,"name" : "Weeks Valentine"},
{"id" : 2,"name" : "Wright Jensen"}
]
}
我们必须执行shardCollection命令来在这个集合中启用分片,使用集合名称和一个将我们的分片关键字表示为参数的文档。 让我们通过在mongos shell中执行以下命令来启用customers集合中的分片:
mongos> sh.shardCollection("ecommerce.customers", {"address.zip": 1,"registered": 1})
{"proposedKey" : {"address.zip" : 1,"registered" : 1
},"curIndexes" : [
{"v" : 1,"key" : {"_id" : 1
},"name" : "_id_", "ns" : "ecommerce.customers" } ], "ok" : 0, "errmsg" : "please create an index that starts with the shard key
before sharding." }
正如你所看到的,在命令执行过程中出现了问题。 MongoDB警告我们必须有一个索引,并且分片键必须是前缀。 所以,我们必须在mongos shell上执行以下序列:
mongos> db.customers.createIndex({"address.zip": 1, "registered": 1})
mongos> sh.shardCollection("ecommerce.customers", {"address.zip": 1,"registered": 1})
{ "collectionsharded" : "ecommerce.customers", "ok" : 1 }
Well done! Now we have the customers collection of the ecommerce database with the shard enabled.
不错! 现在我们拥有启用了分片的电子商务数据库的客户集合。
:
如果您正在分割一个空集合,则shardCollection命令将创建分片键的索引。
但是,决定选择address.zip并注册为分片键的因素是什么? 在这种情况下,正如我之前所说的,我选择了一个随机区域来进行说明。现在,我们来考虑哪些因素可以建立一个好的分片键。
7.1. 2 选择分片键的基本问题
第七章 第一节就到此,请持续关注,还有下一节。
以上是关于第七章:扩展伸缩性 扩展伸缩性-分片扩展MongoDB的主要内容,如果未能解决你的问题,请参考以下文章