1.DistributedCacha不能用了:
一开始以为是mapreduce的版本不对或者hadoop的版本跟公司的平台不兼容,后来发现是
公司给禁了。。
解决办法:每个mapper/reducer都读从hdfs上面读一遍文件,缺点显而易见;将文件读好,然后用conf.set() 放在configuration中,缺点:数据量大的话肯定会出问题。
2.排序慢。
需求:需求中的一部分,不仅要对key进行排序,还需要对value进行排序,还要遍历。
为了解决这个问题从头到尾大概花了一个月时间。
一开始,我的mr要处理的数据量并不是很大,那时候对数据的量级没有概念,想着偷懒(然后被leader批评了),用的是在reducer中储存完全部的数据,然后在reduce中对全量数据进行一次排序。缺点:显而易见,完全放弃了mapreduce的优点,放弃了reduce的流式处理的特点,本末倒置了。数据量稍微大一点(几百万)就处理的很慢。
后来改用二次排序。解决了燃眉之急,第一个需求算是写完了,大概能处理千万级别的数据了。因为是对hive表的每个列都需要排序,还自己实现了一个WritableComparable类来做这个。但是后面数据量到了亿级了,二次排序又不能满足需求了。慢在两点上:
1:在shuffle操作是,reduce要merge所有map的数据,这里花了很长的时间。
2:因为排了序,所有数据都要经过同一个reduce来处理,也就是说一个reduce要处理几亿的数据,造成了瓶颈。
现在用了TeraSort的思想,在排序进行之前现对数据进行采样(这里遇到了问题3),得到采样点之后,使用采样点对数据进行分区,在mapper中给每个输入数据打上PartitionIndex,利用partition将每个区域的分到不同的reducer中去(这里遇到了问题4),这样就利用了二次排序的优点,同时避免了一个reduce处理全部的数据,因为每个reducer中的数据是没有重叠的,按顺序排好就好了。
3.mapreduce自带的采样器采样效果很差。
一开始想着用mapreduce自带的采样器对hive表(实际上是orc文件)进行采样,如果需要100个分割点,我就采样10000次这样,按比例得到分割点。后来发现,采样的结果分布并不能(几乎是完全不能)反映orc文件里的数据分布。
原因:因为采样器在工作之前,需要指定采样比例、最大采样个数、最大采样分区数。而我写的部分是要满足小到几万,大到几百亿的,分区数量一个到几千个不等的hive表的需求的,这就导致了采样参数难以动态设置(实现进行几次查表什么的太慢了)。然后就导致了有的分区采样比例太高了,有的分区没采样到,同时也比较慢。
因为mr自带的采样器是在本地完成的!!!!特别慢!!
解决:新写了个mr过程专门进行采样。效果很好,又快,又好。
4.在partition的时候发现,有的数据倾斜特别严重。导致reduce速度又下来了。
在TeraSort的思想进行排序之后,发现大多数的列数据都能很快地搞定了,但是有些列就还是很慢。
然后打印了一些看,发现这些数据,几亿个数据,有百分之七八十是同一个值。也就是说,就算利用了teraSort思想,他们在分割区间的时候依然被分在了同一个区间里,也就是说,依然是一个reducer处理的几个亿的数据(其他的几十个reducer在旁边看着他死)。这么一来就肯定慢了。
解决:加入随机。就算是同一个值,加上随机数,随机分到不同的reducer里面去。
5.map、reduce之间的数据传输;reduce写数据太耗时了。
因为一开始设计的程序的两步走的,也就是说,需要第一个mr过程的reduce写出一堆的临时数据到hdfs上,再由第二个mr的mapper将这些数据读进去。这一来一回,几百个G的数据,当然慢了。
解决:优化程序结构,将两个mr过程优化为一个,利用mapper、reducer的cleanup写临时文件,再用setup来读的方法解决需求(导致了问题6)。
6.推断执行导致mapper或者reducer的cleanup写文件失败。
设置的是每个mapper或者reducer写出一个临时文件在hdfs上(并不是reducer的OutputFormat输出文件)。然后就遇到了匪夷所思的bug:有的mapper或reducer负责写的文件为空,并且有时出现有时不出现。
后来发现是mapreduce的推断执行导致了这个错误。mr在发现一个mapper或者一个reducer跑的比较慢的时候,会新开一个一模一样的进程(想着后来居上吧)。
这就导致了,其中某个进程先跑到了写临时文件的那一步,创建了那个文件并开始写,还没写完,后来居上的进程跑到写文件这一步了,发现,文件已经写好了,就不写了,或者报个错,或者直接跳过。反正机器认为这个进程跑完了。而这时候一开始写文件的那个进程并没有写完文件,它莫民奇妙地就被kill掉了。就导致了文件是空的。。
解决:把推断执行关掉,缺点,逃避;或者当一个进程发现文件存在的时候,再写个名称不同的文件,加个后缀什么的,再读的时候再处理。
解决:再文件里家TaskID去重
7.orc文件的问题
不知道为什么,OrcStruct可以被mapper读入,但是不能被传输给reducer,报错说是OrcStruct这个玩意没有实现序列化。。
7-1.Orc文件切分有下限(?)
为了快,要将mapper的maxsize设置的小一点,但是在遇到orc文件的时候,有时候设置的比较小了就会无效。。
8.hive表里的empty string。
看着跟null一样,其实不是null,null值检测的时候给它漏了。。
9.在java程序里进行hive表查询!
可以的!
10.hive表的表名和字段名不区分大小写,全部为小写。
是个坑,在找表的orc文件储存路径的时候吃了亏。
11.Hadoop的FileSystem用完不用关
12.分区表的分区字段在orc文件里是没有的!
13.如何根据不同的表来动态分配mapper个数和reducer个数呢?
想了个好办法
14.Reducer的cleanup写出hdfs文件的时候有时候会写出失败。
原因:未写完就告诉主进程我已经完事了,然后主进程可能就认为所有进程都已经完事了,就结束了(写文件的进程当然也被kill掉了)。
解决:再FileSystem写的时候,flush() 后面加一行 close()。这样就不会发生上述的情况了,就解决了问题