HBase(五) HBase JAVA API - HTable、HTablePool与底层连接的共享
HTable、HTablePool与底层连接的共享
HTable
单表交互的API,HBASE的CRUD操作都是使用这个类。继承自HTableInterface接口。
HTable实例的创建过程比较消耗资源,如每个实例都要扫描.META.表,以检查该表是否存在、是否可用,还有其他的一些操作,所以HTable实例不适合频繁的创建,要尽量复用。
HTable不是线程安全类,并发场景要注意隔离。如果是多线程场景,适合为每个线程分配一个HTable实例,或者使用HTablePool。
HTable的所有操作,都保证也只能保证行级别的原子性。
HTablePool
HTablePool是HTable的池化管理类,有几种构造函数,无参的构造函数默认会创建一个无限大的池,一般不建议这么用,使用需要指定最大实例数目的构造函数。还有自定义HTableInterfaceFactory的构造函数,使用这种构造函数可以自定义HTable的一些特殊的配置,比如一些初始化操作等。
使用getTable(String tableName)方法从池中取HTable实例,使用后调用putTable(HTableInterface table)方法放回。
有一点需要注意(个人认为也是hbase实现的问题),maxSize参数并不强行限制用户能得到的HTableInterface实例的上限,客户端能用getTable方法访问尽可能多的table实例。这个参数仅仅能设置池中能存放的HTableInterface实例的数目,比如maxSize=5,调用10次getTable会创建10个实例,后调用putTable,只有5次可以发挥作用,后面5次会被忽略,包括工厂的release机制也不会被触发,只是单纯的抛弃。
Configuration conf = HBaseConfiguration.create();
HTablePool pool = new HTablePool(conf, 5);
HTableInterface [] tables = new HTableInterface[10];
// 超出容量一样可以分配
for(int i=0;i<10;i++){
tables[i] = pool.getTable("t1");
System.out.println(Bytes.toString(tables[i].getTableName()));
}
for(int i=0;i<10;i++){
pool.putTable(tables[i]);
}
pool.closeTablePool("t1");
closeTablePool方法会遍历所有保存在列表中与参数对应的表的引用,使用工厂的release机制,会释放一张表的所有资源。所有的资源都要处理异常并释放,代码中使用过的表都要调用这个方法去释放资源
连接管理
每个HTable实例底层都需要与服务器连接,连接是HConnection类表示的,并使用HConnectionManager类管理和共享。使用API时不需要直接实例化这两个类,只需要创建一个Configuration实例,然后隐式的使用连接。
Hbase使用key-value的方式存储连接,Configuration实例作为KEY,而连接作为value,所以,不管有多少个HTable实例,只要共用一个Configuration实例的引用,那么他们都共享同一个底层的HConnection实例。共享的部分包括zk的连接,-ROOT- 和 .META.的地址,及region的地址缓存。当缓存失效时,有重试机制来刷新缓存。
HTablePool中,所有的HTable实例都自动共用一个Configuration实例,所以也是共享连接的。
每次重用Configuration,连接管理器都会增加引用计数,不使用的HTable一定要调用close方法释放所有连接(或者引用计数),否则可能导致zk连接耗尽、句柄耗尽等问题。close方法还会隐式的调用flushCache方法。
HConnectionManager提供了两个静态方法,可以显式的关闭Configuration实例相关的所有连接或者全部连接
deleteConnection(org.apache.hadoop.conf.Configuration conf)
deleteAllConnections(boolean stopProxy)
- 点赞
- 收藏
- 关注作者
评论(0)