5.1 数据一致性
引入事务的目的,是为了保证数据的“一致性”(Consistency)。
这里的一致性指的是,对数据有特定的预期状态,任何数据更改操作必须满足这些状态约束(或者恒等条件)。例如,处理一个转账业务,其中 A 向 B 转账 ¥50 元。无论是转账前、转账过程中、还是转账完成后,A 和 B 的总金额要求始终保持不变。这意味着数据在整个过程中都保持一致,符合业务约束。
想要达成数据的一致性,需要 3 个方面的努力:
- 原子性(Atomic):“原子”通常指不可分解为更小粒度的东西。这里原子性描述的是,客户端发起一个请求(请求包含多个操作)在异常情况下的行为。例如,只完成了一部分写入操作,系统出现故障了(进程崩溃、网络中断、节点宕机)。把多个操作纳入到一个原子事务,万一出现上述故障导致无法完成最终提交时,则中止事务,丢弃或者撤销那些局部修改。
- 隔离性(Isolation): 同时运行的事务不应互相干扰。例如,当一个事务执行多次写入操作时,其他事务应仅能观察到该事务的最终完成结果,而非中间状态。隔离性旨在防止多个事务交叉操作导致的数据不一致问题。
- 持久性(Durability):事务处理完成后,对数据的修改应当是永久性的,即使系统发生故障也不会丢失。在单节点数据库中,持久性意味着数据已写入存储设备(如硬盘或 SSD)。而在分布式数据库中,持久性要求数据成功复制到多个节点。为确保持久性,数据库必须在完成数据复制后,才能确认事务已成功提交。
这也就是常说的事务的“ACID 特性”。值得一提的是,对于一致性而言,更多的是指数据在应用层的外部表现。应用程序借助数据库提供的原子性、隔离性和持久性,来实现一致性目标。也就是说,A、I、D 是手段,C(Consistency)是 3 者协作的目标,弄到一块完全是为了读起来更顺口。
当事务仅涉及本地操作时,一致性通常可以通过代码实现起来水到渠成。但倘若事务的操作对象扩展到外部系统,例如跨越多个微服务、数据源甚至数据中心时,再依赖传统的 A、I、D 手段来解决一致性问题变得非常困难。但是,一致性又是在分布式系统中不可回避且必须解决的核心问题。
这种情况下,我们需要转变观念,将一致性视为一个多维度的问题,而非简单的“是或否”的二元问题。根据不同场景的需求,对一致性的强度进行分级,在确保代价可承受的前提下,尽可能保障系统的一致性。一致性的强弱程度直接影响系统设计权衡。由此,事务从一个具体操作层面的“编程问题”转变成一个需要全局视角的“架构问题”。人们在探索这些架构设计的过程中产生了诸多思路和理论,这其中最为出名的是一致性与可用性的权衡 —— CAP 定理。
总字数:916字