原文链接:http://hbase.apache.org/acid-semantics.html
关于这篇文档
Apache HBase (TM) 不是一个适用于ACID的数据库。但是它可以保证特定的属性。这篇说明列举了HBase中ACID的属性
定义
为了共同的词汇表,我们定义以下术语:
- Atomicity原子性
- 一个操作是原子的,它要么整体都完成,要么都不完成
- Consistency一致性
- 所有操作都导致表从一个有效状态直接转换到另一个有效状态(例如,在更新期间,一行不会消失)
- Isolation隔离性
- 如果一个操作独立于任何其他并发事务,就会被隔离。
- Durability持久性
- 任何向客户报告“成功”的更新都不会丢失
- Visibility可见性
- 如果任何后续的读操作都能看到已经提交的更新,则可以将更新视为可见的
术语必须和可能是由RFC2119指定的。简而言之,“必须”一词意味着,如果某些情况在陈述不正确的情况下存在,那么它就是一个错误。
“可能”这个词意味着,即使在当前版本中提供了保证,用户也不应该依赖它。
要考虑的APIs
- 读 APIs
- get
- scan
- 写 APIs
- put
- batch put
- delete
- 结合 (读-改-写) APIs
- incrementColumnValue
- checkAndPut
提供的保证
Atomicity原子性
- 在一行内所有的更新都是原子性的,对于一行任意的put都会全部成功或者全部失败。[3]
- 一个操作返回“成功”代码,就已经全部成功。
- 一个操作返回“失败”代码,就已经全部失败。
- 一个操作超时后可能已经成功也可能已经失败。但是,它不会部分成功或部分失败。
- 即使这个更新涉及了一行中的多个列家族,这也是正确的。
- 更新多行的API在多行之间的操作不是原子性的。例如一个在行'a'、'b'和'c'进行多行Put操作的API可能返回已经更新的一部分但不是所有行。在这种情况下,这些API将返回一个成功代码的列表,每一个元素可能是如上所述的已成功、已失败或者是超时。
- API checkAndPut与在许多硬件架构中发现的典型的compareAndSet(CAS)操作类似
- 对于定义好了顺序的每一行,更新是顺序的,而不是相互交错的。例如,如果一个写入者的更新是"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"
- 请注意多行批量的变化就不是正确的
Consistency and Isolation一致性和隔离性
- 通过任何可以访问行的API访问到的所有行,返回的内容都将包含一个完整的行,该行存在于表中某些时间点的历史记录。
- 跨多列族是正确的。例如,在一个完整的行上发生并发更新1,2,3,4,5,将返回一个在更新 i到i+1(i为1到5之间) 存在的完整的行。
- 行的状态只是在行编辑的历史记录中向前移动只会在编辑的历史中前进。
Consistency of Scans Scan的一致性
Scan操作返回的不是表中一个一致的视图。Scan操作不提供快照隔离(在SNAPSHOT隔离级别下,任何写操作都会将更新之前的数据行保存到tempdb中,读取操作要么从Original Database的数据表中读取数据,要么从tempdb中读取行版本数据。Snapshot隔离级别指定:在一个事务中,任何语句读取的数据,是事务一致性的版本。事务一致性是指在事务开始时,在表级别创建数据快照,只能识别其他事务已提交的数据更新。在事务开始之后,当前事务不会识别其他事务执行的数据更新。Sanpshot隔离级别实现事务级别的数据一致性。SQL Server 使用tempdb来存储行版本化(row versioning)的数据,如果数据更新较多,存储的行版本太多,会导致tempdb成为系统瓶颈。)。
相反,scan操作有以下属性:
- Scan返回的任意行是一个一致的视图(返回的完整行的版本存在于某个时间点)[1]
- Scan将始终反映数据的视图,至少与Scan开始时一样新。这满足下面列举的可见性保证:
- 例如,客户端A写数据X,然后通过边信道与客户端B通信,任何由客户端B启动的Scan操作的结果将至少包含和X一样新的数据。
- Scan必须反映出在scanner构建之前所提交到的所有更新,并可能反映scanner构建之后提交的一些更新。
- Scan必须包含在scan之前写入的 所有的 数据(除非数据是Scan之后被更新的,这种情况下的更新有可能被反映到Scan中)
关系型数据库中,认为这种隔离级别是 "read committed"——已提交读。
请注意:以上列出的关于scanner一致性的保证提及了“事务提交时间(transaction commit time)” ,而不是每一个单元的“时间戳”。这说明,一个开始于时间t的scanner可能看到时间戳大于t的值,只要这样被提交的更新值带有远期时间戳,且在scanner被构造之前提交。
Visibility 可见性
- 当一个客户端收到一个关于任何更新的“成功”的响应,那么这样的更新会对这个客户端立即可见,对和这个客户端稍后通过边信道进行通信的任何客户端也是立即可见。[3]
- 一个行不能体现出所谓的“穿越(time-travel)”属性。这个意思是,如果一系列的更新连续地改变这一行的状态,那么任何并发的读取序列都将返回这些状态的子序列。
- 例如,一行的单元通过API “incrementColumnValue”被改变了,客户端不能看到单元值减少
- 无论哪个读API被用来重读这个更新,这个特性都是适用的。
- 读取操作返回的一个单元的任意版本都将被保证是可存储的。
更多内容
更多内容, 参见Apache HBase Reference Guide的小节 client architecture 或 data model 。
脚注
[1] 一个一致的视图不保证行内扫描——举例来说,在一个RPC中获取了一行的一部分,然后在后续的RPC中返回去获取这行的另一部分。当你设置了每一次Scan#next返回的值的数量时,行内扫描就会发生 (参考 Scan#setBatch(int)).
[2] 在Apache HBase的上下文中,"持久地在磁盘上"意味着在事务日志上调用了hflush()方法。这不是真的意味着 fsync()到磁性介质上,而是数据写入到日志的所有副本的OS缓存中。在整个数据中心断电的情况下,对数据的更新有可能不是真正的可持久化的。
[3] Put操作要么整体成功要么整体失败,这些Put操作是被发送到RegionServer上的。如果使用了writebuffer,则在写缓冲区被填满或显式刷新之前,将不会发送该缓冲区。