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(hbase-2.4.9-bin.tar.gz)是一个分布式的、面向列的开源数据库,该技术来源于 Fay Chang 所撰写的Google论文“Bigtable:一个结构化数据的分布式存储系统”。就像Bigtable利用了Google文件系统(File System...
5. **客户端连接**:HBase提供了命令行接口(HBase Shell)和Java API,可以用来交互式操作HBase或在应用程序中集成。 ### HBase的数据模型和操作 1. **创建表**:使用`create`命令创建表,指定列族。 2. **插入...
在使用过程中,用户需要根据实际需求配置相应的连接参数,如Zookeeper地址、HBase表名等。 Phoenix提供了丰富的SQL功能,包括创建表、插入数据、更新、删除、联接、子查询、聚合函数等。这些特性使得Phoenix在处理...
在大数据领域,HBase因其分布式、列式存储的特性,常被用于处理海量半结构化数据。然而,对于习惯于SQL语法的开发者来说,HBase的原生接口可能显得较为复杂。这时,Phoenix应运而生,它为HBase带来了SQL接口,使得...
赠送jar包:hbase-hadoop-compat-1.1.3.jar; 赠送原API文档:hbase-hadoop-compat-1.1.3-javadoc.jar; 赠送源代码:hbase-hadoop-compat-1.1.3-sources.jar; 赠送Maven依赖信息文件:hbase-hadoop-compat-1.1.3....
赠送jar包:hbase-prefix-tree-1.1.3.jar; 赠送原API文档:hbase-prefix-tree-1.1.3-javadoc.jar; 赠送源代码:hbase-prefix-tree-1.1.3-sources.jar; 赠送Maven依赖信息文件:hbase-prefix-tree-1.1.3.pom; ...
赠送jar包:hbase-metrics-api-1.4.3.jar; 赠送原API文档:hbase-metrics-api-1.4.3-javadoc.jar; 赠送源代码:hbase-metrics-api-1.4.3-sources.jar; 赠送Maven依赖信息文件:hbase-metrics-api-1.4.3.pom; ...
HBase,全称为Hadoop Distributed File System上的基础结构(HBase on Hadoop Distributed File System),是一种分布式的、面向列的开源数据库,它构建在Apache Hadoop文件系统(HDFS)之上,提供高可靠性、高性能...
《Phoenix与HBase的深度解析:基于phoenix-hbase-2.4-5.1.2版本》 在大数据处理领域,Apache HBase和Phoenix是两个至关重要的组件。HBase作为一个分布式、列式存储的NoSQL数据库,为海量数据提供了高效、实时的访问...
赠送jar包:hbase-hadoop-compat-1.1.3.jar; 赠送原API文档:hbase-hadoop-compat-1.1.3-javadoc.jar; 赠送源代码:hbase-hadoop-compat-1.1.3-sources.jar; 赠送Maven依赖信息文件:hbase-hadoop-compat-1.1.3....
phoenix-client-hbase-2.2-5.1.2.jar
HBase是Apache Hadoop生态系统中的一个分布式、版本化、列族式存储系统,设计用于处理大规模数据集。这个“hbase-2.4.17-bin”安装包提供了HBase的最新稳定版本2.4.17,适用于大数据处理和分析场景。下面将详细介绍...
赠送jar包:hbase-common-1.4.3.jar; 赠送原API文档:hbase-common-1.4.3-javadoc.jar; 赠送源代码:hbase-common-1.4.3-sources.jar; 赠送Maven依赖信息文件:hbase-common-1.4.3.pom; 包含翻译后的API文档:...
被编译的hive-hbase-handler-1.2.1.jar,用于在Hive中创建关联HBase表的jar,解决创建Hive关联HBase时报FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask. org.apache.hadoop....
HBase 元数据修复工具包。 ①修改 jar 包中的application.properties,重点是 zookeeper.address、zookeeper.nodeParent、hdfs.root.dir配置项,hdfs 最好写 ip; ②将core-site.xml、hdfs-site.xml添加到BOOT-INF/...
hbase-2.2.6-bin.tar.gz HBase是一个分布式的、面向列的开源数据库,该技术来源于 Fay Chang 所撰写的Google论文“Bigtable:一个结构化数据的分布式存储系统”。就像Bigtable利用了Google文件系统(File System)所...
phoenix-4.14.1-HBase-1.2-client.jar
HBase是Apache软件基金会开发的一个开源、分布式、版本化、基于列族的NoSQL数据库,设计用于处理海量数据。这个压缩包"**hbase-2.0.2-bin.tar**"包含了HBase 2.0.2的二进制发行版,它是针对大规模数据存储而优化的。...
赠送jar包:flink-hbase_2.11-1.10.0.jar; 赠送原API文档:flink-hbase_2.11-1.10.0-javadoc.jar; 赠送源代码:flink-hbase_2.11-1.10.0-sources.jar; 赠送Maven依赖信息文件:flink-hbase_2.11-1.10.0.pom; ...
"phoenix-5.0.0-HBase-2.0-client" 是一个针对Apache HBase数据库的Phoenix客户端库,主要用于通过SQL查询语句与HBase进行交互。这个版本的Phoenix客户端是为HBase 2.0版本设计和优化的,确保了与该版本HBase的兼容...