Apache spark HBase Spark连接器:是否为每次扫描建立到HBase的连接?

Apache spark HBase Spark连接器:是否为每次扫描建立到HBase的连接?,apache-spark,hbase,google-cloud-bigtable,Apache Spark,Hbase,Google Cloud Bigtable,我正在使用Cloudera的HBase Spark连接器进行密集的HBase或BigTable扫描。它工作正常,但查看Spark的详细日志,代码似乎试图通过每次调用来重新建立与HBase的连接,以处理我通过JavaHBaseContext.foreachPartition()执行的Scan() 我是否认为该代码每次都会重新建立到HBase的连接?如果是这样,我如何重新编写它以确保重用已建立的连接 下面是产生此行为的完整示例代码: import org.apache.hadoop.hbase.cl

我正在使用Cloudera的HBase Spark连接器进行密集的HBase或BigTable扫描。它工作正常,但查看Spark的详细日志,代码似乎试图通过每次调用来重新建立与HBase的连接,以处理我通过
JavaHBaseContext.foreachPartition()
执行的
Scan()

我是否认为该代码每次都会重新建立到HBase的连接?如果是这样,我如何重新编写它以确保重用已建立的连接

下面是产生此行为的完整示例代码:

import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.filter.FilterList;
import org.apache.hadoop.hbase.filter.FirstKeyOnlyFilter;
import org.apache.hadoop.hbase.filter.KeyOnlyFilter;
import org.apache.hadoop.hbase.filter.PageFilter;
import org.apache.hadoop.hbase.filter.PrefixFilter;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.spark.JavaHBaseContext;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.VoidFunction;

import scala.Tuple2;

import java.util.Iterator;

public class Main
{   
    public static void main(String args[]) throws Exception
    {

        SparkConf sc = new SparkConf().setAppName(Main.class.toString()).setMaster("local");        
        Configuration hBaseConf = HBaseConfiguration.create();
        Connection hBaseConn = ConnectionFactory.createConnection(hBaseConf);

        JavaSparkContext jSPContext = new JavaSparkContext(sc);
        JavaHBaseContext hBaseContext = new JavaHBaseContext(jSPContext, hBaseConf);

        int numTries = 5;
        byte rowKey[] = "ffec939d-bb21-4525-b1ff-f3143faae2".getBytes();
        for(int i = 0; i < numTries; i++)
        {
            Scan s = new Scan(rowKey);
            FilterList fList = new FilterList(FilterList.Operator.MUST_PASS_ALL);
            fList.addFilter(new KeyOnlyFilter());
            fList.addFilter(new FirstKeyOnlyFilter());
            fList.addFilter(new PageFilter(5));
            fList.addFilter(new PrefixFilter(rowKey));
            s.setFilter(fList);
            s.setCaching(5);            

            JavaRDD<Tuple2<ImmutableBytesWritable, Result>> scanRDD = hBaseContext
                    .hbaseRDD(hBaseConn.getTable(TableName.valueOf("FFUnits")).getName(), s);   

            hBaseContext.foreachPartition(scanRDD,  new VoidFunction<Tuple2<Iterator<Tuple2<ImmutableBytesWritable,Result>>, Connection>>(){
                private static final long serialVersionUID = 1L;
                public void call(Tuple2<Iterator<Tuple2<ImmutableBytesWritable,Result>>, Connection> t) throws Exception{
                    while (t._1().hasNext())
                        System.out.println("\tCurrent row: " + new String(t._1().next()._1.get()));
                }});
        }
    }
}
我的hbse-site.xml文件如下所示:

<configuration>
  <property>
    <name>hbase.zookeeper.quorum</name>
    <value>hbase-3</value>
  </property>
  <property>
    <name>hbase.zookeeper.property.clientPort</name>
    <value>2181</value>
  </property>
  <property>
    <name>timeout</name>
    <value>5000</value>
  </property>
</configuration>

谢谢你的帮助和建议

