最近因在项目开发过程中需要用到多线程操作HBase数据库,在调研HBase的连接池的过程中,有了一些收获,分享给大家。
1.连接
HTable是HBase的client,负责从meta表中找到目标数据所在的RegionServers,当定位到目标RegionServers后,client直接和RegionServers交互,而不比再经过master。
HTable实例并不是线程安全的。
当需要创建HTable实例时,明智的做法是使用相同的HBaseConfiguration实例,这使得共享连接到RegionServers的ZK和socket实例。例如,应该使用这样的代码:
HBaseConfiguration conf = HBaseConfiguration.create();
HTable table1 = new HTable(conf, "table1");
HTable table2 = new HTable(conf, "table2");
而不是用下面的代码:
HBaseConfiguration conf1 = HBaseConfiguration.create();
HTable table1 = new HTable(conf1, "table1");
HBaseConfiguration conf2 = HBaseConfiguration.create();
HTable table2 = new HTable(conf2, "table2");
2. 连接池
当面对多线程访问需求时,为了避免较大的系统资源开销,需要预先建立HConnection。
//Create a connection to the cluster.
HConnection connection = HConnectionManager.createConnection(Configuration);
HTableInterface table = connection.getTable("myTable");
// use table as needed, the table returned is lightweight
table.close();
// use the connection for other access to the cluster
connection.close();
通过HTableInterface获取hbase表的实现是非常轻量级的,并且资源是可控的。
说明:HTablePool是HBase连接池的老用法,该类在0.94,0.95和0.96中已经不建议使用,在0.98.1版本以后已经移除。
3.HConnectionManager
HConnectionManager是一个不可实例化的类,专门用于创建HConnection。
最简单的创建HConnection实例的方式是
HConnectionManager.createConnection(config),该方法创建了一个连接到集群的HConnection实例,该实例被创建的程序管理。通过这个HConnection实例,可以使用
HConnection.getTable(byte[])方法取得
HTableInterface implementations的实现,例如
:
HConnection connection = HConnectionManager.createConnection(config);
HTableInterface table = connection.getTable("tablename");
try {
// Use the table as needed, for a single operation and a single thread
} finally {
table.close();
connection.close();
}
(1)static HConnection createConnection(org.apache.hadoop.conf.Configuration conf)
创建一个新的HConnection实例。
该方法绕过了常规的HConnection生命周期管理,常规是通过
getConnection(Configuration)来获取连接。调用方负责执行
Closeable.close()
来关闭获得的连接实例。
推荐的创建HConnection的方法是:
HConnection connection = HConnectionManager.createConnection(conf);
HTableInterface table = connection.getTable("mytable");
table.get(...);
...
table.close();
connection.close();
(2)public static HConnection getConnection(org.apache.hadoop.conf.Configuration conf)
根据conf获取连接实例。如果没有对应的连接实例存在,该方法创建一个新的连接。
说明:该方法在0.96和0.98版本中都被Deprecated了,不建议使用,但是在最新的未发布代码版本中又复活了!!!
public class ConnectionPoolTest {
private static final String QUORUM = "hbase1,hbase2,hbase3";
private static final String CLIENTPORT = "2181";
private static final String TABLENAME = "testTable";
private static Configuration conf = null;
private static HConnection conn = null;
static{
try {
conf = HBaseConfiguration.create();
conf.set("hbase.zookeeper.quorum", QUORUM);
conf.set("hbase.zookeeper.property.clientPort", CLIENTPORT);
conn = HConnectionManager.createConnection(conf);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
HTableInterface htable = ConnectionPoolTest.conn.getTable(TABLENAME);
try {
Scan scan = new Scan();
ResultScanner rs = htable.getScanner(scan);
for (Result r : rs.next(5)) {
for (Cell cell : r.rawCells()) {
System.out.println("Rowkey : " + Bytes.toString(r.getRow())
+ " Familiy:Quilifier : "
+ Bytes.toString(CellUtil.cloneQualifier(cell))
+ " Value : "
+ Bytes.toString(CellUtil.cloneValue(cell))
+ " Time : " + cell.getTimestamp());
}
}
} finally {
htable.close();
}
}
}