【甘道夫】HBase连接池 -- HTablePool被Deprecated之后

说明:

最近两天在调研HBase的连接池,有了一些收获,特此记录下来。

本文先将官方文档(http://hbase.apache.org/book.html)9.3.1.1节翻译,方便大家阅读,然后查阅了关键类HConnectionManager的Developer API(http://hbase.apache.org/devapidocs/index.html) 做了一些总结。

最后介绍一些阅读0.96、0.98及最新源码的精彩发现。


欢迎转载,请注明来源:

http://blog.csdn.net/u010967382/article/details/38046821


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, "myTable");
HTable table2 = new HTable(conf, "myTable");

而不是这样的代码:

HBaseConfiguration conf1 = HBaseConfiguration.create();
HTable table1 = new HTable(conf1, "myTable");
HBaseConfiguration conf2 = HBaseConfiguration.create();
HTable table2 = new HTable(conf2, "myTable");

2.连接池

当面对多线程访问需求时,我们可以预先建立HConnection,参见以下代码:

Example 9.1. Pre-Creating a 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实现是非常轻量级的,并且资源是可控的。

注意:

HTablePool是HBase连接池的老用法,该类在0.94,0.95和0.96中已经不建议使用,在0.98.1版本以后已经移除。


BTW:简陋的官方文档到此为止。。。。Orz


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();

}

3.1构造函数

无,不可实例化。

3.2常用方法

(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了,不建议使用,但是在最新的未发布代码版本中又复活了!!!

3.3实例代码

package fulong.bigdata.hbase;

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.hbase.Cell;

import org.apache.hadoop.hbase.CellUtil;

import org.apache.hadoop.hbase.HBaseConfiguration;

import org.apache.hadoop.hbase.client.HConnection;

import org.apache.hadoop.hbase.client.HConnectionManager;

import org.apache.hadoop.hbase.client.HTableInterface;

import org.apache.hadoop.hbase.client.Result;

import org.apache.hadoop.hbase.client.ResultScanner;

import org.apache.hadoop.hbase.client.Scan;

import org.apache.hadoop.hbase.util.Bytes;

public class ConnectionPoolTest {

private static final String QUORUM = "FBI001,FBI002,FBI003";

private static final String CLIENTPORT = "2181";

private static final String TABLENAME = "rd_ns:itable";

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();

}

}

}


4.阅读源码的新发现

4.1消失的HConnectionManager.getConnection

从0.96和0.98版本HConnectionManager的源码中可以看到

static final Map<HConnectionKey, HConnectionImplementation> CONNECTION_INSTANCES;

就是连接池,连接池中的每个连接用HConnectionKey来标识,然而,HConnectionManager源码中所有涉及CONNECTION_INSTANCES的方法全都被Deprcated了。

我们来看已经被Deprecated的getConnection方法:

/**

* Get the connection that goes with the passed <code>conf</code> configuration instance.

* If no current connection exists, method creates a new connection and keys it using

* connection-specific properties from the passed {@link Configuration}; see

* {@link HConnectionKey}.

@param conf configuration

@return HConnection object for <code>conf</code>

@throws ZooKeeperConnectionException

*/

@Deprecated

public static HConnection getConnection(final Configuration conf)

