
点击上方小坤探游架构笔记可以订阅哦
关于一致性、事务以及共识问题,可能我们每个人对此的认知都或多或少有些偏差,周末我重新翻读《Designing Data Intensive Applications》(设计密集型系统)一书,我觉得作者对这块的理解还是比较深,今天不做深入技术分析,单纯聊自己的理解。
事务的阐述
我们一谈到事务,就很容易想到事务的ACID属性,那么我们先抛开ACID属性,先问下自己,数据库系统为什么要引入事务机制?
可以想象下, 如果我们要来设计一个存储系统,要如何做到可靠性呢? 在现实世界中,我们运行的数据存储系统可能都会出现错误,比如:
从上述列举的异常场景中,如果我们能够在存储系统层面设计一个机制,将上述的异常场景进行抽象封装起来,简化应用程序开发者的编程模型,通过这种机制来保证我们应用程序向数据库层面在进行读写的时候能够得到安全性的保障,即我们的应用程序层面可以不必关注上述的故障情况,而是交由数据库层面提供容忍故障的安全性保障机制,对于这种机制我们称之事务。
那么我怎么判断事务是具备安全性的呢?它有提供哪些安全性保障以及为此付出的成本有哪些呢?我想到这里我们再回来看事务的ACID属性是不是就能够理解了呢?没错,事务的ACID属性就是提供故障安全性性保障。ACID是Theo Härder 以及Andreas Reuter在1983年就被提出来,目的是就是为数据库的Fault Tolerance(故障容忍)提供精确的语义。这里我们仅讨论ACID属性的C,即事务一致性。
不同术语下的一致性认知差异
关于一致性,我想我们会看到很多种不同的说法,也不同的认识。那么我们谈论的一致性经常会在哪些方面看到呢?这里我直接引用《Designing Data Intensive Applications》里面的描述:
前提:用户 A 账户有 1000 元,用户 B 账户有 2000 元,总余额 3000 元。 事件:A 向 B 转账 500 元后,A 余额 500 元,B 余额 2500 元,总余额仍为 3000 元,符合 “总余额不变” 的规则,数据一致。
其中这个余额不变就是我们ACID中的Consistency,它谈及是我们业务层面上的一致性,换言之是我们应用程序的属性,即这种一致性的概念依赖于应用程序对于不变量的定义,并且应用程序有责任正确地定义其事务,以便保持一致性。这并非数据库能够保证的事情:如果你写入了违反不变量的错误数据,数据库无法阻止你。(数据库可以检查某些特定类型的不变量,例如使用外键约束或唯一性约束。但一般来说,是应用程序定义哪些数据是有效或无效的,数据库只是负责存储这些数据。)
分布式事务与原子提交
在我们对事务以及一致性的认知之后,还有一种情况是我之前没有描述过的,那就是如果是在一个跨多节点或者分区事务的存储系统中,我们必然面临着分布式事务问题。同样地,为了更方便后续展开,我们先谈下事务的原子性。
什么是事务的原子性呢?我想大多数同学都能够说出来,就是我现在向数据库发起一系列的操作,要么都成功,要么都失败。那么具体怎么理解呢?首先“原子的”指的是不能再分解为更小部分的事物。
在计算机领域的不同分支中,这个词的含义相似但又略有不同。比如在多线程编程中,如果一个线程执行一个原子操作,这意味着另一个线程绝不可能看到该操作只完成一半的结果。系统只能处于操作前的状态或者操作后的状态,而不会处于两者之间的某种状态。
那如果是在事务层面呢?前面我们说了存储系统引入事务是为了提供容忍故障的安全性保障,那么这里的原子性就是说我们客户端向数据库发起一系列操作,如果在这个操作期间突然发生故障,那么这个时候为保证安全性,我们必须确保应用程序不会更改到任何内容,换言之就是出现错误时中止事务并丢弃该事务中所有写入操作的能力,是ACID原子性的关键特征。
为什么突然讲原子性呢?很简单,它和我们分布式系统中的一个称之为原子提交问题相关,什么是原子提交问题呢?
在支持跨多个节点或分区事务的数据库中,存在这样一个问题:一个事务可能在某些节点上失败,但在其他节点上成功。如果我们想要保持事务的原子性,我们就必须让所有节点就事务的结果达成一致:要么所有节点都中止/回滚事务(如果出现任何问题),要么所有节点都提交事务(如果一切顺利)。这种达成共识的情况被称为原子提交问题。
重述共识问题
讲到这里又回到共识问题了,之前我们通过引入FLP结论从而引出共识问题的阐述,今天我们又在原子提交问题上又见到共识问题。在前面分布式共识问题我们讲述了共识是对Fault Tolerance提供安全性保障的通用解法,即构建一个Faults Tolerance的系统的最佳实践方式是将一些通用有效的保障进行抽象并形式化,通过实现它们一次并让应用系统依赖于这些保障。这就有点类似于我们共享服务或者共用组件的意思,向上提供复用的能力。
那么事务、一致性以及共识之间又有什么区别与联系呢?事务我们关注的是单点层面如何保证存储系统的可靠性,对于故障容忍提供一种安全性保障的机制,而共识问题关注的是分布式层如何实现具备安全性保障的故障容忍算法,而我们关注的一致性问题,建议我们在一致性描述增加一个术语的描述,即是ACID中一致性,还是Replica Consistency的一致性,我想我们这样就能够很好地去区分和理解其中的本质问题。
总结
最后我贴了一张图来对比我们的事务与共识之间关注的点:

最后感谢阅读,如有错误欢迎指正!!!