您的位置:首页 > 其它

MapReduce(Hbase)学习笔记---初学遇到的问题以及解决办法

2017-03-07 00:00 681 查看
摘要: 依旧是工作驱动,自学MapReduce,从官网例程到自身业务逻辑,过程中遇到很多问题,比如:如何运行MapReduce;运行MapReduce时类找不到等等,通过各种渠道找答案,经过无数次的测试,最后总算坎坎坷坷的交差了。现分享一些学习笔记,希望跟我一样自学的人可以少走弯路。

作为一个新手,此篇文章就不对MapReduce的原理做过多介绍了(我也不会。。。),只是从使用的层面,跟大家分享一下我在学习中遇到的问题以及解决办法,希望对像我一样的新手有帮助。我的工作中需要MapReduce对Hbase进行读写,以下问题都是此类问题,并不涉及HDFS文件的读写问题。

学习一门技术,必然要到官网找例程。
http://abloz.com/hbase/book.html#perf.reading
此链接是国人对Hbase使用文档的翻译,从使用文档的目录中可以找到如下信息:



点开Hbase MapReduce示例可以看到,由于我需要对Hbase进行读写,所以我直接使用了读/写示例。在Idea中新建Maven项目,名字随便起,我的项目名为MapReduceExample,然后将创建MapReduceExample类,将示例代码复制进去,注意!示例中有三处需要修改的地方

a.



括号里的参数修改成自己的类名,比如我的就是MapReduceExample。

b.


sourceTable是需要读的表名称,String类型,同样修改成自己的,比如我的就是“test1”。

c.


targetTable是需要写的表名称,String类型,同样修改成自己的,比如我的就是“test2”。

修改完成后,我就开始了漫长的爬坑之路,说多了都是泪啊。。。好了,不多比比,直接上问题:

1.TableMapper的jar包问题

既是新建的Maven项目,必然需要导入相关jar包,示例中没有import代码部分,作为一个新手,只能上网搜,由于是对Hbase进行读写,则必然用到Put,搜索Put所在jar包,结果是hbase-client.jar,将此jar包添加到pom文件中,发现已经解决了大部分的依赖问题,就剩下TableMapper的依赖了,原以为很简单就能搜到,结果花了我半天时间都没有搜到(生无可恋),实在没有办法,只能从阿里的Maven私服上将Hbase相关jar包全部下载下来,使用反编译工具,查看TableMapper所在位置。最后终于让我找到了,TableMapper所属jar包是hbase-server.jar,赶紧将其添加到pom文件中,依赖问题解决~呼~~

2.打包问题

依赖问题解决后就是打包运行了,突然发现自己不会运行MapReduce任务。。。这就尴尬了。于是又去请教度娘,度娘的回答多是在服务器上使用开发工具直接运行,然而我是本地机器开发,打成jar包后在服务器上运行,虽然搜索过程略有坎坷,但还是让我发现了一条命令:hadoop jar jar包名 类名。死马当活马医,放到服务器上试了一下,发现确实可以运行,但是……没错,运行报错了!



错误信息显示有个类没有找到,猜测可能是MapReduce运行还需要其他jar包,继续百度搜索该类所在的jar包:hbase-hadoop-compat.jar,添加到pom文件中,重新打包(这里需要注意下,一定要重新打包,仅仅rebuild是无效的,别问我是怎么知道的),放到服务器上执行运行命令,又报错了。。。



又是类找不到。。。不过好消息是上一个错误没有了,说明解决方式是对的,没得说,继续搜索该类所在jar包:metrics-core.jar,继续添加到pom文件中,重新打包上传执行运行命令,皇天不负有心人,终于成功运行了!



此截图只截取了map过程,实际日志信息有很多,后边详细探讨MapReduce的日志问题。前边说过了,此次MapReduce只是测试官网的示例:把test1表的数据复制到test2表中。注意:这两张表一定要提前创建好,且结构要一致(列族名一致),否则MR(以下均用MR代替MapReduce)运行报错,最终效果如下:

下图是MR执行之前的表信息,可以看到,test1里有4行记录,test2里是空:



下图是MR执行之后的表信息,可以看到,test2中已经有了记录,且与test1的记录一致。



截止到此处,测试用例已经跑起来了,剩下的就是自由发挥了。总结下,简单的运行Hbase读写示例只需4个jar包:hbase-client、hbase-server、hbase-hadoop-compat、metrics-core。如果项目使用了Maven,将配置文件中的镜像仓库路径改成阿里或开源中国的私服,下载会快一些。如果想直接下载jar包,手动导入Maven本地仓库,可以直接打开阿里或开源中国的私服下载,如果不知道jar包目录结构,那向大家推荐个jar包下载网址:http://mvnrepository.com/,提供搜索功能,且各个版本都有。

3.多表读取的问题

由于业务要求,我需要从两张表中读取数据,官方文档中7.3提供了思路:



然而这又是个坑。。。也许是我jar包引入版本与官方文档不匹配,在我的程序中,HTable有很多构造方法,唯独没有只传入表名的构造方法(有种被人戏耍的感觉),没办法,依旧询问度娘如何使用java访问Hbase中的表,多次测试后,如下代码是可以正常访问的:

