HBase MVCC和内建的原子操作
来源:互联网 发布:为什么网络是脆弱的 编辑:程序博客网 时间:2024/05/18 18:46
原版英文地址:http://www.68idc.cn/help/mysqldata/nosql/20150302241120.html
By Lars Hofhansl
HBase有一些特殊的原子操作:
- checkAndPut,checkAndDelete:这些简单的检查列值作为执行 put 和 delete 的前提条件,检查成功则执行。
- Increment,Append:对一个列值进行原子操作,比如将一个整数值增加,或者在值的尾部追加
Increment和Append并不是幂等的,他们在HBase中是唯一的不可重复操作,他们也是唯一的对HBase MVCC 模型提供的快照隔离机制无效的操作。
事实证明,checkAndPut和checkAndDelete并不是我们期待那样的所谓原子操作(这个问题是Gregory提出的,虽然作者本人最开始并不相信这个问题是真的-见HBASE-7051)。
看下代码会让这个问题变得清晰:
一些针对Put的优化允许在修改同步到 WAL 之前释放行锁(HBASE-4528)。当然这需要MVCC的修改提交之前释放锁,以此来保证修改确认持久化之前对其他事务不可见。
其他的操作(比如 checkAndXXX)要求行锁做原子修改,尽管持有了行锁,但事实上可能并没有看到当前的快照,因为仍然有未完成的 MVCC 修改。这个快照只有在行锁被释放、重新获取之后才变成可见。所以后来就可能操作脏数据。在 HBASE-4528之后,仅仅持有行锁不再够用。
同理,Increment和Append操作同样有这方面的问题。
然而对这种问题的修改也相对来说简单:我们需要一个MVCC路障,来取代之前在更新完成后完成一个单独的MVCC事务(等待之前所有的事务结束),现在只需要在开始原子操作的检查获取(check and get)阶段之前就开始等待。(注:checkAndXXX分两个阶段,读检查阶段和修改阶段,之前是在修改阶段用一个MVCC事务,它会等待先前的事务结束,现在在读检查阶段就要等待先前的事务结束,避免脏读。MVCC 对于读操作是宽容的,而这个在读的时候就要等待了,所以降低了并发效率)。这样只是稍微降低了并发效率:在当前事务结束之前,需要无条件等待所有先前的事务。HBASE-7051完全是按照这样的方式实现了checkAndXXX操作。
另外,在上文提到,Increment和Append还有另一个问题,它们需要可串行化的事务。快照隔离不能满足需求。
比如:从0开始,一个操作Increment 1,另一个操作Increment 2,期望结果应该是3。但如果两个操作基于同一个快照0开始执行,结果要么是1,要么是2,取决于哪个先结束。
当前Increment和Append采用了一种取巧的方法来解决此问题:当他们需要将修改写进Memstore,他们把新 KeyValue的MemstoreTS设置为0(注:对于任何一个put,当其写入memstore的时候,都会设置其MemstoreTs的值。
而这个值在内存中是以一个递增的形式存在的,即新写入内存的数据比旧的其MemstoreTs大。而这个值就是用来保证在内存中的update的可靠性。这个值在《HBase内部的ACID》中提到过,它不是一般提到的时间戳,写操作开始之前取回的先前最大的事务号,应该叫WriteNumber,历史原因称为memstore timestamp),效果是这些修改马上对其他事务可见,但是破坏了HBase的MVCC机制。
这种做法保证了并发的Increment和Append操作的结果是正确的,但是对于并发 scanner 的可见度和我们的预期是不一致的。在 Increment 和 Append 执行修改的过程中,并发的 scanner 本来应该看到先前版本的数据快照,但是现在却可以看到部分行修改的结果。
Increment 和 Append 出于高吞吐量的设计考虑,他们会把HBase memstore 中刚刚修改后的列的老版本移除。这样一来,以丢失修改的版本历史为代价避免了 memstore 被 Increment 和 Append 的历史版本挤爆。这就是 HBase 中的“upsert”,(关于upsert的解释:upsert,与 insert 对比,in 表示插入,不覆盖,up 表示插上,历史版本没有了,相当于覆盖)。Upsert 的优点在于避免了 memstore 中旧数据的拥挤,缺点在于它们是memstore上没有了版本历史,违背了 MVCC 的理念。
- HBase MVCC和内建的原子操作
- gcc内建的原子操作
- GCC内建原子操作
- linux实现原子操作的内建函数
- Hbase原子性操作
- gcc内建原子操作总结
- 原子变量和原子操作
- HBase上region操作append加了行锁为什么还要mvcc等待之前的操作完成?
- java的原子操作和volatile
- volatile关键字和原子操作的区别
- volatile关键字和原子操作的区别
- Java:java的原子操作和volatile
- volatile关键字和原子操作的区别
- 原子操作和线程的并发执行
- Java 原子操作的原理和问题
- volatile和原子操作
- 原子操作和信号量
- 原子操作和锁
- MES安装配置流程说明
- Java代码实现设置系统时间
- 构建一个属于你自己的镜像
- IOException while loading persisted sessions: java.io.EOFException异常的解决办法
- android 文件缓存 DiskLruCache
- HBase MVCC和内建的原子操作
- LeetCode Add Binary(二进制加法)
- Error running app: Instant Run requires 'Tools | Android | Enable ADB integration' to be enabled.
- 标准的Java连接Oracle数据库的示例代码
- 营销案例,只保留一天,马上要删
- 从平庸到卓越!5个帮你快速提高设计稿质感的实用方法
- Lnmp中nginx经常出现502错误解决方法
- FPGA入门的基础知识
- JSON 之FastJson解析