本地IDEA(Windows)访问ECS服务器HBase

添加Maven依赖

一般来说只要有hbase-clientJAR包就好,毕竟我们是客户端远程访问HBase。

<dependencies>
        <!-- https://mvnrepository.com/artifact/org.apache.hbase/hbase-client -->
        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-client</artifactId>
            <version>2.2.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.hbase/hbase-common -->
        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-common</artifactId>
            <version>2.2.2</version>
        </dependency>
</dependencies>

测试连接代码

运行后,如果存在student表,输出已存在,否则输出不存在。

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;

import java.io.IOException;

public class HBaseConnection {
    public static Configuration configuration;
    public static Connection connection;
    public static Admin admin;

    public static void init(){
        configuration = HBaseConfiguration.create();
        //以下xxx.xxx.xxx.xxx都是公网ip
        configuration.set("hbase.master","xxx.xxx.xxx.xxx:16000");
        configuration.set("hbase.zookeeper.quorum", "xxx.xxx.xxx.xxx");
        configuration.set("hbase.rootdir","hdfs://xxx.xxx.xxx:9000/hbase");
        configuration.set("hbase.zookeeper.property.clientPort","2181");
        try{
            connection = ConnectionFactory.createConnection(configuration);
            admin = connection.getAdmin();
        }catch (IOException e){
            e.printStackTrace();
        }
    }

