HBase RowLock系列问题

Hbase api 中 put delete checkandput 等都是独立执行的。
行锁分为隐式和显式。
行锁保证了只有一个客户端能获取一行数据的锁。
显式应用行锁已经被作为过时,不推荐使用。
行锁会不会出现死锁?
两个客户端拥有对方要的行锁,又同时请求对方拥有的锁,必然死锁。
这时,就需要一个服务器端额处理线程,来控制锁超时解决死锁的问题。
由hbase.regionserver.lease.period 属性设置超时时间。(后面看到这个配置也是控制扫描器租约的时间,用来保护其不被失效的客户端阻塞太久。前提是scanner 没有合理的close。)

public class RowLockTest implements Runnable {

    private static Configuration conf;
    private static HConnection conn;
    private static HTableInterface table;

    public static void init() throws IOException {
        conf = HBaseConfiguration.create();
        conn = HConnectionManager.createConnection(conf);
        table = conn.getTable("students".getBytes());
    }

    @Override
    public void run() {
        try {
            System.out.println("Thread trying to put same row now ...");

            Configuration conf1 = HBaseConfiguration.create();
            HConnection conn1 = HConnectionManager.createConnection(conf1);
            HTableInterface table1 = conn1.getTable("students".getBytes());

            Put put = new Put("Howard".getBytes());
            put.add("moreInfo".getBytes(), "phone".getBytes(), "110".getBytes());
            long time = System.currentTimeMillis();
            table1.put(put);
            System.out.println("Wait time: "
                    + (System.currentTimeMillis() - time) + " ms");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws IOException {

        init();
        System.out.println("Taking out lock...");
        RowLock lock = table.lockRow("Howard".getBytes());
        System.out.println("Lock ID: " + lock.getLockId());

        Thread thread = new Thread(new RowLockTest());
        thread.start();

        try {
            System.out.println("Sleeping 2s in main()...");
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        try {
            Put put1 = new Put("Howard".getBytes());
            put1.add("basicInfo".getBytes(), "age".getBytes(), "19".getBytes());
            table.put(put1);

            Put put2 = new Put("Howard".getBytes());
            put2.add("moreInfo".getBytes(), "phone".getBytes(),
                    "119".getBytes());
            table.put(put2);
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            System.out.println("Releasing lock...");
            table.unlockRow(lock);
        }
    }
}

如上,执行时,报出异常 UnknownRowLockException,原因是 在占有锁的线程main中,put构造器要把锁作为参数传给它,才能正确执行,不然regionserver不知道你占用的锁是哪个,报出异常,有兴趣的可以跟踪以下源码,查看具体执行机制。
有意思的是,上述代码中,如果run()中没有重新创建HConnection,而是用类中的static配置的几个conf、conn,会抛出异常,不能创建session等,可以理解为两个线程不能共享一个HConnection,需要有各自的连接。

修改过后,执行成功。
Taking out lock...
Lock ID: -3305589738841484909
Sleeping 2s in main()...
Thread trying to put same row now ...
11:28:33,075 INFO RecoverableZooKeeper:103 - The identifier of this process is 6516@LS--20151016UGR
11:28:33,076 INFO ZooKeeper:438 - Initiating client connection, connectString=hadoop-master:2181 sessionTimeout=180000 watcher=hconnection0x0
11:28:33,081 INFO ClientCnxn:966 - Opening socket connection to server hadoop-master/192.168.159.128:2181. Will not attempt to authenticate using SASL (unknown error)
11:28:33,083 INFO ClientCnxn:849 - Socket connection established to hadoop-master/192.168.159.128:2181, initiating session
11:28:33,905 INFO ClientCnxn:1207 - Session establishment complete on server hadoop-master/192.168.159.128:2181, sessionid = 0x158b7fc11490024, negotiated timeout = 180000
Releasing lock...
Wait time: 2665 ms

猜你喜欢

转载自blog.csdn.net/sinat_30333853/article/details/53419590