首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >如何看待一致性 & 事务 & 共识问题

如何看待一致性 & 事务 & 共识问题

作者头像
小坤探游架构笔记
发布2025-07-14 17:13:45
发布2025-07-14 17:13:45
1400
举报

点击上方小坤探游架构笔记可以订阅哦

关于一致性、事务以及共识问题,可能我们每个人对此的认知都或多或少有些偏差,周末我重新翻读《Designing Data Intensive Applications》(设计密集型系统)一书,我觉得作者对这块的理解还是比较深,今天不做深入技术分析,单纯聊自己的理解。

事务的阐述

我们一谈到事务,就很容易想到事务的ACID属性,那么我们先抛开ACID属性,先问下自己,数据库系统为什么要引入事务机制?

可以想象下, 如果我们要来设计一个存储系统,要如何做到可靠性呢? 在现实世界中,我们运行的数据存储系统可能都会出现错误,比如:

  • 不论何时我们向数据库发起写操作,我们的存储系统都可能存在软件层面、硬件层面以及人为配置层面引起的故障。
  • 如果这个时候正在执行一系列的写入操作,在写入数据过程中我们的存储系统突然断电导致崩溃,这个写入数据仅写了部分,这个时候又该如何决策我们的写入操作?重试?丢弃?
  • 数据库与应用程序之间的连接由于网络发生故障导致连接中断导致应用程序写操作也间接中断,这个时候数据也是不完整,那么我们还要考虑连接层面断连引起的故障问题。
  • 多个客户端向数据库并发执行同一个数据操作导致数据冲突异常或者直接覆盖彼此数据。
  • 只能读取到部分数据,正如上述所说的,写入操作执行到一半发生异常导致数据不完整。
  • 多个客户端存在竞争同一个资源,比如A,B需要同时持有C以及D资源,但A有C资源而B有D资源,两者相互都不肯放手引起的死锁问题。

从上述列举的异常场景中,如果我们能够在存储系统层面设计一个机制,将上述的异常场景进行抽象封装起来,简化应用程序开发者的编程模型,通过这种机制来保证我们应用程序向数据库层面在进行读写的时候能够得到安全性的保障,即我们的应用程序层面可以不必关注上述的故障情况,而是交由数据库层面提供容忍故障的安全性保障机制,对于这种机制我们称之事务

那么我怎么判断事务是具备安全性的呢?它有提供哪些安全性保障以及为此付出的成本有哪些呢?我想到这里我们再回来看事务的ACID属性是不是就能够理解了呢?没错,事务的ACID属性就是提供故障安全性性保障。ACID是Theo Härder 以及Andreas Reuter在1983年就被提出来,目的是就是为数据库的Fault Tolerance(故障容忍)提供精确的语义。这里我们仅讨论ACID属性的C,即事务一致性。

不同术语下的一致性认知差异

关于一致性,我想我们会看到很多种不同的说法,也不同的认识。那么我们谈论的一致性经常会在哪些方面看到呢?这里我直接引用《Designing Data Intensive Applications》里面的描述:

  • Replica Consistency and Eventual Consistency,即副本的一致性以及最终一致性,这里产生的原因是我们在实现一个高可用复制架构中,Replica之间如果是通过异步方式进行通信,中间必然存在Replication Lag,所以会产生数据复制的一致性问题, 那么我们如何去看待这个一致性问题呢? 这个时候我们能够根据业务场景下不同的数据利用一致性模型抑或是CAP定理 or BASE理论去帮助我们做分析, 做判断, 从而帮助在实现高可用目标决策上进行Trade-Off.
  • CAP定理的Consistency,主要是描述是线性一致性,相比分布式一致性,它更多地是描述在一个非共享且数据复制的高可用架构下,如何保证我们的客户端看到最新数据的时效性,即如果有一个客户端是从系统读取到一份最新的数据,那么后续的其他客户端也能够读取到最新的数据,也就是我们前面所说的一致性模型中的线性一致性。
  • Consistent hashing,关于这个一致性,我觉得我不用细说很多同学也能够理解,它就是一个系统用于重平衡分区的算法,并基于hash重平衡保证均匀。
  • 还有就是我们的事务ACID中Consistency,它是什么意思呢?这里我直接贴书中的原话:consistency refers to an application-specific notion of the database being in a “good state.” 这种我觉得你可以交由AI去帮你解答,其中有个核心点我是认同的,即数据库的一致性并非由数据库系统本身定义,而是由应用程序的业务规则决定,怎么理解呢?在我上一篇文章中,关于一致性模型有位读者的留言对一致性描述就是这个意思,这里我简述一下:

前提:用户 A 账户有 1000 元,用户 B 账户有 2000 元,总余额 3000 元。 事件:A 向 B 转账 500 元后,A 余额 500 元,B 余额 2500 元,总余额仍为 3000 元,符合 “总余额不变” 的规则,数据一致。

其中这个余额不变就是我们ACID中的Consistency,它谈及是我们业务层面上的一致性,换言之是我们应用程序的属性,即这种一致性的概念依赖于应用程序对于不变量的定义,并且应用程序有责任正确地定义其事务,以便保持一致性。这并非数据库能够保证的事情:如果你写入了违反不变量的错误数据,数据库无法阻止你。(数据库可以检查某些特定类型的不变量,例如使用外键约束或唯一性约束。但一般来说,是应用程序定义哪些数据是有效或无效的,数据库只是负责存储这些数据。)

分布式事务与原子提交

在我们对事务以及一致性的认知之后,还有一种情况是我之前没有描述过的,那就是如果是在一个跨多节点或者分区事务的存储系统中,我们必然面临着分布式事务问题。同样地,为了更方便后续展开,我们先谈下事务的原子性。

什么是事务的原子性呢?我想大多数同学都能够说出来,就是我现在向数据库发起一系列的操作,要么都成功,要么都失败。那么具体怎么理解呢?首先“原子的”指的是不能再分解为更小部分的事物。

在计算机领域的不同分支中,这个词的含义相似但又略有不同。比如在多线程编程中,如果一个线程执行一个原子操作,这意味着另一个线程绝不可能看到该操作只完成一半的结果。系统只能处于操作前的状态或者操作后的状态,而不会处于两者之间的某种状态。

那如果是在事务层面呢?前面我们说了存储系统引入事务是为了提供容忍故障的安全性保障,那么这里的原子性就是说我们客户端向数据库发起一系列操作,如果在这个操作期间突然发生故障,那么这个时候为保证安全性,我们必须确保应用程序不会更改到任何内容,换言之就是出现错误时中止事务并丢弃该事务中所有写入操作的能力,是ACID原子性的关键特征

为什么突然讲原子性呢?很简单,它和我们分布式系统中的一个称之为原子提交问题相关,什么是原子提交问题呢?

在支持跨多个节点或分区事务的数据库中,存在这样一个问题:一个事务可能在某些节点上失败,但在其他节点上成功。如果我们想要保持事务的原子性,我们就必须让所有节点就事务的结果达成一致:要么所有节点都中止/回滚事务(如果出现任何问题),要么所有节点都提交事务(如果一切顺利)。这种达成共识的情况被称为原子提交问题。

重述共识问题

讲到这里又回到共识问题了,之前我们通过引入FLP结论从而引出共识问题的阐述,今天我们又在原子提交问题上又见到共识问题。在前面分布式共识问题我们讲述了共识是对Fault Tolerance提供安全性保障的通用解法,即构建一个Faults Tolerance的系统的最佳实践方式是将一些通用有效的保障进行抽象并形式化,通过实现它们一次并让应用系统依赖于这些保障。这就有点类似于我们共享服务或者共用组件的意思,向上提供复用的能力。

那么事务、一致性以及共识之间又有什么区别与联系呢?事务我们关注的是单点层面如何保证存储系统的可靠性,对于故障容忍提供一种安全性保障的机制,而共识问题关注的是分布式层如何实现具备安全性保障的故障容忍算法,而我们关注的一致性问题,建议我们在一致性描述增加一个术语的描述,即是ACID中一致性,还是Replica Consistency的一致性,我想我们这样就能够很好地去区分和理解其中的本质问题。

总结

最后我贴了一张图来对比我们的事务与共识之间关注的点:

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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-07-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小坤探游架构笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档