您的位置:首页 > 其它

Hbase-0.98.6源码分析--行锁

2016-06-21 11:25 393 查看
       在传统的关系型数据库,如MySQL中,存在事务(Transaction)这一概念 ,事务是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会执行。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。一个逻辑工作单元要成为事务,必须满足ACID(原子性、一致性、隔离性和持久性)属性。

       在事务特性方面,HBase这种NoSQL数据库中,并没有事务这种概念,它为了保证操作的原子性,采用行锁机制。HBase只支持单row的事务,不能保证跨row(cross-row)的事务。HBase通过行锁来实现单row事务。客户端进行操作时,可以显式对某一个行加锁,但官方并不推荐,原因是两个客户端很可能在拥有对方请求的锁时,又同时请求对方已拥有的锁,这样便形成了死锁,在锁超时前,两个被阻塞的客户端都会占用一个服务端的处理线程,而服务器线程是非常稀缺的资源。hbase在内部会默认的加行锁。在行锁未释放该行前,最起码其他访问者是无法对该行做修改的,即要修改的话,必须得获得该行的锁才能拥有修改改行数据的权限。

       HBase行锁是利用Java并发包concurrent里的CountDownLatch(1)来实现的。它的主要思想就是在服务器端每个访问者单独一个数据处理线程,每个处理线程针对特定行数据修改时必须获得该行的行锁,而其他客户端线程想要修改数据的话,必须等待前面的线程释放锁后才被允许,这就利用了Java并发包中的CountDownLatch,CountDownLatch为Java中的一个同步辅助类,在完成一组正在其他线程中进行的操作之前,它允许一个或多个线程一直等待。这里,将线程数设置为1,十分巧妙的实现了独占锁的概念。

       HBase的行锁主要是通过HRegion的两个内部类实现的,其中一个是RowLock,另外一个是RowLockContext。首先看RowLock这个类,其定义如下:



       再看RowLockContext的源码:



       通过源码,我们能清晰地看到,RowLockContext利用了java的concurrent并发包里的CountDownLatch(1)实现了线程对对象的独占锁。
       新加锁时,通过调用newLock()方法即可实现,首先锁的计数器lockCount加1,然后返回由当前RowContext构造RowLock实例即可。
       释放锁时,通过调用releaseLock()方法即可实现,首先通过ownedByCurrentThread()方法确保调用releaseLock()方法的当前线程是否和RowContext持有的线程一致,然后,锁的计数器lockCount减1,并且,如果lockCount为0的话,说明不再有操作占用该行,将row对应的行锁从数据结构lockedRows中删除,允许其他线程获得该行的行锁,最后,最重要的一步,latch.countDown(),就可完成行锁的释放了。

       至于行锁在HBase中的具体应用,举一个之前讲到过的方法doMiniBatchMutation()方法,在《Hbase-0.98.6源码分析--Put写操作HRegionServer端流程》中讲到过。该方法就调用了行锁机制。



        在对一行数据操作之前,都会调用getRowLock()方法,获得该行数据的行锁。代码如下:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: