HBase行锁
1 行锁简介
在事务特性方面,hbase只支持单row的事务,不能保证跨row(cross-row)的事务。hbase通过行锁来实现单row事务。客户端进行操作时,可以显式对某一个行加锁,但是大部分情况下是没有必要的,因为如果没有显式的加行锁,hbase在内部会默认的加行锁。为了描述方便,用户显式加的行锁简称为显式行锁。
源码1:客户端使用显式行锁的示例代码
HTable table = new HTable(config, tablename);
RowLock lock = table.lockRow(rowkey);//首先获得rowkey对应的行锁,可能阻塞
Put p1 = new Put(rowkey,lock);
p1.add(cf, qua,value); //在行rowkey上,写数据
table.put(p1);
table.unlockRow(lock);//解锁
hbase不推荐客户端显式加行锁,因为可能造成regionserver死锁。并且现在正就"客户端不支持显式加行锁"进行讨论。
引自hbase官网:
RowLocks are still in the client APIhowever they are
discouraged because if not managed properly thesecan lock up the RegionServers. There is an oustanding ticketHBASE-2332
to remove this feature from the client.
2 实现行锁
如下图所示,客户端看到的行锁由两部分组成:rowkey和外部锁id。外部锁id是向regionserver申请行锁时,由regionserver返回的。外部锁id在对应的regionserver上全局唯一。

图1 行锁的定义
如图2所示。一个regionserver对应一个HRegionServer实例,一个分片对应一个HRegion实例。
在HregionServer中提供两个接口lockRow和unlockRow,供客户端显式加锁和解锁。rowlocks存储了<客户端所见的锁id,内部锁id>的映射关系。因为内部锁id在分片内部是唯一的,但是在regionserver上不唯一,所以需要这个映射关系。
在HRegion中,lockedRows记录了所有已经加锁的行,lockIds记录了映射关系<内部锁id,rowkey>。

图2
为了处理客户端忘记释放锁的情况,显式行锁有一个租约(即有效期,默认是60秒,可配置,对应的配置项是hbase.regionserver.lease.period),如果显式行锁超过了租约时间,regionserver会自动释放行锁。在租约时间内,如果又收到了在这个行上的写请求,会延长租约时长。
加显式行锁的算法
1 判断目标行是否已经加锁,如果已经加锁,则等待至解锁。
while (lockedRows.contains(row))
lockedRows.wait();
2 分配内部锁id,记为lockId。并把映射关系<lockIds,row>加入至lockIds。lockId在region内是唯一的。
保证内部锁id唯一性的常规的解决办法是:找出一个没有使用过的id,然后分配给行锁。hbase采用的方法比较有意思:在内部维护一个id生成器,每次分配时,把id生成器的值分配给行锁,并且id生成器自增1。如果没有出现冲突(冲突:当前分配的id不唯一),分配完成。 如果出现冲突,为id生成器赋一随机值,然后重复的上面的流程,直到没有冲突,见源码2。
方法对比:如果使用常规方法,必然要使用到锁来进行并发控制,锁的开销还是比较大的。hbase认为出现冲突的可能性非常小,这种方法的开销应该远小于常规方法。这种提供性能的方法值得学习。
源码2:分配内部锁id。 见HRegion. internalObtainRowLock()
byte[] prev = null;
Integer lockId = null;
do
{
lockId = new Integer(lockIdGenerator++);//生成锁id
prev = lockIds.put(lockId, row);
if (prev != null)
//如果lockId已经分配了,即发生冲突
{
lockIds.put(lockId, prev);// 恢复被破坏的映射关系
lockIdGenerator = rand.nextInt();//生成新的锁id
}
} while (prev != null);
源码:添加映射关系
lockIds.put(lockId, row)
3 把目标行加入至lockedRows。
lockedRows.add(row);
4 为行锁分配外部锁id,这个id在regionserver内是唯一的。
lockId = rand.nextLong();//这种方法会给hbase带来问题,见第三节
5 在行锁上添加行锁监听器。
行锁监听器的主要功能是处理行锁的租约,租约过期时,自动释放行锁,收到新的写请求延长租约时长。
下图是实现行锁的类图。

