MongoDB 是现代高性能应用开发者的首选 NoSQL 文档数据库。凭借其类似 JSON 的文档,MongoDB 以其横向扩展和负载均衡而闻名,为开发者提供了定制性和可扩展性的完美平衡。
但像任何高性能工具一样,MongoDB 在专家手中表现最佳。性能问题可能表明数据库没有发挥出应有的潜力,特定的优化可能带来更好的性能。
在这篇文章中,我们将通过以下内容来探讨如何使用 MongoDB 实现可扩展的性能
请注意,我们将要介绍的最佳实践并非详尽无遗(那将需要一篇更长的文章)。
虽然任何对文档数据库平台感兴趣的人都可以从这篇文章中学到一些东西,但如果你是以下情况,你可能会发现这些信息特别有用:
作为经验丰富的 MongoDB 开发者开始你的第一个项目。
在 Atlas 上运行 MongoDB,这是全托管、全球云数据库服务
自行管理 MongoDB
如果你只有几分钟时间,这篇快速的性能常见问题解答可能很有用
即兴查询、索引和实时聚合提供了强大的数据访问方式。MongoDB 默认是分布式数据库,这允许在不更改应用程序逻辑的情况下进行横向扩展。
非常快。主键或索引查询只需几毫秒。没有索引的查询取决于集合大小和机器规格等。
这取决于你目前做了什么和没做什么。尝试添加索引。不要进行连接(内嵌更可取)。升级你的机器规格。如果你还没有,绝对尝试分片以实现横向扩展。
MongoDB 需要足够的 RAM 来在内存中存储你的工作集。当然,确切的答案取决于你的数据大小和你的工作负载。你可以使用 MongoDB Atlas 进行自动扩展。
当然,它非常适合大数据集。MongoDB Atlas 可以处理跨对象存储(例如,Amazon S3)和文档存储的联合查询。
那么,我们就来谈谈从你的 MongoDB 数据库中获得最佳性能的五大最佳实践。
大多数开发者都会同意,优化性能的第一步是了解预期和实际的查询模式。一旦你像自己的手掌一样熟悉了应用程序的查询模式,你就可以相应地设计数据模型并选择合适的索引。
使用MongoDB,开发者可以访问一些强大的工具,这些工具可以帮助他们极大地提高性能——但这并不意味着可以忽视查询模式和配置文件。
例如,提高性能的一个简单方法是通过分析你的查询模式,确定可以在哪里嵌入数据,而不是在应用程序内或数据库内进行连接。
在确定你的主要查询模式之后,提高MongoDB性能的其他方法包括
将频繁子查询的结果存储在文档中以减少读取负载
确保你对你经常查询的字段有索引
查看你的日志以识别慢查询,然后检查你的索引
MongoDB以其灵活的架构而闻名,但这并不意味着你可以忽略架构设计最佳实践。你应该在项目的开始时就确定你的架构,这样你就不必在以后重新配置一切。这100%适用于你的数据模型。
在设计你的数据模型时,你必须决定如何建模数据之间的关系。例如,决定何时在一个文档中嵌入文档或在不同集合的不同文档之间创建引用,这是一个特定于应用程序的考虑。
JSON文档的一个主要优势是它们允许开发者根据应用程序的需求建模数据。嵌套数组和子文档允许你使用简单的文本文档来建模数据之间的复杂关系。
但是,使用MongoDB,你也可以建模
平面、表格和列式结构
简单的键值对
地理空间数据
时间序列数据
连接图数据结构的节点和边等
数据建模是一个庞大而广泛的话题,你可能会花几个月的时间来学习。如果你还没有,以下是一些可能有助于你的资源
MongoDB文档包含一个关于数据建模的精彩部分,从规划文档数据模型开始,并详细介绍了嵌入式和引用等具体内容。
MongoDB大学提供了一门免费的数据建模培训课程。这对于初学者来说是一个很好的开始,可以帮助他们进行架构设计和文档数据模型。
数据建模的自然扩展是嵌入,它允许你避免应用程序连接,从而最小化查询和更新。
值得注意的是,具有1:1关系的应该嵌入到单个文档中。具有1:n关系的,其中“n”个对象与父文档一起出现或被查看,也是嵌入的良好候选者。因为这些类型的数据总是一起访问,所以将它们存储在同一文档中是合情合理的。
由于这种类型的数据具有这种数据局部性,嵌入通常为读取操作提供更好的性能。嵌入的数据模型还允许开发者在单个写操作中更新相关数据,因为单个文档写操作是事务性的。
然而,并非所有1:1和1:n关系都适合在单个文档中嵌入。这时就需要在集合中不同文档之间进行引用。
在建模许多对许多关系时,引用更有意义。但是,在引用时,你的应用程序必须发出后续查询以解决任何引用。这反过来又需要更多的往返服务器。
当以下情况发生时,你应该考虑引用
文档经常被访问,但其中包含的数据很少使用。嵌入只会增加内存需求,因此引用可能更有意义。
文档的一部分经常更新并且不断变长,而文档的其余部分相对静态。
文档大小超过了MongoDB的16MB文档限制。这可能在建模多:1关系时发生,例如产品评论:产品。
与大多数数据库一样,MongoDB在应用程序的工作集(例如,索引和频繁访问的数据)没有问题地适合内存时表现最佳。虽然其他因素也会影响性能,但RAM大小显然是实例大小最重要的考虑因素。
当应用程序的工作集适合RAM时,从磁盘的读取活动应该很低。但如果您的工作集超过了实例大小或服务器的RAM,读取活动将开始急剧上升。如果您注意到这种情况发生,您可能可以通过迁移到具有更多内存的大实例来解决问题。
或者,您可以在多个服务器上分区(分片)您的数据库(关于这一点稍后讨论)。
无论是运行MongoDB Atlas还是自行管理MongoDB,正确调整工作集的大小都非常重要。如果您使用Atlas,请记住始终查看您的Atlas大小和等级选择文档,以正确计算您的工作集大小。
值得一提的是,在MongoDB Atlas中,扩展内存是自动化的,也很简单。例如,您可以选择加入集群等级自动扩展,它会根据实时变化的应用程序需求自动调整计算能力。
在讨论提高性能或水平扩展时,不提及复制是不完整的,复制通过水平扩展增加了数据可用性。复制可以提高性能并提供冗余,从而提供更安全。
在MongoDB中,通过副本集实现复制,允许开发人员从主服务器或节点复制数据到多个从节点。这允许您的应用程序在从节点上运行一些查询而不是在主节点上,从而避免竞争并提高负载均衡。
副本集为MongoDB开发人员提供了一些优势
冗余和数据可用性:在灾难性事件(如硬件故障或服务器崩溃)的情况下,复制非常有用。如果主节点失败,选举过程将自动从剩余的从节点中选举一个新的主节点。
负载分担:副本集为您的应用程序提供了更好的可伸缩性。例如,开发人员可以配置他们的应用程序以从多个服务器读取,以帮助在副本集之间进行负载均衡。
数据本地性:在性能方面,复制也提高了读取操作的延迟。如果您有相同的数据分布在多个服务器上,则可以在距离最终用户最近的位置访问这些数据。
MongoDB中的分片集群是另一种可能提高性能的方法。与复制一样,分片是将大型数据集分布在多个服务器上的方法。使用所谓的分片键,开发人员可以将数据片段(或“分片”)复制到多个服务器。这些服务器一起工作以利用所有数据。
分片带来了几个优势,包括读取/写入的水平扩展、增加的存储容量和更高的可用性。
这又是一个关于MongoDB顶级性能最佳实践的列表,但并不全面。正如任何经验丰富的数据库开发人员都会告诉您的,有无数的事情可以做来提高性能——它们都取决于您的具体应用程序。
更重要的是,始终记住适当的数据建模、索引、嵌入和引用是基本考虑因素。假设您非常了解您应用程序的查询模式,您会发现您可以从MongoDB的分布式和复制特性中获得稳定性能和很多额外的优势。
如果所有其他方法都失败了...我们提到过MongoDB Atlas还有一个内置的性能顾问吗?如果您不确定从哪里开始,它可以让您的生活变得容易得多。