在最近的一个项目中有这样一个需求,我们的业务数据是存放在hbase中,一天大概新增五到六百万的,然后我这边需要做一件事是按小时把新增数据加载到impala中,并且数据需要按年月日三个字段分区。
起初想到的是直接在hive中建立一个表,然后在表上建立一个mapping映射到hbase中的表。但是考虑到分区,业务表中无法提供这些字段,所以另想它法。
后来想到的是用hbase中提供的TableMapper按时间截扫描(这里不用rowkey原因可以自己思考,时间截会出现的问题,业务那边已经处理),mapreduce任务定时每隔一小时执行一次,每次记录下扫描到的数据的最大和最小时间截。下次依据这个扫描最新数据,然后通过reduce把数据写到hdfs上,最后load到impala上。
按照上面的思路敲完代码测试的时候,在log中发现一个error,如下图
通过源码找到报错的地方
InetAddress regionAddress = isa.getAddress(); String regionLocation; try { regionLocation = reverseDNS(regionAddress); } catch (NamingException e) { LOG.warn("Cannot resolve the host name for " + regionAddress + " because of " + e); regionLocation = location.getHostname(); }
抛出异常的方法reverseDNS
private String reverseDNS(InetAddress ipAddress) throws NamingException { String hostName = this.reverseDNSCacheMap.get(ipAddress); if (hostName == null) { hostName = Strings.domainNamePointerToHostName(DNS.reverseDns(ipAddress, this.nameServer)); this.reverseDNSCacheMap.put(ipAddress, hostName); } return hostName; }
可见hostName的获取是与nameServer有关
this.nameServer = context.getConfiguration().get("hbase.nameserver.address", null);
而nameServer是从配置(hbase-site.xml)中读取的,hbase.nameserver.address从字面上看是名字服务器的地址,也就是域名服务器。
try { regionLocation = reverseDNS(regionAddress); } catch (NamingException e) { LOG.warn("Cannot resolve the host name for " + regionAddress + " because of " + e); regionLocation = location.getHostname(); }
在分析这里,首先根据region所在的regionserver的ip地址去域名服务器中找这个regionserver的主机名,而我们搭建本地集群一般不会去弄个域名服务器什么的,这里当然会找不到,然后才会去hosts文件获取regionserver的主机名。总之这里还是获取到了regionserver的主机名,没有获取到想要的主机域名,不影响mapreduce的执行。
只有在线上集群,我们可能会申请一个域名,然后为每个节点 的ip映射一个二级域名,然后在hbase-site.xml中配置上hbase.nameserver.address的值为一个域名服务器的ip(比如114.114.114.114)。
所以不想看到这个error:1、可以自己在一个节点上搭建一个域名服务器,然后再域名服务器的数据库中按hosts的配置添加映射;2、修改源码注释这行代码,覆盖到集群中