图3 实现行锁类图
3 设计缺陷
在加显式行锁算法的第4步中,因为Random对象可能产生重复的值,所以分配的外部锁id可能不唯一。
通过修改regionserver的代码,模拟生成重复锁id的情况,测试流程如下:
1修改regionserver的代码使得每次分配的外部锁id都为999
2线程1为rowkey1申请行锁;线程2为rowkey2申请行锁。线程1和线程2同时并发运行。
测试发现只要只要rowkey1对应的行锁不释放,线程2会永远阻塞。
修正方法:保证外部锁id的唯一性。
HBase行锁的更多相关文章
- HBase行锁原理及实现
请带着例如以下问题阅读本文. 1.什么是行锁? 2.HBase行锁的原理是什么? 3.HBase行锁是怎样实现的? 4.HBase行锁是怎样应用的? 一.什么是行锁? 我们知道.数据库中存在事务的概念 ...
- 数据库进阶之路(五) - MySQL行锁深入研究
由于业务逻辑的需要,必须对数据表的一行或多行加入行锁,举个最简单的例子,图书借阅系统:假设id=1的这本书库存为1,但是有2个人同时来借这本书,此处的逻辑为: ; --如果restnum大于0,执行u ...
- 浅谈SQL Transaction在请求中断后的行锁表锁
最近在维护Web Service接口时,由于数据数据量达到千万级别,接口调用不时出现错误让人不胜烦恼,经过性能测试查出瓶颈在数据库数据处理上,可着实忙了一番.相信众多程序猿和DBA都会头痛性能的问题, ...
- MySQL行锁深入研究
原文:http://blog.csdn.net/minipeach/article/details/5325161/ 做项目时由于业务逻辑的需要,必须对数据表的一行或多行加入行锁,举个最简单的例子,图 ...
- select for update行锁
select for update行锁 2008-05-26 15:15:37 分类: Oracle Select-For Update语句的语法与select语句相同,只是在select语句的后面 ...
- Innodb行锁源码学习(一)
Innodb是mysql数据库中目前最流行的存储引擎,innodb相对其它存储引擎一个很大的特点是支持事务,并且支持行粒度的锁.今天我重点跟大家分享下innodb行锁实现的基础知识.由于篇幅比较大,文 ...
- mysql行锁和表锁
mysql innodb支持行锁和表锁,但是MyIsam只支持表锁.现在我们说说mysql innodb的行锁和 有如下表id为主键 为了出现演示效果,我们将mysql的autocommit设置为0 ...
- Mysql InnoDB行锁实现方式(转)
Mysql InnoDB行锁实现方式 InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MySQL与Oracle不同,后者是通过在数据块中对相应数据行加锁来实现的.InnoDB这种行锁实现特点 ...
- Mysql InnoDB行锁实现方式
Mysql InnoDB行锁实现方式 InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MySQL与Oracle不同,后者是通过在数据块中对相应数据行加锁来实现的.InnoDB这种行锁实现特点 ...
随机推荐
- JAVA面向对象-----内部类的概述
JAVA面向对象-–内部类的概述s 将类定义在另一个类的内部则成为内部类.其实就是类定义的位置发生了变化. 在一个类中,定义在类中的叫成员变量,定义在函数中的叫成员函数,那么根据类定义的位置也可以分为 ...
- Struts 2 之配置文件
Struts 1使用ActionServlet作为分发器,而Struts 2使用Filter作为分发器.如果有多个Filter,要把Struts 2的分发器Filter放在最后 web.xml < ...
- SSH网上商城---用户激活
在前面的博客中,小编主要结合SSH网上商城这个项目,简单的介绍了如何实现邮件发送的这个功能,邮件发送了,接下来就是激活了,为什么呢?现在大多网站都要通过对账号进行激活,然后才能注册成功,这是防止恶性注 ...
- JVM的GC(概念与深入)
深入浅出了解什么是GC: http://my.oschina.net/xianggao/blog/86985 GC策略详解: http://blog.csdn.net/winniepu/article ...
- Android传感器概述-android学习之旅(七)
传感器概述 传感器是第二代智能手机的重要标志之一.现在许多的手机和平板都内置了传感器(tv除外).android的SDK支持许多的传感器有十几种,但是手机只是支持一部分.例如方向传感器(电子罗盘)和重 ...
- android RecycleView Adapter简单封装
早些时候我们使用系统提供个的BaseAdapter的时候为了满足大家的需要,我们总会对BaseAdapter做一层上层的封装,然后对于实际业务我们只需要关心getView里面的View即可,是代码可读 ...
- 浅谈C++中的友元关系
在封装中C++类数据成员大多情况是private属性:但是如果接口采用多参数实现肯定影响程序效率:然而这时候如果外界需要频繁访问这些私有成员,就不得不需要一个既安全又理想的"后门" ...
- C语言--测试电脑存储模式(大端存储OR小端存储)
相信大家都知道大端存储和小端存储的概念,这在平时,我们一般不用考虑,但是,在某些场合,这些概念就显得很重要,比如,在 Socket 通信时,我们的电脑是小端存储模式,可是传送数据或者消息给对方电脑时, ...
- JPA(三)之实体关系一对多(多对一)
1.背景介绍: 对于购买商品时,订单信息(Order)和订单商品信息(OrderItem)的关系就是一对多的关系. 2.实体bean: Order.java代码 ? 1 2 3 4 5 6 7 ...
- Fedora 19: How to resize/extend (LVM) partition?
Enlarge the disk using fdisk fdisk -l (to see the partition layout, typically we're dealing with /de ...