数据的读写、ACID和CAP原则

 

数据的分布问题解决了,接下来就是数据的读写了。首先我们来看看在单机系统中数据的读写需要了解的有啥(或者说俺知道有啥)。

 

一、单机数据的读写

  相较于分布式系统,单机系统的数据读写不需要考虑多个副本之间的一致性问题,大大简化了存储系统的设计。

  单机系统存储主要需要考虑的则是并发控制和持久化的问题。而数据库操作的事务性则是一个非常好的讲解用例。

  

  事务是数据库操作的基本单位,它包含4个特性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。即大家常说的ACID。

  1、原子性:整个事务中的所有操作,要么全部完成,要么全部失败,不可能停滞在中间某个环节。中途如果出现错误,已执行完的操作会回滚至未操作前的状态。

  2、一致性:在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。如数据类型必须正确,数值必须在规定的范围内。

  3、隔离性:多个事务提交时,如果有修改事务正在执行,则必须将其串行化,不能同时有多个事务同时执行。即多个事务产生的中间影响是互不可见的。

  4、持久性:在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。系统出现异常也需保证此点。

 

  在上述4个特性中,隔离性是最影响性能的,所以数据库对此会有些特定的实现和优化,主要有下面3点:

  1、读写锁:最简单的处理,性能也最低。同一个元素可以加多个读锁,但只允许加一个写锁。可能会有死锁情况,解决死锁有:a) 死锁检测。b)事务设置超时回滚机制。

  2、写时复制(Copy On Write, COW):因为大部分业务的应用场景都是读操作远远大于写操作次数。而写时复制技术(在linux内核和STL实现中有应用)可以读操作不加锁,能比较显著的提高性能。数据库的索引是一颗B+树,它在写时复制时的步骤如下(假设修改黄色data节点数据):

    a) 复制:将从叶子节点到根节点的整个路径上的节点拷贝出来。

    b) 修改:对拷贝的节点做修改。

    c) 提交:原子的切换根节点指针,将其指向新的数据节点。                             

    写时复制技术在读操作远大于写时性能提升较高,但写操作本身因要大量复制数据,写操作本身成本较高。且多个写操作时仍需要进行互斥。

  3、多版本并发控制:多版本并发控制(Multi-Version Concurrency Control, MVCC)和写时复制技术一样,也能实现读事务不加锁。它对每行记录维护多个版本。Mysql InnoDB对每行记录维护了2个隐含的列,一列存储被最近修改的事务版本号,一列存储被删除的事务版本号。每个事务操作都会全局的分配一个递增的事务版本号。当其对记录进行修改或者删除操作时,会将其事务版本号记录下来。针对不同的操作类型则有不同的处理逻辑。

    a) SELECT: 当记录满足下面两个条件时才返回。

      i) 记录的修改版本小于等于当前事务版本号。

      ii) 记录的删除版本要么为空,要么大于当前事务版本号。

    b) DELETE: 直接将记录的删除版本号设置为当前事务的版本号。

    c) INSERT: 将新插入的记录的修改版本号设置为当前事务的版本号。

    d) UPDATE:将记录复制一份,修改记录后,将记录的修改版本号改成当前事务版本号。

  MVCC读记录时不需要加锁,事务通过版本检查可以获得自己想要的记录版本。但MVCC需要定期删除不再需要的版本,从而释放空间。

 

二、分布式系统的数据读写

  分布式系统的数据读写相对于单机系统来说需要考虑的则是多个副本之间的一致性问题。对此,分布式系统中主要有两种处理副本间数据同步问题的方法。分别是:主备复制协(primary-backup protocal)议和NWR协议。

  主备复制协议:类似于传统数据库的master-slave同步机制。协议鉴于可用性有两种复制方式:同步和异步。

    同步:主副本将写操作同步到其他备副本获得成功返回后再修改主副本,然后再返回结果给客户端。若有备副本出现问题则可能阻塞写操作,导致系统可用性较差。当有多个备副本时,为了提供可用性,有时会对一致性进行折中,当有一个备副本写操作成功后即可返回同步成功操作。这样主副本出现故障时,至少有一个备副本具有完整的数据。

    异步:收到客户端的写请求后,主副本写本地成功后即可返回写操作成功,备副本的同步通过异步的更新即可。该机制的一致性较差,但可用性最高。主副本出现故障时,可能丢失一部分数据。

  NWR协议:主要用在去中心化(P2P)的分布式系统中。Amazon的Dynamo分布式键值系统即采用的此种同步方案。N代表副本数,W代表每次写操作最少写成功的副本数,R代表每次读操作至少读取的副本数。W和R可以根据业务特性进行调整。这样当W+R>N时,可以保证每次读取的数据至少有一个副本具有最新的更新。当系统比较注重读效率,而写操作较少时,可以设置W=N, R=1。若系统允许一定程度的数据丢失,则可以将W设置小点。一般系统可设置N=3,W=2,R=2。

    缺点:NWR看起来很不错,但其实有个比较重要的缺陷。因为他是没有主备逻辑的,常用于去中心化(P2P)的系统中,多个写操作的顺序往往很难保证,导致多个副本之间的写操作顺不一致。当然这个有一些尝试解决冲突的办法,比如Dynamo的向量时钟(Vector Clock),但它也只能保证最终一致性。

 

三、CAP原则

  CAP是Inktomi公司的创始人,Berkeley大学的Eric A. Brewer提出来的分布式存储系统理论。理论提出:在任何分布式存储系统中,一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance) 三者最多只能满足其中的2者。该理论被认为是NOSQL数据库的基石。三者的大致意思如下:

  一致性(C): 数据一致更新,所有数据变动都是强同步的。

  可用性(A): 在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。

  分区容错性(P): 俺笔者个人的理解而言,就是当你的某个分区(比如某个节点或机房)出现故障(比如网络问题)时,系统需要自动容错,就好比从来就没有过这个分区。而以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。

 

  分布式系统的最基本要求就是能够自动容错。所以分区容错性基本总是需要满足的,因此系统需要在一致性和可用性之间做权衡。

  而上文介绍的副本间的强同步和异步复制方案则分别保证了一致性和可用性。有的系统也会在两者之间做折中,当正常情况下,提供强一致性模式,当主备之间出现更新故障时,则切换到异步更新模式。这是一个比较好的系统设计方案。

 

  后面讲讲系统的容错。

posted on 2015-02-03 23:43  lhonglwl  阅读(734)  评论(0编辑  收藏  举报

导航