HBase虽然不是严格意义上的ACID数据库,但其也在一定程度上对ACID做了适当的支持。本文将对HBase的ACID特性做一个简要的介绍。
首先对ACID做一个简单的定义,
A(Atomicity)原子性:一个事务中的一组操作要不全部完成,要不全部不完成,不可能只完成一部分。
C(Consistency)一致性:一个事务中所有的操作将保证数据表中的数据从一个有效状态转换到另一个有效状态,即从外部来看,数据是一致的。比如转账业务,从用户A中减去100块,存入用户B的账户中,在这个过程中,无论从用户A去查询还是从用户B去查询都可以确保这100块钱还存在于系统之中,不会出现程序将数据从A中减去了100块而没完成存入到B的过程,此时从A,B账户去查询都看不到这100块的情况。
I(Isolation)隔离性:同时执行事务中的操作相互之间不影响。
D(Durability)持久性:任何报告给client成功的操作都应该被永久保存在系统之中。
V(Visibility)可见性:任何更新操作都是可以被之后的读操作所见到的,就好像更新操作是被提交了一样。
以下从HBase的几方面来看HBase对于ACID的支持:
- 读APIs
- get
- scan
- 写 APIs
- put
- batch put
- delete
- 混合操作(read-modify-write) APIs
- incrementColumnValue
- checkAndPut
-
HBase在ACID的特性上所能保证的包括以下的一些特性:
原子性
- 所有对于一个hbase行的操作都是原子的,也即在hbase的table中加入,更新一行要不成功要不失败,不会部分成功部分失败,特别说明的是
- 如果客户端(API)操作超时的话,改操作也是全部成功或全部失败,不会有部分成功的情况出现, 这个是hbase在行上的原子操作的保证。
- 操作跨多个CF(column family)也是一样,全部成功或全部失败
- API对于跨行的操作是不能保证原子性的。比如说通过multiput去创造行'a','b','c',可能从API的调用中得到对每一行各自的成功,失败了或超时状态。
- 对于行的操作会按照一定的顺序进行,而不会出照操作之间的叠加而导致数据的异常。如一个线程对于一行的操作是"a=1,b=1,c=1",另一个线程对于该行的操作是"a=2,b=2,c=2",该行的最终值有可能是"a=1,b=1,c=1"或者"a=2,b=2,c=2";不可能出现"a=1,b=2,c=1"的情况,这个是hbase来保证的。但是要注意的是,跨多行的批量操作是不能保证这一点的。
一致性和隔离性
- API对于hbase中的行访问,会得到在某一个时间点上的完整的数据行.对于同行跨多个CF(column family)的操作来说依然成立。
- 一个行的状态是通过对其历史版本不停的前滚而来
Consistency of Scans
一个scan不可以获得一个table的一致状态(scan后包括不同行不在同一个时间点值,如r1(t1),r2(t2)),但是可以保证的是每一行的状态都是一致的。
一个scan将一直反应在其被创建时刻的数据值,这包括以下几个方面:
1.如果Client A写了一个数据X并通过其它方式通知client B去访问该数据,client B将可以看到最起码X或其之后的数据X.
2.一个scan必需反应出在其创建之前所有的被提交的更新,并且也可能反应出在其创建过程中可能产生的更新。
如果你对关系数据库事务的隔离性熟悉的话,scan的行为实际上是一种'read committed'。
请注意以上所能保证的被称为‘事务提交时间’,并不是相应的行上‘timestamp'列,也就是说,一个scanner开始时间为t可能会看到一个timestamp的值为t的数据,如果那些版本是由于提交‘forward dated'的时间崔在scanner被创建之前。
可见性
1.当一个client收到一个更新操作的成功反馈,这个更新将会马上被当前client或任意其它连接进行查询的client可见。
可持久化:
1. 所有可见的数据都是被持久化的数据。也就是说,一个read不会把一个还没有写入磁盘的数据返回给client.
2. 任何返回成功的操作都会被持久化
3. 任何返回失败操作的数据都不会被持久化