文章目录
1. 整体介绍
大数据存储系统中,提高系统高可用,会将同一份数据存储为多份副本,工程中常规是3备份。除了增加高可用性外,还增加了读操作的并发性,但与此同时就会引起数据一致性问题:同一个数据的多个副本,在并发读/写情况下,如何维护数据一致视图是很重要的,也就是说同一份数据无论多少副本,外部表现也像单份数据一样。
本节介绍数据复制带来的一致性问题和解决方案。先介绍集成理论模型:CAP、ACID、BASE,再介绍几种典型的副本数据更新策略。
2. 基础理论模型
2.1 保守主义的CAP
- 强一致性
Consistency
:分布式系统多副本情况下,对数据更新效果与单份数据一致; - 可用性
Availability
:对于读写操作都需要满足特定的响应时间; - 分区容忍性
Partition Tolerance
:分布式系统中,分区间的机器无法通信的情况下,保证服务正常工作;
CAP三要素不可兼得,同一个系统最多实现其中两个,不得不放宽第三个要素。
如果数据v只存在一个副本,这种情况我们显然满足强一致性C,但如果集群中某些机器宕机,肯定不能得到可用性A。
如果数据v存在多个副本,在X、Y机器上,更新X机器上的数据,如果此时机器XY之间的网络分区不可达,此时就需要在AC之间权衡,如果选择可用性A,那么此时v的值处于不一致状态;如果选择强一致性C,那么此时应该拒绝对机器Y中v值的读请求。所以无论选择哪一个,必将抛弃另外一个。
2.2 重新解读的CAP
CAP原则的提出者Eric Brewer在2012年对上述理论提出了质疑,必须3选2其实是具有误导性。
因为网络分区P出现的概率很小,不应该为了P在一开始就放弃强一致性C和可用性A。
所以我们在设计之初应该为了同时满足CA而努力,如果出现网络分区问题,作为特殊情况,进行取舍不一致状态提供服务,当网络分区现象结束,重新进入CA提供服务。
2.3 ACID原则
ACID是关系数据库使用的原则,具有高可靠性与强一致性,代表含义如下:
- 原子性
Atomicity
:指一个事务要么全部执行,要么完全不执行; - 一致性
Consistency
:事务在开始和结束时,应该始终满足一致性约束条件。 - 独立性
Isolation
:两个事务不会出现交错执行的状态,因为这样可能导致数据不一致。 - 持久性
Durability
:事务执行成功以后,该系统状态的更新是永久的,不会无缘无故的回滚。
关于原子性的理解,例如转账,转账事务要么成功要么失败,不可能出现转出方扣了钱,收款方最终没有收到钱,或者转账方没有扣钱,收款方最终却收到了钱的情况(如果真的是这样,那么银行可能就真的要垮了)。
关于一致性的理解,依旧例如转账,转出100元,就应该扣卡上100元,如果事务改变了转账转出的数值,那么扣款的数值也需要改变,满足这种一致性要求。同时说下,这里的C与CAP中的C代表的意义不一样,需要注意。
2.4 BASE原则
大数据环境的云存储系统和NoSQL系统则遵循BASE原则,与ACID原则的差异大。
BASE原则具体如下:
- 基本可用
Basically Available
:绝大多数时间系统处于可用状态,允许偶尔失败; - 软状态
Soft State
:数据状态不要求在任意时刻都完全保持同步; - 最终一致性
Eventual Consistency
:虽然软状态不要求任意时刻数据保持一致同步,但最终一致性要求在给定的时间窗口内数据会达到一致状态。
BASE原则上通过牺牲强一致性来满足高可用性。
目前一般的分布式系统采用的方案上在全局满足BASE原则,局部满足ACID,吸取各自的好处,建立平衡。
2.5 CAP/ACID/BASE关系
ACID更强调数据一致性,传统数据库的设计思路。BASE更强调可用性,弱化数据强一致性的概念,是互联网时代大规模分布式数据系统的一种需求。
- CAP中的C是指数据的强一致性,是ACID中C的子集。
- 当出现网络分区时,不可能满足事务,因为事务的序列化需要网络通信。
- 当出现网络分区,应该尽可能地在每个分区执行ACID,等网络分区结束后恢复。
2.6 幂等性
抽象代数中,对一元运算来说,满足f(f(x))=f(x)
条件的运算称为满足幂等性,例如取绝对值运算。对二元运算来说,如果满足f(x,x)=x
条件的运算称为满足幂等性,例如实数集合运算max(x,x)=x
。
分布式系统中幂等性指:调用方反复执行同一操作与只正确执行一次操作的效果相同。网络情况下调用未收到成功响应,会认为失败进行再次调用,可能会反复执行,该情况下保持幂等性可以保证系统的正确性。
Zookeeper和Raft就支持很多操作的幂等性。
3. 一致性模型
一致性模型包括:强一致性、弱一致性,而弱一致性包括:最终一致性、因果一致性、“读你所写”一致性、会话一致性、单调读一致性、单调写一致性。在实际的系统中要根据具体的情况来选择合适的一致性模型。下图为他们之间的关系:
3.1 强一致性
对于连接到数据库的所有进程,看到的关于某数据的数据值都是一致的。对于一个数据不管存在多少个副本,在任意时刻对任意一个副本访问得到的结果都是一样的。
3.2 最终一致性
最终一致性无法保证某个数值x更新后,所有后续针对x的操作都能够立即读取到新的数值,需要一个时间片段,才能够保证数据一致,在这之前数据可能是不一致的。
3.3 因果一致性
因果一致性发生在进程之间有相互依赖关系的情形下。例如AB两个进程相互依赖,那么如果A对某个变量进行更新,他在更新之后会通知B,这时候B看到的就是新值,但是如果还有进程C,那么C看到的值可能还是旧值。
3.4 “读你所写”一致性
“读你所写”一致性是因果一致性的一个特例,进程A对数据做了更新之后,会立马给自己发送一个通知,所以进程A在之后的操作都是以新值为基础进行的。
3.5 会话一致性
当进程A通过会话与数据库进行连接时,在同一个会话中,可以保证读你所写一致性。而在不一致窗口内,如果因为系统故障等原因导致会话终止,那么进程A仍旧可能读出旧值。
3.6 单调读一致性
如果一个进程读取到数据的某个版本V2的值,那么系统后续的所有读操作都不能看到比V2更老的版本的数值。
3.7 单调写一致性
对于某个进程来说,单调写一致性可以保证其多次写操作的序列化,如果无法保证,那么应用开发人员很难进行程序开发。
4. 副本更新策略
在大规模分布式存储系统中,副本更新有3种策略:同时更新策略、主从式更新策略以及任意节点更新策略。
4.1 同时更新
-
类型A:不通过任何一致性协议直接同时更新多个副本数据。此时存在潜在的数据不一致性问题:假设2个客户端同时发出update1和update2更新请求,系统无法确定先后顺序,导致副本可能为update1结果,也可能是update2结果。
-
类型B:通过某种一致性协议预处理,确定更新操作的执行顺序,确保数据一致性,一致性协议有处理成本,所以演示会有所增加。
4.2 主从更新策略
如果数据的多副本中存在一个主副本,其他副本为从副本,所有对这个数据的更新操作首先提交到主副本,再由主副本通知从副本进行更新,根据主副本通知从副本的机制分为以下3中类型:
同步方式
主副本等待所有从副本更新完成后才确认更新操作完成,确保了数据的强一致性。延时增大
异步方式
主副本通知从副本更新前即可确认更新操作。这种情况下,如果从副本还没收到更新就崩溃了,会出现数据一致性问题,一般会首先在另外的可靠存储位置更新操作记录下来,防止该情况的发生。
对于请求延时和一致性权衡,分为以下2种情形:
1. 如果所有读请求都通过主副本来响应,一致性可以保证,延时会增加;
2. 如果任意副本都可以响应读请求,延时降低,会有数据一致性问题;
混合方式
采用同步异步混合的方式,主副本先同步更新部分从副本数据,确认更新操作完成,其他副本通过异步方式更新。可以看出来,在请求延时和数据一致性之间的权衡也是取决于意向两种读操作的响应方式。
1. 如果读操作的数据从至少1个同步更新节点中读出,数据一致性获得保证,请求延时增加,但是延时比同步的要低;
2. 如果读操作不要求一定要从至少一个同步节点中读取,那就还是会出现异步方式的第二种情形,引起数据一致性问题;
4.3 任意节点更新策略
数据更新请求发送给多副本的任意一个节点,有这个节点负责通知其他副本进行数据更新,与主从式的区别是,不固定主副本,任意节点都可以响应。特殊性在于:有可能有2个不同客户端在同一时刻对同一个数据发出数据更新请求,此时可能有2个不同的副本各自响应。
这样的更新策略下,有以下2中情形:
- 类型A:同步通知其他副本,与主从式同步更新相似,延时较大;
- 类型B:异步通知其他副本,存在和同时更新策略与主从式更新策略异步方式类似,数据一致性可能有问题;