说明:
近期两天在调研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;
    }

}

该方法逻辑非常easy:
依据传入的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取决于当前username及当前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>
42   <version>2.0.0-SNAPSHOT</version>
43   <name>HBase</name>
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
49   </description>

HBase即将迎来2.0.0版本号!!
HBase的下一个公布版是否会像Hadoop2.0那样来一个华丽丽的升华。迎来众多牛逼的新特性呢?

版权声明:本文博主原创文章,博客,未经同意不得转载。

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

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

      说明: 最近两天在调研HBase的连接池,有了一些收获,特此记录下来. 本文先将官方文档(http://hbase.apache.org/book.html)9.3.1.1节翻译,方便大家阅读,然 ...

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

    目标: 编译Apache Hadoop2.2.0在win7x64环境下的Eclipse插件 环境: win7x64家庭普通版 eclipse-jee-kepler-SR1-win32-x86_64.z ...

  3. 【甘道夫】MapReduce实现矩阵乘法--实现代码

    之前写了一篇分析MapReduce实现矩阵乘法算法的文章: [甘道夫]Mapreduce实现矩阵乘法的算法思路 为了让大家更直观的了解程序运行,今天编写了实现代码供大家參考. 编程环境: java v ...

  4. 【甘道夫】HBase(0.96以上版本号)过滤器Filter具体解释及实例代码

    说明: 本文參考官方Ref Guide,Developer API和众多博客.并结合实測代码编写.具体总结HBase的Filter功能,并附上每类Filter的对应代码实现. 本文尽量遵从Ref Gu ...

  5. 【甘道夫】HBase基本数据操作的详细说明【完整版,精绝】

    介绍 之前具体写了一篇HBase过滤器的文章.今天把基础的表和数据相关操作补上. 本文档參考最新(截止2014年7月16日)的官方Ref Guide.Developer API编写. 全部代码均基于& ...

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

    异常: 2014-02-24 12:15:48,507 WARN  [Thread-2] util.DynamicClassLoader (DynamicClassLoader.java:<in ...

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

    引言 之前详细写了一篇HBase过滤器的文章,今天把基础的表和数据相关操作补上. 本文档参考最新(截止2014年7月16日)的官方Ref Guide.Developer API编写. 所有代码均基于“ ...

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

    环境: Win764bit Eclipse Version: Kepler Service Release 1 java version "1.7.0_40" 第一步:Eclips ...

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

    准备: 确保hadoop2.2.0集群正常执行 1.eclipse中建立javaproject,导入hadoop2.2.0相关jar包 2.在src根文件夹下拷入log4j.properties,通过 ...

随机推荐

  1. uva 11722 - Joining with Friend(概率)

    题目连接:uva 11722 - Joining with Friend 题目大意:你和朋友乘火车,而且都会路过A市.给定两人可能到达A市的时段,火车会停w.问说两人能够见面的概率. 解题思路:y = ...

  2. VS2010,原来还有这些快捷键,果断记下来!

    一直认为VS的快捷键跟eclipse比起来差远了,那些由于不知道还有如此多有效却不知的快捷键阿 1. 检查括号匹配(在左右括号间切换): Ctrl +] 2. 选中从光标起到行首(尾)间的代码: Sh ...

  3. arcgis jsapi 调用google地区服务

    做地理信息系统(GIS)项目,除了实现功能用户体验度要好之外,最重要的是地图渲染效果更要好.很多时候苦于数据的完整性和对于配图的审美观,程序猿们都很难配出好看的地图效果.基于上述一般直接调用googl ...

  4. 整理QTP知识之1

    以下说明由网络其他文章整合而成. 一.关于QTP的说明 QTP是目前市场上占有率最高的一款自动化测试工具,也是每一位测试工作者最想掌握的工具之一,也是目前流行的基于GUI的功能自动化测试工具之一. Q ...

  5. sed中求公共前缀

    string1="test toast" string2="test test" printf "%s\n%s\n" "$stri ...

  6. android 泰国/缅甸语/捷克较低,Contacts联系出现精神错乱之类的问题清单

    更改ContactsProvider2.java文件 public static final String SECTION_HEADING = "SUBSTR(%1$s,1,1)" ...

  7. c++学习笔记4,调用派生类的顺序构造和析构函数(一个)

    测试源代码: //測试派生类的构造函数的调用顺序何时调用 //Fedora20 gcc version=4.8.2 #include <iostream> using namespace ...

  8. rsync+inotify 实现资源服务器的同步目录下的文件变化时,备份服务器的同步目录更新,以资源服务器为准,去同步其他客户端

    测试环境: 资源服务器(主服务器):192.168.200.95 备份服务器(客户端):192.168.200.89 同步目录:/etc/test 同步时使用的用户名hadoop密码12345 实验目 ...

  9. 【原创】只学到二维数组和结构体,不用链表也能写一个C贪食蛇?(四)

    全系列Index: [原创]只学到二维数组和结构体,不用链表也能写一个C贪食蛇?(一) [原创]只学到二维数组和结构体,不用链表也能写一个C贪食蛇?(二) [原创]只学到二维数组和结构体,不用链表也能 ...

  10. Swing-email(转)

    项目结构: 运行效果: 如果你感兴趣,请不要那我的邮箱做测试!!!! ========================================================== 下面是代码部 ...