随着实时应用程序和物联网(IoT)设备的使用,以及非结构化数据资产的指数级增长,越来越多的组织正在转向NoSQL数据库。事实上,预计到2032年,NoSQL市场将达到745亿美元,从2024年到2032年的增长率(CAGR)为24.9%(IMARC集团,2024年)。
这种增长并不令人惊讶,因为NoSQL数据库管理系统(DBMS)能够有效管理大型、多样化的数据集和相关的大数据分析。然而,许多人仍然认为NoSQL DBMS无法满足许多组织的关键要求——ACID事务管理和合规性。好消息是,一些NoSQL DBMS绝对可以做到这一点!
在这篇文章中,我们将讨论ACID事务是什么,ACID事务属性,为什么这些事务很重要,以及NoSQL DBMS中的ACID事务示例。
目录
在最基本的层面上,数据库事务是一组根据DBMS定义(例如,定义的事务标准)成功完成的数据库读取和写入操作。主要有两种类型的交易
单一事务:单一事务指的是一系列一个或多个数据库操作,导致一个动作,成功完成。一旦完成,事务被接受,可以在事务日志中找到。单一事务的一个常见例子是从ATM机取款。
多事务:多事务,有时称为分布式事务,由多个相互依赖的事务组成,这些事务分布在不同的数据库和系统(例如,分布式系统)中。这些事务的记录也存在于事务日志中。这些交易的例子包括从一个账户向另一个账户转账或雇主为新员工发放带有照片的安全徽章。
需要注意的是,某些交易需要遵守严格的数据完整性标准(例如,数据是完整和正确的)和数据一致性标准(例如,值在所有表/数据库中相同)。这通常涉及信托责任或监管合规性。例如,商业银行业务、投资经纪和法律结算。在这些情况下,仅仅遵守DBMS定义的标准是不够的,需要ACID事务。
ACID是一个代表原子性、一致性、隔离性和持久性的缩写(ACID)。ACID属性共同确保一组数据库操作(在事务中分组)即使在意外错误发生时也能将数据库保持在有效状态。此外,ACID事务提供了许多监管机构要求的交易保证水平。
以下是每个ACID事务元素的概述以及NoSQL文档数据库如何处理这些ACID元素的一般描述。本文中,将使用MongoDB Atlas。
原子性保证事务中所有组成命令被视为一个单一单元,要么一起成功,要么一起失败。这在系统故障或断电的情况下非常重要,如果事务没有完全处理,它将被丢弃,数据库保持其数据完整性。
在MongoDB中,单个文档级别的写操作是原子的,即使该操作修改了单个文档内的多个嵌入文档。对于需要多个文档(在单个集合或多个集合中)的读写原子性的情况,MongoDB支持分布式事务,包括对副本集和分片集群的事务。
一致性保证事务内所做的更改在整个数据库系统(例如,节点)中填充,并且符合DBMS约束。如果事务在不一致状态下将负面影响数据一致性,则整个事务将失败。
MongoDB如何处理一致性MongoDB提供了灵活地将数据规范化或复制的选项,以优化应用程序。如果数据在模式中重复,则开发人员必须决定如何在不同集合中保持重复数据的一致性。某些应用程序需要立即使重复数据保持一致,而其他应用程序可以容忍读取旧数据。以下是一些示例
注意:了解有关数据一致性的更多信息。
每个事务都与其他事务隔离,以防止数据冲突。这还有助于数据库操作在管理多个条目和多级事务方面的关系。例如,如果有两个用户试图修改相同的数据(甚至相同的交易),则DBMS使用称为锁管理器的机制来暂停其他用户,直到第一个用户所做的更改完成。
MongoDB使用一种称为快照隔离的技术(例如,每个事务似乎都在事务开始时对数据库的个人快照进行操作)。事务可以从事务开始时提交的数据“快照”中读取数据,任何冲突的更新都将导致事务中止。
此外,MongoDB事务支持事务级读取关注点和事务级写入关注点。客户端可以设置适当的读取和写入关注级别,其中最严格的是快照读取关注点与多数写入关注点相结合。多数写入关注点意味着写入操作已持久地提交到计算出的多数数据承载节点(由开发者配置)。
持久性保证一旦事务完成并且更改已写入数据库,它们就会被持久化。这确保了即使系统出现故障(如崩溃或断电),系统中的数据也会持续存在。持久性的概念是数据可靠性的关键要素。
MongoDB创建一个包含每个“写入”磁盘位置和更改字节的OpLog。如果在事务写入过程中发生不可预见的事件(例如,断电),则在系统再次启动时可以使用OpLog重放任何在关闭前未刷新到磁盘的写入。此外,操作在写入OpLog之前更改,以便它们是幂等的,可以多次重试。默认情况下,事务或“写入”每60秒大约刷新到磁盘一次。
ACID事务有助于维护数据完整性和可靠性,同时确保受政府或行业监管的必要数据(例如,银行账户、股票组合)符合要求标准。此外,ACID合规性通常是实现数据复制和在分布式数据库系统中实现高可用性的先决条件。
使用NoSQL文档数据库MongoDB Atlas,以下是一个关于如何处理ACID多文档事务以及如何保证ACID事务符合最小ACID属性标准的示例。
想象你正在构建一个函数,从一个银行账户向另一个账户转账,其中每个账户都是其自己的记录。如果成功从源账户取款但未向目标账户贷记,则创建了严重的会计问题。相反,如果目标账户已贷记但源账户从未借记,则另一个严重的会计问题发生。
该图展示了ACID属性如何影响从一方银行账户转账到另一方的流程。
这两个写入操作必须同时发生或同时不发生,以保持系统和其数据的连续性。此外,这意味着如果事务中的任何命令失败,数据库必须回滚(例如,撤销)它在事务过程中写入的所有更改。
注意:要了解更多信息,请访问Node.js 快速入门 GitHub 仓库,以获取完整的代码示例并自行运行。
在处理分布式系统中的多文档事务时,请记住,这可能会对资源限制和性能目标产生影响。此外,由于数据库必须“锁定”所涉及的资源以防止并发写入相互干扰(例如,事务失败),尝试写入数据的其他客户端可能陷入等待事务完成的僵局,这可能会影响应用程序延迟和用户体验。
MongoDB 的文档模型允许将相关数据存储在单个文档中。文档模型结合原子文档更新,在大多数情况下可以消除对事务的需求。尽管如此,在某些情况下,真正的多文档、多集合 MongoDB 事务是最佳选择。
MongoDB 事务的工作方式与其他数据库中的事务类似。要使用事务,通过驱动程序启动 MongoDB 会话。然后,使用该会话执行您的数据库操作组。您可以在多个文档、集合和分片上运行任何 CRUD(创建、读取、更新和删除)操作。
有关如何实现事务的具体代码示例,请参阅 MongoDB 开发者中心的快速入门指南
访问MongoDB 驱动程序文档,获取 MongoDB 官方支持的每种语言的特定指南。您还可以查看事务最佳实践和生产注意事项列表。
需要事务的应用程序通常具有在不同各方之间交换值的用例。这些通常是“记录系统”或“业务线”应用程序。
可能从多文档事务中受益的示例应用程序包括
将资金从一个账户转移到另一个账户的系统(例如,银行应用程序、支付处理系统、交易平台)。
供应链和预订系统,其中商品和服务的所有权从一方转移到另一方。
计费系统,它存储详细信息记录以及汇总记录。
通常,建议以这种方式对数据进行建模,以便一起访问的数据存储在一起。当以这种方式对数据进行建模时,不仅可以实现更好的性能,而且不需要事务。
对于需要事务的应用程序,请遵守以下最佳实践
将长时间运行的事务分解为更小的部分,以确保它们不超过默认的 60 秒超时。(注意,此超时可以延长。)确保事务中的操作使用索引,以便它们快速运行。
将每个事务限制为 1,000 个文档修改。
确保配置了适当的读取和写入关注点(注意,从版本 5.0 开始,MongoDB 默认为必要的多数写入关注点)。
添加适当的错误处理 并重试因暂时性错误而失败的交易。
记住影响多个分片的交易的性能成本。有关这些最佳实践的更多信息,请参阅MongoDB的“多文档ACID事务”白皮书以及MongoDB事务文档。
准备好学习更多吗? MongoDB Atlas 是MongoDB的全托管数据库即服务,它是开始使用MongoDB的最简单方式。通过 创建免费的MongoDB Atlas集群 来开始使用交易。