这是一个常见问题。创建连接的成本可能会使您所做的实际工作相形见绌

在Cloud Bigtable中,您可以在配置设置中将
google.Bigtable.use.cached.data.channel.pool
设置为
true
。这将大大提高绩效。Cloud Bigtable最终为所有Cloud Bigtable实例使用一个HTTP/2端点


我不知道在HBase中有类似的构造,但一种方法是建议创建一个
连接的实现,该实现在封面下创建一个缓存的
连接。您必须为新类设置
hbase.client.connection.impl

很有趣,谢谢您的建议!在Bigtable中,我将在何处/如何设置此设置?就是这样吗?Connection btConn=BigtableConfiguration.connect(“项目ID”、“BT实例ID”);btConn.getConfiguration().set(“google.bigtable.use.cached.data.channel.pool”,“true”);我在Bigtable中尝试了这一点,方法是使用hbase-site.xml(并使用它来建立连接)和将其直接放入如下代码中:btConf.set(BigtableOptionsFactory.Bigtable_USE_CACHED_DATA_CHANNEL_POOL,“true”);(也尝试过。setBoolean();所有这些似乎都不会产生任何影响--每次都会尝试连接到服务器。可以有多个连接对象;底层的Netty通道对象更重要。理想情况下,您会在BigtableOptions打印输出中看到useCachedDataPool=true。不幸的是,BigtableOptions.toString()中存在错误不会打印出该值(将在1.3.1中修复)你可以使用这个方法:看看有多少连接是活动的。我会看看我能做些什么来提高这个特性的可用性。在1.3.1。@ vsyfff,如果你认为所罗门的答案是正确的,你应该考虑接受它来确认你的问题已经解决了。谢谢。我认为新的HBASE连接是很正常的。在每个mapPartition/foreachPartition中建立,因为RDD是按设计分发的,连接对象不能在不同的节点之间序列化。相反,如果您希望每个执行器只有一个HBase连接,并与该节点中执行的所有任务共享,则必须实现一种单例连接对象/po在foreachPartition中使用ol,但请注意某些HBase客户端API的线程安全限制、客户端级别的缓冲区大小以及在上一个任务完成后关闭连接。我不确定是否同意。事实上,这里需要注意的一点是,这种重新连接只发生在涉及hBaseContext.hbaseRDD()的操作中,在本例中,它是执行并行扫描所必需的。如果您对RDD执行hBaseContext.foreachPartition(),该RDD还将连接对象传递给每个执行器,则该连接似乎被每个执行器重复使用(至少我没有看到Spark日志条目显示每次都会重新禁用连接。hBaseContext.foreachPartition()没有将连接对象传递给执行器(TCP连接无法序列化)但是正在向他们广播HBaseConfiguration;它负责目标执行者与正确的RegionServer建立直接的hbase连接。当然,这是每个分区一次完成的,而不是所有行。请尝试从JavaRDD中删除Hbaseconnection?JavaRDD scanRDD=hBaseContext.hbaseRDD(TableName.valueOf(“FFUnits”);这样做也是一样的。这是我最初使用它的方式,但我添加了hbasconnection.getTable(…)以防万一,可能会以这种方式重用现有连接。也许你是对的,我们只是在查看日志报告,而不是实际的实现问题。如前所述,这只会发生在使用HBaseContext.HBaseRDD(…)通过扫描生成的HBaseRDD上。在HBase Spark软件包的其他功能中,如果需要与HBase群集保持经常联系,则不会报告多次重新连接。可能它们确实发生了,只是不会报告?
<configuration>
  <property>
    <name>hbase.zookeeper.quorum</name>
    <value>hbase-3</value>
  </property>
  <property>
    <name>hbase.zookeeper.property.clientPort</name>
    <value>2181</value>
  </property>
  <property>
    <name>timeout</name>
    <value>5000</value>
  </property>
</configuration>
Spark v 1.6.2
HBase 1.3.1
Spark-HBase 1.2.0-cdh5.14.0