事务理解(ACID)

有些人抱怨,常用的两阶段提交在性能和可用性方面代价太高而我们认为事务滥用和过度使用所引入的性能瓶颈应该主妥由应用层未解决,而不是简单的抛弃事务。
一-James Corbett 等,Spanner:来自 Google 的全球分布式数据库( OSDI 2012)

什么是事物?

在一个严格要求数据准确性的环境中,会有许多可能出错的情况,如:

  • 服务器处理业务时报错,出现异常
  • 数据库软件异常,导致增删改出错
  • 服务器宕机
  • 服务器和数据库之间连接中断。
  • 多个客户端同时写入数据,导致数据覆盖
  • 客户端读到一些无意义部分更新的数据。
  • 客户端之间由于边界条件竞争所引入的各种奇怪问题

为了保证数据的准确性,可靠性。为了系统高可靠,高可用的目标。我们必须处理好上述问题,万一发生类似的情况确保不会出现系统级的失效。然而,完善的容错机制需要大量的工作,要仔细考虑各种各样出错的可能,并进行充分的测试才能保证方案切实可行。

事务一直是简化这些问题的首选机制。事务将应用程序的多个读写操作捆绑在一起成为一个逻辑操作单元,即事务中的所有读写是一个执行的整体,整个事务要么成功、要么失败。如果失败则回滚数据,那么应用程序可以安全的进行重试。这样就不需要担心部分失败的问题,应用层的错误处理就回简单很多。

事务的概念也许并非如此简单,细究起来,事务并非一个天然存在的东西,它是被创造出来的,目的是简化应用层的编程模型。有了事务应用程序可以不用考虑数据部分错误,客户端脏数据读取,服务器脱机数据保存一半等问题,这些都可以交由给事务来处理。
然而并非每个应用程序都需要事务机制,有时可以弱化或放弃事务,一些安全相关的属性也会避免引入事物。那放弃事务是为什么呢?为了换取更高的性能或更高的可用性。

那该如何判断是否需要事务呢?为了回答这个问题,我们首先需要确切地理解事务能够提供哪些安全性保证,背后的代价又是什么。 事务的概念看似简单,实际上却有许多微妙而关键的细节值得研究。

深入理解事务

目前几乎所有的关系数据库和一些非关系数据库都支持事务处理。它们大多数都沿用IBM于1975年推出的第一个SQL数据库“System R”相似的总体设计。尽管在一些具体实现方面有些不同,但事务的概念几乎没有发生任何变化,换句话说Mysql、Oracle、SQL Server、PostgreSQL等系统实现的事务与当年System R非常相似。

21世纪末,非关系型数据库(NoSql)开始兴起。它们的目标是通过提供新的数据模型,以及内置的复制和分区等手段来改进传统的关系型数据库。然而事务却成了这场变革的受害者,很多新一代数据库完全放弃了事务支持,或者将其重新定义,替换成比以前弱很多的保证。

与其他技术一样,事务有其优势,也有其自身的局限性。为了更好的理解事务设计的权衡知道让我们考虑正常运行和各种极端情况,详细分析事务可以为我们提供哪些保证。

ACID定义

ACID分别代表原子性(Atomicity),一致性(Consistency),隔离性(Isolation),持久性(Durability),取这四个特性的首字母就是ACID了。最早由TheoHarder和Andreas Reuter于1983年为精确描述数据库的容错机制而定义。

顺便普及下BASE。即基本可用性(Basically Available),软状态(Soft state)和最终一致性(Eventual consistency)。

原子性(Atomicity)

通常原子指不可再分解最小粒度的东西。这个术语在计算机的不同领域有着相似却不同的差异。
如:多线程中,某线程执行原子性操作,意味着其它线程无法看到操作该线程操作中发生的变化。只能看到操作前和操作后的状态。
而ACID中的原子性并不关乎多个操作的并发性,它并没有描述多个线程试图访问相同数据会发生什么(即“隔离性”)。
原子性指每一次的提交要么一起成功,要么一起失败。
如:客户端发起一个多次写操作请求时,如果在写入一部分数据后,系统发生故障,可能进程崩溃,可能网络中断,磁盘满了等;把多个写操作纳入到一个原子事务,万一出现上述故障导致最终无法完成提交时。此时事务会终止,且数据库需丢弃或撤销这些局部完成的更改。
假如没有原子性的保证,当多个更新操作中间发生了错误,就需要知道哪些更改已经生效,哪些没有生效,这个寻找过程非常繁琐且耗时,或许程序可以重试,但情况类似,并且可能导致重复更新或不正确的结果。原子性就大大简化了这个问题。如果事务中止,程序可以确定没有实质发生任何更改,可以安全地重试。

因此ACID中原子性的特性是:每一次的多次写操作提交要么一起成功,要么一起失败。

一致性(Consistency)

ACID 中的一致性的主要是指对数据有特定的预期状态,任何数据更改必须满足这些状态约束(或者恒等条件)。例如,对于一个账单系统,账户的贷款余额应和借款余额保持平衡。如果某事务从一个有效的状态开始,并且事务中任何更新操作都没有违背约束,那么最后的结果依然符合有效状态。

这种 致性本质上要求应用层来维护状态 致(或者恒等),应用程序有责任正确地定义 务来保持 致性。这不是数据库可以保证的事情:即如果提供的数据修改违背了恒等条件,数据库很难检测进而阻止该操作(数据库可以完成针对某些特定类型的恒等约束检查,例如使用外键约束或唯 性约束。但通常主要靠应用程序来定义数据的有效/无效状态,数据库主要负责存储)。

我认为ACID中的一致性更多是应用层的属性。应用程序可能借助数据库提供的原子性和隔离性达到一致性,但一致性本身不该源于数据库。所以我会认为C其实应该更偏向应用层。

隔离性(Isolation)

大多数数据库都支持多个客户端同时访问 。如果读取和写入的是不同数据,这肯定没有什么问题:但如果访问相同的记录, 可能会遇到并发问题(即带来竞争条件)。

假设有两个客户端同时增加数据库中的 个计数器。每个客户首先读取当前值 ,再客户端增加 ,然后写回新值(这里假设数据库尚不支持自增操作)。由于有两次相加,计数器应该由 34 增加到36 ,但实际上由于竞争条件最终结果却是35。
如下图所示:
image

ACID语义中的隔离性意味着并发执行的多个事务相互隔离,它们不能互相交叉。经典的数据库教材把隔离定义为可串行化,这意味着可以假装它是数据库上运行的唯一事务。虽然实际上它们可能同时运行,但数据库系统要确保当事务提交时,其结果与串行执行(一个接一个执行)完全相同。

持久性(Durability)

数据库系统本质上是提供一个安全可靠的地方来存储数据而不用担心数据丢失。
一旦数据提交成功,就算存在硬件故障或数据库崩溃,事务所写入的任何数据也不会丢失。对于单节点数据库,持久性通常意味着数据已被写入非易失性存储设备,如硬盘或SSD。在写入执行过程中,通常还涉及预习日志等。这样万一磁盘数据损坏可以进行修复。

本次分享到这里结束啦,希望对你有所帮助~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值