本地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那需要开放多个端口给本地访问。
可以参考