在传统的数据中,有ACID四大原则,在分布式中也有对应的CAP理论和BASE理论,这些都是分布式理论的基础。
更多内容参考:大数据学习之路
ACID
ACID分别是Atomicity 原子性、Consistency 一致性、Isolation 隔离性、Durability 持久性,有了这几个特性,就保证了数据库的可靠。
原子性
原子性代表一系列的操作要么全做,要么全不做。比如,在银行转账,从一个账号扣钱,另一个账号加钱,这两个操作必须同时进行。否则就会出现账目对不上的情况。
一致性
一致性官方的描述是,事务执行后必须是从一个一致性状态转到另一个一致性状态。通俗点说就是保证整个系统在操作完成后,虽然处于不同状态,但仍保持一致。比如在转账情境中,从一个账号转出500,转入另一个账号,那么整个系统的金额不应该有变化。
隔离性
隔离性意味着多个并发之间是不可见的,相互隔离不被打扰。隔离性在数据库操作中还是很重要的,如果不考虑隔离性,可能会出现下面的问题:
- 脏读:事务T1读取了事务T2未提交的数据,结果事务T2回滚了,T1拿到了一个脏数据
- 不可重复读:事务T1读取数据后,紧接着事务T2就更新了数据,事务T1再次读取的时候发现数据不一致了
- 幻读:这种一般发生在大批量修改的时候,比如事务T1把所有的数据从1修改到了2,结果修改的过程中,事务T2插入了一条新数据1。最后检查数据发现有一条数据没有修改过来。
针对这几种情况,数据库如Mysql提供了几种事务的隔离级别:
- Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
- Repeatable read (可重复读):可避免脏读、不可重复读的发生。
- Read committed (读已提交):可避免脏读的发生。
- Read uncommitted (读未提交):最低级别,任何情况都无法保证。
持久性
这种最容易理解了,事务提交后,结果就保存不变了。
CAP
在分布式系统中,也有类似ACID的特性,那就是CAP,他们分别是:
- Consistency 一致性,强调进群节点中数据一致。在分布式中一致性又包括强一致性和弱一致性,强一致性就是指在任何时刻任何节点看到的数据都是一样的;弱一致性一般实现是最终一致性,即刚开始可能存在差异,但随着时间的推移,最终数据保持一致。
- Availability 可用性,强调集群在任何时间内都正常使用
- Partition Tolerance 分区容错性,即使某一部分集群坏掉,另一部分仍能正常工作。
这三个特性只能满足其中两个,牺牲另一个。大部分系统也都是如此:
一般来说分布式集群都会保证P优先,即集群部分节点坏死不影响整个集群的使用,然后再去追求C和A。因为如果放弃P——分区可用性,那不如就直接使用多个传统数据库了。事实上,很多微服务分库分表就是这个道理。
如果追求强一致性,那么势必会导致可用性下降。比如在Master-Slave的场景中,Master负责数据写入,然后分发给各个节点,所有节点都写入成功,才算写入,这样保证了强一致性,但是延迟也会随之增加,导致可用性降低。
因此在可用性和一致性之间,就出现了各种解决方案,如时序一致性、最终一致性等等。
BASE
前面由于分布式在CAP面前各种纠结,因此有人总结出了一套适合分布式的理论——BASE:
- BA,Basically Available 基本可用,比如降低性能要求、或者功能特性来保证整体的服务可用。比如服务的降级、增加延迟、等待等等。
- S,Soft State 软状态,允许出现中间状态,比如节点的不同副本之间同步存在延迟
- E,Eventual Consistency 最终一致性,具体的方案有很多,如因果一致性、读己一致性、会话一致性、单调读一致、单调写一致。
对于这几种一致性,可以简单的说一下:
- 因果一致性:进程B对进程A有依赖关系,那么B读取到的应该总是A更新后的值
- 读己一致性:进程A更新某个值后,它自己读到的应该是最新的值
- 会话一致性:在会话中进行操作,需要保证总是读取到最新的值
- 单调读一致:从系统读取某个值后,不应该读取到比它还旧的值
- 单调写一致:同一个进程对系统的写操作,需要保证顺序