    public static void close(){
        try{
            if(admin != null){
                admin.close();
            }
            if(null != connection){
                connection.close();
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }


    public static void main(String[] args) {
        init();
        System.out.println ("connected");
        String tableName = "student";
        if(admin != null) {
            try{
                if (admin.tableExists(TableName.valueOf(tableName)))
                //如果表已经存在
                {
                    System.out.println(tableName + "已存在");
                }
                else
                //如果表不存在
                {
                    System.out.println(tableName + "不存在");
                }
            }catch (IOException e){
                e.printStackTrace ();
            }
        }
        close();
    }
}

以下是遇到的几个问题以及完成本文题目所需的配置

有了本地IDEA访问HDFS的经验,我们可以知道我们从本地Windows要访问ECS服务器,那我们应该使用公网ip:端口的形式。

主机名映射配置

在我第一次启动程序后,我发现程序一直运行中,没有任何输出结果,一开始以为代码问题或是没连接上的问题。现在总结,其实这个时间是本地windows不断访问Zookeeper Server、HMaster、HRegionServer的过程,由于连接不上,会一直进行以下这个过程:申请继续访问,连接超时,结束会话。

在一段较长时间后,程序会报一些错误,大致如下,由于没有保存,只能在网站上把差不多错误的复制到这里。

如果觉得时间太长,可以设置访问连接时间,减小程序运行时间,更快debug。

Exception in thread "main" org.apache.hadoop.hbase.client.RetriesExhaustedException: Failed after attempts=16, exceptions:
Sun Dec 09 23:41:54 CST 2018, RpcRetryingCaller{globalStartTime=1544370111222, pause=100, maxAttempts=16}, org.apache.hadoop.hbase.MasterNotRunningException: java.net.ConnectException: Call to localhost/127.0.0.1:16000 failed on connection exception: org.apache.hbase.thirdparty.io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: localhost/127.0.0.1:16000
Sun Dec 09 23:41:54 CST 2018, RpcRetryingCaller{globalStartTime=1544370111222, pause=100, maxAttempts=16}, org.apache.hadoop.hbase.MasterNotRunningException: java.io.IOException: Call to localhost/127.0.0.1:16000 failed on local exception: org.apache.hadoop.hbase.ipc.FailedServerException: This server is in the failed servers list: localhost/127.0.0.1:16000
Sun Dec 09 23:41:54 CST 2018, RpcRetryingCaller{globalStartTime=1544370111222, pause=100, maxAttempts=16}, org.apache.hadoop.hbase.MasterNotRunningException: java.io.IOException: Call to localhost/127.0.0.1:16000 failed on local exception: org.apache.hadoop.hbase.ipc.FailedServerException: This server is in the failed servers list: localhost/127.0.0.1:16000
Sun Dec 09 23:41:54 CST 2018, RpcRetryingCaller{globalStartTime=1544370111222, pause=100, maxAttempts=16}, org.apache.hadoop.hbase.MasterNotRunningException: java.io.IOException: Call to localhost/127.0.0.1:16000 failed on local exception: org.apache.hadoop.hbase.ipc.FailedServerException: This server is in the failed servers list: localhost/127.0.0.1:16000

org.apache.hadoop.hbase.ipc.CallTimeoutException

Caused by: java.net.SocketTimeoutException: callTimeout=60000, callDuration=60304: row '11' on table 'dw_app' at region=dw_app,11,1537153390542.d1fe5dbbc180e3b62ed9634ce9b6fc02., hostname=xxxxxxxxxxxxxx.xxxx.com.cn,16020,1571111359242, seqNum=30134436
    at org.apache.hadoop.hbase.client.RpcRetryingCaller.callWithRetries(RpcRetryingCaller.java:159)
    at org.apache.hadoop.hbase.client.ResultBoundedCompletionService$QueueingFuture.run(ResultBoundedCompletionService.java:65)
    ... 3 more
Caused by: java.io.IOException: Call to xxxxxxxxxxxxxx.xxxx.com.cn/xx.xx.xx.xx:16020 failed on local exception: org.apache.hadoop.hbase.ipc.CallTimeoutException: Call id=5, waitTime=60001, operationTimeout=60000 expired.
    at org.apache.hadoop.hbase.ipc.AbstractRpcClient.wrapException(AbstractRpcClient.java:291)
    at org.apache.hadoop.hbase.ipc.RpcClientImpl.call(RpcClientImpl.java:1272)
    at org.apache.hadoop.hbase.ipc.AbstractRpcClient.callBlockingMethod(AbstractRpcClient.java:226)
    at org.apache.hadoop.hbase.ipc.AbstractRpcClient$BlockingRpcChannelImplementation.callBlockingMethod(AbstractRpcClient.java:331)
    at org.apache.hadoop.hbase.protobuf.generated.ClientProtos$ClientService$BlockingStub.scan(ClientProtos.java:34094)
    at org.apache.hadoop.hbase.client.ScannerCallable.call(ScannerCallable.java:219)
    at org.apache.hadoop.hbase.client.ScannerCallable.call(ScannerCallable.java:64)
    at org.apache.hadoop.hbase.client.RpcRetryingCaller.callWithoutRetries(RpcRetryingCaller.java:200)
    at org.apache.hadoop.hbase.client.ScannerCallableWithReplicas$RetryingRPC.call(ScannerCallableWithReplicas.java:360)
    at org.apache.hadoop.hbase.client.ScannerCallableWithReplicas$RetryingRPC.call(ScannerCallableWithReplicas.java:334)
    at org.apache.hadoop.hbase.client.RpcRetryingCaller.callWithRetries(RpcRetryingCaller.java:126)
    ... 4 more
Caused by: org.apache.hadoop.hbase.ipc.CallTimeoutException: Call id=5, waitTime=60001, operationTimeout=60000 expired.
    at org.apache.hadoop.hbase.ipc.Call.checkAndSetTimeout(Call.java:73)
    at org.apache.hadoop.hbase.ipc.RpcClientImpl.call(RpcClientImpl.java:1246)

搞明白以上的问题后,会对HBase有更深的了解。

我们一开始是访问了zk server,但后面访问Hmaster和regionserver可要注意,我们不是通过zk,然后让zk去访问以上两者。而是继续通过本地Windows去访问,那么问题来了。它怎么知道HMaster和regionserver的地址呢。尤其是,它们所在的是一个局域网,用的内网IP,而外面访问它们的时候,又需要公网IP。

当时想不通这个,在看了几篇博客后,了解到了主机名的重要性。公网和内网,通过主机名绑定到了一起。本地绑定主机名和公网IP,服务器绑定主机名和内网IP。这样本地得到内网服务器信息如主机名:端口后,就会根据自己本地的hosts去解析这个主机名的IP地址,得到公网IP,就会访问公网IP:端口,而服务器本身会将主机名解析为内网IP,进而绑定到相应的内网IP:端口。

解决方式

修改本地的C:\Windows\System32\drivers\etc下的hosts文件,添加主机名和公网ip。这个文件的修改需要权限,右键点击,安全性,编辑,将其设为所有用户可编辑。
这个hostname要和服务器的一致。

xxx.xxx.xxx.xxx bigdata

同理也要修改服务器的/etc/hosts,将主机名和内网IP添加上,一般来说ECS原本就有。

xxx.xxx.xxx.xxx bigdata  bigdata

对于hbase-site.xml文件也要进行相应的修改。把IP地址地方都改为主机名。

<configuration>
        <property>
                <name>hbase.rootdir</name>
                <value>hdfs://bigdata:9000/hbase</value>
        </property>
        <property>
                <name>hbase.cluster.distributed</name>
                <value>true</value>
        </property>
        <property> <!--  定义master的ip和端口  -->
                <name>hbase.master</name>
                <value>bigdata:16000</value>
        </property>
        <property>
                <name>hbase.zookeeper.quorum</name>
                <value>bigdata</value>
        </property>
        <property>
                <name>hbase.unsafe.stream.capability.enforce</name>
                <value>false</value>
        </property>
</configuration>

端口设置和安全组规则

在主机名配置好后,我还是连接失败,忘记了最致命的一点。阿里云ECS有安全组规则,所以是需要开放相应端口权限给外网访问的。

我的HBase是伪分布式的,但我这里ZK Server、HMaster和RegionServer其实都只设置占用一个端口。将zk设置为2181,HMaster设置为16000,RegionServer设置为16020。所以需要在阿里云安全组将这三个端口开放出去,如果设置很多个zkserver和regionserver的话,占用很多端口,那开放很多端口出去,应该也可以成功连接。

总结

一开始我是开放了2181端口、9000端口以及16000端口。但我还是没有意识到Regionserver也需要开放,也就是我忘记了客户端是如何与HBase交互的。

客户端在访问zkserver后,取得元数据信息后,去寻找数据所在的Regionserver,也就是获取到相应的主机名:端口后,要通过本地主机名解析为公网IP:端口进行访问相应的Regionserver,最后得到数据。

如果有多个zkServer和regionserver那需要开放多个端口给本地访问。

可以参考

https://blog.csdn.net/qq_36448587/article/details/105148063

https://blog.csdn.net/eff666/article/details/51997997?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.nonecase

访问腾讯云HBase

posted @ 2020-07-07 17:51  Tanglement  阅读(795)  评论(0编辑  收藏  举报