欢迎阅读有关MongoDB性能最佳实践的系列博文的第五篇。
在这个系列中,我们从多个重要维度上讨论实现大规模性能的关键考虑因素,包括:
- 数据建模和内存大小,即工作集
- 查询模式和性能分析
- 索引
- 分片
- 事务和读/写关注点(本期讨论的内容)
- 硬件和操作系统配置
- 基准测试
单文档的原子性
MongoDB的文档模型可以将相关数据汇集到一起,简化了传统关系型数据库中需要通过父子表关系建模的复杂性。其单文档操作具备原子性,能够满足大多数应用程序对数据完整性的要求。
在MongoDB中,单个操作可以同时更新多个字段,包括对多个子文档和数组元素的修改。MongoDB首先会确保文档在更新过程中的完全隔离;同时,任何操作错误都会触发回滚机制,保证客户端获取的文档总是一致的。
多文档ACID事务的引入
MongoDB中的事务为开发者提供了一种熟悉的体验,如同关系型数据库中的事务一样,具有多语句支持和相似的语法结构,便于集成到任何应用程序中。事务通过提供快照隔离来确保数据的一致性,并且遵循“全有或全无”的原则,同时对那些不依赖于事务特性的工作负载的性能没有负面影响。
您可以通过查阅我们在VLDB会议上发布的论文中的TPC-C基准测试结果来了解事务的性能表现。
此外,我们提供了一些策略,帮助您在应用程序中最大限度地利用MongoDB事务的优势。
多文档事务的最佳实践
创建长时间运行的事务,或在单个ACID事务中执行过多操作,都可能对WiredTiger存储引擎的缓存造成显著压力。这是因为缓存需要从最早的快照创建开始,就为后续所有的写入操作保持状态。由于事务在运行过程中始终使用同一快照,因此缓存中会不断积累新的写入,直到长时间运行的事务提交或中止,释放其所持锁定时,这些写入才能从缓存中被清除。
为了保持数据库性能的可预测性,开发人员应考虑以下建议。
(1)事务运行时限制
默认情况下,MongoDB会自动终止运行时间超过60秒的多文档事务。不过,如果服务器的写入负载相对较低,您可以调整事务设置,延长其执行时间。
为了防止事务超时,建议将大型事务拆分成多个较小的操作,确保它们能够在设定的时间限制内完成。同时,应当优化查询模式,并确保拥有合适的索引,这样可以在事务过程中快速访问数据。
(2)事务中的操作数量
虽然在事务中读取的文档数量并没有严格的限制,但从最佳实践来看,建议在一个事务中修改的文档数量不要超过1,000个。
对于需要修改超过1,000个文档的操作,开发人员应考虑将这些操作分解为多个部分,每个部分处理一批文档,以此来组织事务。
(3)分布式、多分片事务
跨多个分片执行的事务会带来较高的性能开销,因为这需要在多个节点间通过网络进行协调。
在多分片环境中,只有使用快照读关注点(snapshot read concern)才能保证提供一致的数据快照。然而,如果对延迟的敏感度超过了对跨分片读取一致性的需求,可以选择默认的本地读关注点,该选项在每个分片的本地快照上进行操作。
(4)异常处理
当事务被中止时,相关的异常会被返回给客户端驱动程序,并且事务的更改会被完全撤销。开发人员需要在应用程序中实现逻辑来捕获这些异常,并对因暂时性问题(例如多版本并发控制(MVCC)的写入冲突、短暂的网络错误或主节点选举)而中止的事务进行重试。
当启用可重试写入功能时,MongoDB的驱动程序会自动重试提交事务的操作。
(5)写入延迟的优势
尽管刚开始可能不那么直观,但使用多文档事务实际上可以通过减少提交所需的延迟来提升写入性能。
当采用“w:majority”这一写关注点时,如果执行10次独立的更新操作,每次更新都必须等待复制到多数节点的时间。而如果把这10个更新操作放入一个事务中执行,这些操作会在事务提交时一次性复制。这种做法可以将延迟降低到原来的十分之一。
更多参考
您可以在MongoDB的多文档事务文档中查看所有最佳实践。有关性能特定的指导,请参考该文档的“生产考虑”部分。
选择适当的写保证
MongoDB允许您在执行写操作时选择所需的持久性级别,这被称为写关注点(write concern)。
值得注意的是,写关注点适用于数据库中的所有操作,无论是对单个文档的简单操作还是多文档事务的一部分。
您可以根据需要在每个连接、数据库、集合,甚至是单个操作的基础上配置以下选项:
已确认写入:这是默认设置。mongod确认执行了写操作,这样客户端就能捕捉到网络问题、键冲突、模式验证错误等异常。
已写入日志:mongod仅在操作被记录到主节点的操作日志后才确认写操作。这确保了即使mongod崩溃,写操作也能得到保留,保证了写入的持久性。
已复制:您还可以选择等待操作被副本集中的其他成员确认。MongoDB支持将写入确认到指定数量的副本。这也确保了写操作被记录在包括主节点在内的辅助节点的日志中。
大多数:这种写关注点等待写操作被大多数副本集成员应用,并且在主节点选举事件中不会被回滚。这也确保了写操作被记录在这些成员的日志中,包括主节点。
以上是MongoDB中关于写关注点的选项,它们帮助您根据应用需求调整数据的持久性和复制保证。
选择适当的读关注点
与写关注点类似,读关注点也适用于数据库中的任何查询操作,无论是对单个文档或一组文档的常规读取,还是作为多文档事务的一部分。
为了保证数据的隔离性和一致性,可以将读关注点设置为majority。这意味着只有当数据已经被复制到副本集大多数成员之后,这些数据才会返回给应用程序,从而保证在主节点选举过程中数据不会发生回滚。
MongoDB还提供了“可线性化”(linearizable)的读关注点级别。启用可线性化读关注点可以确保在读取数据时,该节点仍是副本集的主节点,并且在发生主节点切换后,所返回的数据不会被回滚。但是,配置此级别的读关注点可能会显著增加延迟,因此建议设置maxTimeMS值来为长时间运行的操作设定超时限制。
在需要时使用因果一致性
因果一致性确保在客户端会话中,无论请求被哪个副本节点服务,每次读操作都能看到前一次写操作的结果。您可以根据需要启用因果一致性,仅在需要保证读操作的顺序性时使用它,从而减少潜在的延迟影响。
设置阿里云MongoDB 的默认写关注
阿里云MongoDB 已最新支持 7.0 版本,您可以在阿里云MongoDB 实例详情页的「参数设置」部分,根据需要,对于阿里云MongoDB 的默认写关注进行设置。
更多内容可参考:
https://help.aliyun.com/zh/mongodb/product-overview/mongodb-versions-and-storage-engines
更多内容
以上是本期性能最佳实践系列的内容。在本系列的下一篇文章中,我们将讨论硬件和操作系统配置。访问阿里云官网了解更多 https://www.aliyun.com/product/mongodb?utm_content=g_1000376457