throws IOException {

HConnectionKey connectionKey = new HConnectionKey(conf);

synchronized (CONNECTION_INSTANCES) {

HConnectionImplementation connection = CONNECTION_INSTANCES.get(connectionKey);

if (connection == null) {

connection = (HConnectionImplementation)createConnection(conf, true);

CONNECTION_INSTANCES.put(connectionKey, connection);

else if (connection.isClosed()) {

HConnectionManager.deleteConnection(connectionKey, true);

connection = (HConnectionImplementation)createConnection(conf, true);

CONNECTION_INSTANCES.put(connectionKey, connection);

}

connection.incCount();

return connection;

}

}

该方法逻辑很简单:

根据传入的conf构建HConnectionKey,然后以HConnectionKey实例为key到连接池Map对象CONNECTION_INSTANCES中去查找connection,如果找到就返回connection,如果找不到就新建,如果找到但已被关闭,就删除再新建

我们来看HConnectionKey的构造函数:

HConnectionKey(Configuration conf) {

Map<String, String> m = new HashMap<String, String>();

if (conf != null) {

for (String property : CONNECTION_PROPERTIES) {

String value = conf.get(property);

if (value != null) {

m.put(property, value);

}

}

}

this.properties = Collections.unmodifiableMap(m);

try {

UserProvider provider = UserProvider.instantiate(conf);

User currentUser = provider.getCurrent();

if (currentUser != null) {

username = currentUser.getName();

}

catch (IOException ioe) {

HConnectionManager.LOG.warn("Error obtaining current user, skipping username in HConnectionKey", ioe);

}

}

由以上源码可知,接收conf构造HConnectionKey实例时,其实是将conf配置文件中的属性赋值给HConnectionKey自身的属性,换句话说,不管你new几次,只要conf的属性相同,new出来的HConnectionKey实例的属性都相同。

结论一:conf的属性 --》 HConnectionKey实例的属性

接下来,回到getConnection源码中看到这样一句话:

HConnectionImplementation connection = CONNECTION_INSTANCES.get(connectionKey);

该代码是以HConnectionKey实例为key来查找CONNECTION_INSTANCES这个LinkedHashMap中是否已经包含了HConnectionKey实例为key的键值对,这里要注意的是,map的get方法,其实获取的是key的hashcode,这个自己读JDK源码就能看到。

然而HConnectionKey已经重载了hashcode方法:

@Override

public int hashCode() {

final int prime = 31;

int result = 1;

if (username != null) {

result = username.hashCode();

}

for (String property : CONNECTION_PROPERTIES) {

String value = properties.get(property);

if (value != null) {

result = prime * result + value.hashCode();

}

}

return result;

}

在该代码中,最终返回的hashcode取决于当前用户名及当前conf配置文件的属性。所以,只要conf配置文件的属性和用户相同,HConnectionKey实例的hashcode就相同!

结论二:conf的属性 --》HConnectionKey实例的hashcode

再来看刚才这句代码:

HConnectionImplementation connection = CONNECTION_INSTANCES.get(connectionKey);

对于get方法的参数connectionKey,不管connectionKey是不是同一个对象,只要connectionKey的属性相同,那connectionKey的hasecode就相同,对于get方法而言,也就是同样的key!!!

所以,可以得出结论三:conf的属性
--》
HConnectionKey实例的hashcode --》 get返回的connection实例

结论三换句话说说:

conf的属性相同 --》 CONNECTION_INSTANCES.get返回同一个connection实例

然而,假设我们的HBase集群只有一个,那我们的HBase集群的conf配置文件也就只有一个(固定的一组属性),除非你有多个HBase集群另当别论。

在这样一个机制下,如果只有一个conf配置文件,则连接池中永远只会有一个connection实例!那“池”的意义就不大了!

所以,代码中才将基于getConnection获取池中物的机制Deprecated了,转而在官方文档中建议:

*******************************************************************************************************************

当面对多线程访问需求时,我们可以预先建立HConnection,参见以下代码:

Example 9.1. Pre-Creating a 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实现是非常轻量级的,并且资源是可控的。

*******************************************************************************************************************

(以上重新拷贝了一次官方文档的翻译)

如果大家按照官方文档的建议做了,也就是预先创建了一个连接,以后的访问都共享该连接,这样的效果其实和过去的getConnection完全一样,都是在玩一个connection实例


4.2 HBase的新时代

我查看了Git上最新版本的代码(https://git-wip-us.apache.org/repos/asf?p=hbase.git;a=tree),发现getConnection复活了:

/**

* Get the connection that goes with the passed <code>conf</code> configuration instance.

* If no current connection exists, method creates a new connection and keys it using

* connection-specific properties from the passed {@link Configuration}; see

* {@link HConnectionKey}.

@param conf configuration

@return HConnection object for <code>conf</code>

@throws ZooKeeperConnectionException

*/

public static HConnection getConnection(final Configuration conf) throws IOException {

return ConnectionManager.getConnectionInternal(conf);

}

这个不是重点,重点是最新版本代码的pom:

39   <groupId>org.apache.hbase</groupId>

40   <artifactId>hbase</artifactId>

41   <packaging>pom</packaging>

42   <version>2.0.0-SNAPSHOT</version>

43   <name>HBase</name>

44   <description>

45     Apache HBase\99 is the Hadoop database. Use it when you need

46     random, realtime read/write access to your Big Data.

47     This project‘s goal is the hosting of very large tables -- billions of rows X millions of columns -- atop clusters

48     of commodity hardware.

49   </description>

HBase即将迎来2.0.0版本!!

HBase的下一个发布版是否会像Hadoop2.0那样来一个华丽丽的升华,迎来众多牛逼的新特性呢?

CHANGES.txt文档中没法得到最新的信息,最后一次更新还在2012年2月24日,看来开源大佬们也是爱编码不爱写文档的主。。

时间: 2024-10-12 17:43:25

【甘道夫】HBase连接池 -- HTablePool被Deprecated之后的相关文章

Hbase的连接池--HTablePool被Deprecated之后

说明: 最近两天在调研HBase的连接池,有了一些收获,特此记录下来. 本文先将官方文档(http://hbase.apache.org/book.html)9.3.1.1节翻译,方便大家阅读,然后查阅了关键类HConnectionManager的Developer API(http://hbase.apache.org/devapidocs/index.html) 做了一些总结. 最后介绍一些阅读0.96.0.98及最新源码的精彩发现. 1.连接 HTable是HBase的client,负责从

【甘道夫】Eclipse+Maven搭建HBase开发环境及HBaseDAO代码示例

环境: Win764bit Eclipse Version: Kepler Service Release 1 java version "1.7.0_40" 第一步:Eclipse中新建Maven项目,编辑pom.xml并更新下载jar包 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance&qu

【甘道夫】Win7环境下Eclipse连接Hadoop2.2.0

准备: 确保hadoop2.2.0集群正常运行 1.eclipse中建立java工程,导入hadoop2.2.0相关jar包 2.在src根目录下拷入log4j.properties,通过log4j查看详细日志 log4j.rootLogger=debug, stdout, R log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLa

【甘道夫】HBase基本数据操作详解【完整版,绝对精品】

引言 之前详细写了一篇HBase过滤器的文章,今天把基础的表和数据相关操作补上. 本文档参考最新(截止2014年7月16日)的官方Ref Guide.Developer API编写. 所有代码均基于"hbase 0.96.2-hadoop2"版本编写,均实测通过. 欢迎转载,请注明来源: http://blog.csdn.net/u010967382/article/details/37878701 概述 对于建表,和RDBMS类似,HBase也有namespace的概念,可以指定表空

【甘道夫】HBase开发环境搭建过程中可能遇到的异常:No FileSystem for scheme: hdfs

异常: 2014-02-24 12:15:48,507 WARN  [Thread-2] util.DynamicClassLoader (DynamicClassLoader.java:<init>(106)) - Failed to identify the fs of dir hdfs://fulonghadoop/hbase/lib, ignored java.io.IOException: No FileSystem for scheme: hdfs 解决: 在pom文件中加入: &

【甘道夫】HBase(0.96以上版本)过滤器Filter详解及实例代码

说明: 本文参考官方Ref Guide,Developer API和众多博客,并结合实测代码编写,详细总结HBase的Filter功能,并附上每类Filter的相应代码实现. 本文尽量遵从Ref Guide中"9.4. Client Request Filters"的行文顺序,便于读者对比查看,但内容比官方文档更加详实. 欢迎转载,请注明来源: http://blog.csdn.net/u010967382/article/details/37653177 目录: 引言 -- 参数基础

【甘道夫】Sqoop1.99.3基础操作--导入Oracle的数据到HDFS

第一步:进入客户端Shell [email protected]:~$ sqoop.sh client Sqoop home directory: /home/fulong/Sqoop/sqoop-1.99.3-bin-hadoop200 Sqoop Shell: Type 'help' or '\h' for help. sqoop:000> set server --host FBI003 --port 12000 --webapp sqoop Server is set successfu

【甘道夫】Hadoop2.2.0环境使用Sqoop-1.4.4将Oracle11g数据导入HBase0.96,并自动生成组合行键

目的: 使用Sqoop将Oracle中的数据导入到HBase中,并自动生成组合行键! 环境: Hadoop2.2.0 Hbase0.96 sqoop-1.4.4.bin__hadoop-2.0.4-alpha.tar.gz Oracle11g jdk1.7 Ubuntu14 Server 这里关于环境吐槽一句: 最新版本的Sqoop1.99.3功能太弱,只支持导入数据到HDFS,没有别的任何选项,太土了!(如有不同意见欢迎讨论给出解决方案) 命令: sqoop import --connect

【甘道夫】Win7x64环境下编译Apache Hadoop2.2.0的Eclipse小工具

目标: 编译Apache Hadoop2.2.0在win7x64环境下的Eclipse插件 环境: win7x64家庭普通版 eclipse-jee-kepler-SR1-win32-x86_64.zip Apache Ant(TM) version 1.8.4 compiled on May 22 2012 java version "1.7.0_45" 參考文章: http://kangfoo.u.qiniudn.com/article/2013/12/build-hadoop2x