原文地址:Best Practices Guide for MongoDB Performance
一、前言
MongoDB 是面向开发高性能应用程序的现代开发人员的主要 NoSQL 文档数据库。MongoDB 采用类似 JSON 的文档,以水平扩展和负载平衡著称,为开发人员提供了定制化和可扩展性之间的绝佳平衡。
但是,与其他高性能工具一样,MongoDB 在熟悉业务的专家手中才能发挥最佳性能。性能问题可能表明数据库没有尽最大努力工作,而特定的优化可以带来更好的性能。
在本篇文章中,我们将重点介绍如何使用 MongoDB 实现大规模性能。请记住,我们要介绍的最佳实践并不是详尽无遗的(这需要更长的篇幅)。
二、谁应该阅读本指南?
尽管任何对文档数据库平台感兴趣的人都可以从本篇文章中学到一些东西,但如果你是以下情况,你可能会发现这些信息特别有用:
- 作为一名经验丰富的 MongoDB 开发人员开始第一个项目
- 在全面管理的全球云数据库服务 Atlas 上运行 MongoDB
- 自己管理 MongoDB
三、MongoDB 性能常见问题
如果您只有几分钟的空闲时间,这个快速性能常见问题解答可能会对您有所帮助:
- 为什么 MongoDB 性能很高?
为即席查询、索引和实时聚合提供了强大的数据访问方式。MongoDB 默认为分布式数据库,因此无需更改应用程序逻辑即可实现广泛的横向扩展性。
- MongoDB 查询速度有多快?
非常快。主键或索引查询只需几毫秒。不带索引的查询取决于集合大小和机器规格等。
- 如何让 MongoDB 更快?
这取决于你已经在做什么和还没有做什么。尝试添加索引。不要做 join 查询(最好是嵌入)。升级你的机器规格。如果还没有,一定要尝试分片,以实现水平扩展。
- MongoDB 需要多少内存?
MongoDB 需要足够的内存来存储工作集。当然,具体答案取决于您的数据大小和工作负载。您可以使用 MongoDB Atlas 进行自动扩展。
- MongoDB 适合大型数据吗?
当然可以。MongoDB 非常适合大型数据集。MongoDB Atlas 可以处理跨对象存储(如亚马逊 S3)和文档存储的联合查询。
废话不多说,让我们来看看让 MongoDB 数据库达到最佳性能的 5 大最佳实践。
四、最佳实践 1:检查查询模式和分析查询
大多数开发人员都同意,优化性能的第一步是了解预期和实际查询模式。一旦对应用程序的查询模式了如指掌,就可以据此设计数据模型并选择适当的索引。
使用 MongoDB,开发人员可以使用多种强大的工具,帮助他们大大提高性能,但这并不意味着可以忽略查询模式和配置文件。
例如,提高性能的一个简单方法是分析查询模式,确定可以在哪些地方嵌入数据,而不是进行应用内或数据库内连接。
确定主要查询模式后,提高 MongoDB 性能的其他方法包括
- 将频繁子查询的结果存储在文档中,以减少读取负载
- 确保在经常查询的字段上有索引
- 查看日志以确定缓慢的查询,然后检查索引
五、最佳实践 2:审查数据建模和索引
MongoDB 以其灵活的模式而著称,但这并不意味着您可以忽略模式设计的最佳实践。您应该在项目开始时就确定模式,这样以后就不必重新调整一切。这一点也适用于数据模型。
在设计数据模型时,您必须决定如何为数据之间的关系建模。例如,决定何时嵌入文档或在不同集合中的独立文档之间创建引用,都是针对特定应用的考虑因素。
JSON 文档的一个主要优势是,它允许开发人员根据应用程序的需要为数据建模。通过嵌套数组和子文档,您可以使用简单的文本文档为数据之间的复杂关系建模。
但使用 MongoDB,您还可以为以下数据建模:
- 平面、表格和列式结构
- 简单的键值对
- 地理空间数据
- 时间序列数据
- 连接图数据结构的节点和边等。
数据建模是一个庞杂的话题,你可以花上几个月的时间来学习。如果你还没有学习过,这里有一些资源可能会对你有所帮助:
- MongoDB 文档中有一个关于数据建模的重要部分,从规划文档数据模型开始,详细介绍了嵌入和引用等具体内容。
- MongoDB 大学提供有关数据建模的免费培训课程。对于初学者来说,这是开始学习模式设计和文档数据模型的好方法。
六、最佳实践 3:尝试嵌入和引用
嵌入是数据建模的自然延伸,可以避免应用程序连接,从而最大限度地减少查询和更新。
值得注意的是,具有 1:1 关系的数据应嵌入到单个文档中。具有 1:1 关系的数据(其中 “许多” 对象与其父文档一起出现或一起查看)也非常适合嵌入。因为这些类型的数据总是一起被访问,所以将它们一起存储在同一文档中是合理的。
由于这种数据位置性,嵌入通常能为读取操作提供更好的性能。嵌入式数据模型还允许开发人员在单个写入操作中更新相关数据,因为单个文档的写入是事务性的。
不过,并非所有 1:1 和 1:many 关系都适合嵌入到单个文档中。这就需要在不同集合中的文档之间进行引用。
在对多对多关系建模时,引用更有意义。但是,无论何时引用,应用程序都必须发出后续查询以解决任何引用问题。这反过来又需要更多的服务器往返。
在以下情况下,您应该考虑引用
- 文档被频繁访问,但其中包含的数据很少被使用。嵌入只会增加内存需求,因此引用可能更有意义。
- 文档的一部分经常更新且不断变长,而文档的其余部分则相对静态。
- 文档大小超过了 MongoDB 的 16MB 文档限制。这种情况可能发生在 many:1 关系建模时,例如 产品评论:产品。
七、最佳实践 4:确定内存使用情况(在 Atlas 中更简单)
与大多数数据库一样,当应用程序的工作集(如索引和频繁访问的数据)能够顺利地容纳在内存中时,MongoDB 的性能最佳。虽然其他因素也会影响性能,但内存大小显然是实例大小最重要的考虑因素。
当应用程序的工作集适合放在内存中时,从磁盘读取数据的活动就会减少。但如果工作集超过了实例大小或服务器的内存,读取活动就会开始激增。如果发现这种情况,可以通过转移到内存更大的实例来解决问题。
或者,也可以在多个服务器上对数据库进行分区(shard)(稍后详述)。
无论是运行 MongoDB Atlas 还是自己管理 MongoDB,适当调整工作集的大小都至关重要。如果您使用的是 Atlas,请务必查看 Atlas 大小和层级选择文档,以正确计算工作集的大小。
值得指出的是,在 MongoDB Atlas 中,内存的缩放是自动且直接的。例如,您可以选择群集层自动缩放,它可以根据应用需求的实时变化自动调整计算能力。
注:企业版才有 MongoDB Atlas
八、最佳实践 5:监控复制和分片
在讨论提高性能或横向扩展时,不能不提到复制,它可通过横向扩展提高数据可用性。复制可以提高性能,还可以提供冗余,从而提供更高的安全性。
在 MongoDB 中,复制是通过复制集完成的,它允许开发人员将主服务器或节点上的数据复制到多个辅助服务器或节点上。这样,您的应用程序就可以在辅助服务器上运行某些查询,而不是在主服务器上运行,从而避免了竞争,提高了负载平衡。
副本集为 MongoDB 开发人员提供了多项优势:
- 冗余和数据可用性: 复制在发生硬件故障或服务器崩溃等灾难性事件时非常有用。如果主节点发生故障,选举过程会自动从剩余的次节点中选出一个新的主节点。
- 负载分担: 复制集可为应用程序提供更好的可扩展性。例如,开发人员可以配置其应用程序从多个服务器读取数据,以帮助在副本集之间实现负载平衡。
- 数据本地性: 在性能方面,复制还能改善读取延迟。如果将相同的数据分散到多个服务器上,就可以在离最终用户最近的位置访问这些数据。
MongoDB 中的分片集群是另一种可能提高性能的方法。与复制一样,分片也是在多个服务器之间分发大型数据集的一种方式。使用所谓的分片密钥,开发人员可以在多个服务器之间复制数据片段(或 “分片”)。这些服务器协同工作,利用所有数据。
分片有几个优点,包括读/写的水平扩展以及存储容量的增加和可用性的提高。
九、请记住,最佳实践在不断改进
再次重申,这是一份不全面的 MongoDB 顶级性能最佳实践列表。任何一位经验丰富的数据库开发人员都会告诉你,要提高性能,你可以做的事情千千万万,而这一切都取决于你的具体应用。
更重要的是,请始终记住,适当的数据建模、索引、嵌入和引用是基本的考虑因素。如果您对自己应用程序的查询模式了如指掌,您就会发现,您可以从 MongoDB 的分布式和复制特性中获得稳定的性能和大量额外的收益。