@Override
public void setup(Context context) throws IOException, InterruptedException {
Configuration config = HBaseConfiguration.create();
//设置Hbase的zookeeper 端口
config.set("hbase.zookeeper.property.clientPort", "2181");
//设置Hbase的zookeeper ip
config.set("hbase.zookeeper.quorum", "localhost");
//创建HTable,配置文件+表名
HTable keywordTable = new HTable(config,"keyword_info");
Scan scan = new Scan();
ResultScanner rs = keywordTable.getScanner(scan);
List<String> keywords = new ArrayList<>();
try {
//开始按行读取数据
for (Result r = rs.next(); r != null; r = rs.next()) {
if(null == r.getValue(Bytes.toBytes("keywordInfo"),Bytes.toBytes("keyword"))){
break;
}
//getValue(列族名,字段名),参数类型为字节数组
String keyword = new String(r.getValue(Bytes.toBytes("keywordInfo"),Bytes.toBytes("keyword")));
keywords.add(keyword);
}
} finally {
rs.close();
}
keywordTable.close();
}

在MapReduce的执行流程中,会先执行setup方法,然后再执行map和reduce方法,因此将所需要的表和数据声明为全局变量,在setup方法中赋值,map方法中就可以使用该表的数据。

此外,多表读取还有另外一种实现方式,官方文档没有进行说明,我也是百度才查到的,但此种方式有很大局限性:只能顺序读取,即不能同时读取多张表的数据,只有按行读完其中一张表,才会继续按行读下一张表。

查看TableMapReduceUtil.initTableMapperJob的源码,可以发现,该方法支持传入List<Scan>,因此只需在initTableMapperJob之前创建多个Scan,然后调用Scan的setAttribute方法传入表名即可,代码如下:

List<Scan> scanList = new ArrayList<>();

Scan scan1 = new Scan();
scan1.setCaching(500);
scan1.setCacheBlocks(false);
scan1.setAttribute(Scan.SCAN_ATTRIBUTES_TABLE_NAME, Bytes.toBytes("test1"));

Scan scan2 = new Scan();
scan2.setCaching(500);
scan2.setCacheBlocks(false);
scan2.setAttribute(Scan.SCAN_ATTRIBUTES_TABLE_NAME, Bytes.toBytes("test2"));

scanList.add(scan1);
scanList.add(scan2);

TableMapReduceUtil.initTableMapperJob(
scanList,
MyMapper.class,
null,
null,
job);

上面说的局限性只是针对我本身的业务而言,我读A表数据的同时,需要B表的全部数据做辅助,因此第二种方式并不适合我,但这也不能说是MapReduce的局限,MapReduce还是很强大的。

4.多行输出问题

还是业务原因,我读取一行数据进行处理,有时会返回多条数据,然而MapReduce中的context.write()方法只能输出一行记录,这就比较尴尬了,询问度娘也并没有给我很好的答案。最终的办法是:既然context.write()方法只能输出一行记录,那么我使用for循环多次调用不就可以了么?事实证明,我是对的。刚开始由于惯性思维,以为map方法中调用context.write()就会结束,然而并不是,context.write()方法是可以多次调用的,即实现输出多行记录。

5.MapReduce日志问题

在MapReduce处理数据时,我们希望可以看到处理过程中的某些信息,可以到"hadoop安装目录/logs/userlogs/"下查看,根据job后边的编号就可以找到本次MapReduce的日志,比如我本次的编号如截图:job_1487574841800_0002,在该目录下就会有一个application_1487574841800_0002,如下图:



当然了,前提是处理过程中有日志输出。

6.虚拟内存溢出问题

当所需读取的数据量很大时,或者打包的程序比较大时,MapReduece启动会报虚拟内存溢出错误,如下:

Container[pid=41884,containerID=container_1405950053048_0016_01_000284] is running beyond virtual memory limits. Current usage: 314.6 MB of 1.0 GB physical memory used; 3.2 GB of 2.0 GB virtual memory used. Killing container.

即程序运行所需的虚拟内存超出了容器默认的虚拟内存,具体原理可阅读下面的链接文章:
http://www.aboutyun.com/thread-11353-1-1.html
我的修改方法是将map的内存设置变大,问题解决。

config.setInt("mapreduce.map.memory.mb",2048);

7.预测执行问题

由于业务需要,我的MapReduce程序中使用了Socket远程通信,当数据量增加到10W的时候,Socket通信出现卡死现象,即某次通信过程中丢失信息,导致无法关闭连接,MapReduce任务卡死。

MapReduce有预测执行机制,又叫推测执行机制,具体机制原理可阅读下面的链接文章:
http://blog.csdn.net/beliefer/article/details/51249119 http://blog.csdn.net/beliefer/article/details/51251757
MapReduce默认开启预测执行,不过好在这个预测执行是可以关掉的:

config.setBoolean("mapred.map.tasks.speculative.execution ",false);

8.HRegionServer关闭问题(目前未解决)

当数据量增加到1000W的时候,Hbase的HRegionServer总会莫名其妙的死掉,查看日志的错误信息是Socket超时,经过多方查找也不知如何解决,重启Hbase倒是可以让MapReduce继续运行,但这种方法无异于饮鸩止渴,无奈最终上报领导。

总结:

问题1-5是代码问题,很容易解决,至于后面的6、7、8则是调优问题,我认为这种问题没个三五年的调优经验是没办法解决的。此篇文章主要是分享下我在初次学习MapReduce时的教训,希望能够让初学者少走一些弯路。感谢在本博客中引用的各位大神的文章,让我学到了很多,谢谢大神们。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  MapReduce HBase
相关文章推荐