﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-SIMONE-随笔分类-hadoop</title><link>http://www.blogjava.net/wangxinsh55/category/54532.html</link><description /><language>zh-cn</language><lastBuildDate>Mon, 02 Mar 2015 13:45:56 GMT</lastBuildDate><pubDate>Mon, 02 Mar 2015 13:45:56 GMT</pubDate><ttl>60</ttl><item><title>Storm集成Kafka编程模型</title><link>http://www.blogjava.net/wangxinsh55/archive/2015/03/01/423114.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Sun, 01 Mar 2015 07:47:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2015/03/01/423114.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/423114.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2015/03/01/423114.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/423114.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/423114.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 转载自http://www.cnblogs.com/tovin/p/3974417.html本文主要介绍如何在Storm编程实现与Kafka的集成 　　一、实现模型 　　　数据流程： 　　　　1、Kafka Producter生成topic1主题的消息　 　　　　2、Storm中有个Topology，包含了KafkaSpout、SenqueceBolt、KafkaBolt三个组件。其中KafkaS...&nbsp;&nbsp;<a href='http://www.blogjava.net/wangxinsh55/archive/2015/03/01/423114.html'>阅读全文</a><img src ="http://www.blogjava.net/wangxinsh55/aggbug/423114.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2015-03-01 15:47 <a href="http://www.blogjava.net/wangxinsh55/archive/2015/03/01/423114.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hadoop作业调优参数整理及原理</title><link>http://www.blogjava.net/wangxinsh55/archive/2014/11/19/420297.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Wed, 19 Nov 2014 05:42:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2014/11/19/420297.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/420297.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2014/11/19/420297.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/420297.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/420297.html</trackback:ping><description><![CDATA[<div>http://www.linuxidc.com/Linux/2012-01/51615.htm</div><br /><div><h2><span>1 </span>Map side tuning <span style="font-family: 宋体">参数</span> </h2> <h3><span>1.1 </span>MapTask <span style="font-family: 宋体">运行内部原理</span> </h3> <p><img alt="" src="http://www.linuxidc.com/upload/2012_01/120116103468161.gif" /> <br /></p> <p style="text-indent: 21pt; line-height: normal;" align="left"><span style="color: black; font-family: 宋体">当map task 开始运算，并产生中间数据时，其产生的中间结果并非直接就简单的写入磁盘。这中间的过程比较复杂，并且利用到了内存buffer 来进行已经产生的部分结果的缓存，并在内存buffer 中进行一些预排序来优化整个map 的性能。如上图所示，每一个map 都会对应存在一个内存buffer （MapOutputBuffer ，即上图的buffer in memory ），map 会将已经产生的部分结果先写入到该buffer 中，这个buffer 默认是100MB 大小，但是这个大小是可以根据job 提交时的参数设定来调整的，该参数即为：</span> <strong><span style="color: red; font-family: 宋体">io.sort.mb</span> </strong><span style="color: black; font-family: 宋体">。当map 的产生数据非常大时，并且把io.sort.mb 调大，那么map 在整个计算过程中spill 的次数就势必会降低，map task 对磁盘的操作就会变少，如果map tasks 的瓶颈在磁盘上，这样调整就会大大提高map 的计算性能。map 做sort 和spill 的内存结构如下如所示：</span> </p> <p style="line-height: normal;" align="left"><span style="color: black; font-family: 宋体"><img alt="" src="http://www.linuxidc.com/upload/2012_01/120116103468162.gif" height="404" width="575" /> <br /></span></p> <p style="text-indent: 21pt; line-height: normal;" align="left"><span style="color: black; font-family: 宋体">map</span> <span style="color: black; font-family: 宋体">在运行过程中，不停的向该buffer 中写入已有的计算结果，但是该buffer 并不一定能将全部的map 输出缓存下来，当map 输出超出一定阈值（比如100M ），那么map 就必须将该buffer 中的数据写入到磁盘中去，这个过程在mapreduce 中叫做spill 。map 并不是要等到将该buffer 全部写满时才进行spill ，因为如果全部写满了再去写spill ，势必会造成map 的计算部分等待buffer 释放空间的情况。所以，map 其实是当buffer 被写满到一定程度（比如80% ）时，就开始进行spill 。这个阈值也是由一个job 的配置参数来控制，即</span> <strong><span style="color: red; font-family: 宋体">io.sort.spill.percent</span> </strong><span style="color: black; font-family: 宋体">，默认为0.80 或80% 。这个参数同样也是影响spill 频繁程度，进而影响map task 运行周期对磁盘的读写频率的。但非特殊情况下，通常不需要人为的调整。调整io.sort.mb 对用户来说更加方便。</span> </p> <p style="text-indent: 21pt; line-height: normal;" align="left"><span style="color: black; font-family: 宋体">当map task 的计算部分全部完成后，如果map 有输出，就会生成一个或者多个spill 文件，这些文件就是map 的输出结果。map 在正常退出之前，需要将这些spill 合并（merge ）成一个，所以map 在结束之前还有一个merge 的过程。merge 的过程中，有一个参数可以调整这个过程的行为，该参数为：</span> <strong><span style="color: red; font-family: 宋体">io.sort.factor</span> </strong><span style="color: black; font-family: 宋体">。该参数默认为10 。它表示当merge spill 文件时，最多能有多少并行的stream 向merge 文件中写入。比如如果map 产生的数据非常的大，产生的spill 文件大于10 ，而io.sort.factor 使用的是默认的10 ，那么当map 计算完成做merge 时，就没有办法一次将所有的spill 文件merge 成一个，而是会分多次，每次最多10 个stream 。这也就是说，当map 的中间结果非常大，调大io.sort.factor ，有利于减少merge 次数，进而减少map 对磁盘的读写频率，有可能达到优化作业的目的。</span> </p> <p style="text-indent: 21pt; line-height: normal;" align="left"><span style="color: black; font-family: 宋体">当job 指定了combiner 的时候，我们都知道map 介绍后会在map 端根据combiner 定义的函数将map 结果进行合并。运行combiner 函数的时机有可能会是merge 完成之前，或者之后，这个时机可以由一个参数控制，即</span> <strong><span style="color: red; font-family: 宋体">min.num.spill.for.combine</span> </strong><span style="color: black; font-family: 宋体">（default 3 ），当job 中设定了combiner ，并且spill 数最少有3 个的时候，那么combiner 函数就会在merge 产生结果文件之前运行。通过这样的方式，就可以在spill 非常多需要merge ，并且很多数据需要做conbine 的时候，减少写入到磁盘文件的数据数量，同样是为了减少对磁盘的读写频率，有可能达到优化作业的目的。</span> </p> <p style="text-indent: 21pt; line-height: normal;" align="left"><span style="color: black; font-family: 宋体">减少中间结果读写进出磁盘的方法不止这些，还有就是压缩。也就是说map 的中间，无论是spill 的时候，还是最后merge 产生的结果文件，都是可以压缩的。压缩的好处在于，通过压缩减少写入读出磁盘的数据量。对中间结果非常大，磁盘速度成为map 执行瓶颈的job ，尤其有用。控制map 中间结果是否使用压缩的参数为：</span> <strong><span style="color: red; font-family: 宋体">mapred.compress.map.output</span> </strong><span style="color: black; font-family: 宋体">(true/false)</span> <span style="color: black; font-family: 宋体">。将这个参数设置为true 时，那么map 在写中间结果时，就会将数据压缩后再写入磁盘，读结果时也会采用先解压后读取数据。这样做的后果就是：写入磁盘的中间结果数据量会变少，但是cpu 会消耗一些用来压缩和解压。所以这种方式通常适合job 中间结果非常大，瓶颈不在cpu ，而是在磁盘的读写的情况。说的直白一些就是用cpu 换IO 。根据观察，通常大部分的作业cpu 都不是瓶颈，除非运算逻辑异常复杂。所以对中间结果采用压缩通常来说是有收益的。以下是一个wordcount 中间结果采用压缩和不采用压缩产生的map 中间结果本地磁盘读写的数据量对比：</span> </p> <p style="line-height: normal;" align="left"><strong><span style="color: black; font-family: 宋体">map</span> </strong><strong><span style="color: black; font-family: 宋体">中间结果不压缩：</span> </strong></p> <p style="line-height: normal;" align="left"><span style="color: black; font-family: 宋体"><img alt="" src="http://www.linuxidc.com/upload/2012_01/120116103468163.gif" /> <br /></span></p> <p style="line-height: normal;" align="left"><strong><span style="color: black; font-family: 宋体">map</span> </strong><strong><span style="color: black; font-family: 宋体">中间结果压缩：</span> </strong></p> <p style="line-height: normal;" align="left"><strong><span style="color: black; font-family: 宋体"><img alt="" src="http://www.linuxidc.com/upload/2012_01/120116103468164.gif" /> <br /></span></strong></p> <p style="text-indent: 21pt; line-height: normal;" align="left"><span style="color: black; font-family: 宋体">可以看出，同样的job ，同样的数据，在采用压缩的情况下，map 中间结果能缩小将近10 倍，如果map 的瓶颈在磁盘，那么job 的性能提升将会非常可观。</span> </p> <p style="text-indent: 21pt; line-height: normal;" align="left"><span style="color: black; font-family: 宋体">当采用map 中间结果压缩的情况下，用户还可以选择压缩时���用哪种压缩格式进行压缩，现在<a href="http://www.linuxidc.com/topicnews.aspx?tid=13" target="_blank" title="Hadoop">Hadoop</a> 支持的压缩格式有：</span> GzipCodec <span style="font-family: 宋体">，</span> LzoCodec <span style="font-family: 宋体">，</span> BZip2Codec <span style="font-family: 宋体">，</span> LzmaCodec <span style="font-family: 宋体">等压缩格式。通常来说，想要达到比较平衡的</span> cpu <span style="font-family: 宋体">和磁盘压缩比，</span> LzoCodec <span style="font-family: 宋体">比较适合。但也要取决于</span> job <span style="font-family: 宋体">的具体情况。用户若想要自行选择中间结果的压缩算法，可以设置配置参数：</span> <strong><span style="color: red">mapred.map.output.compression.codec</span> </strong>=org.apache.hadoop.io.compress.DefaultCodec <span style="font-family: 宋体">或者其他用户自行选择的压缩方式。</span> </p></div><br /><div><h3><span>1.2 </span>Map side <span style="font-family: 宋体">相关参数调优</span> </h3> <table style="border-right: medium none; border-top: medium none; border-left: medium none; border-bottom: medium none; border-collapse: collapse" border="1" cellpadding="0" cellspacing="0"> <tbody> <tr> <td style="border-right: black 1pt solid; padding-right: 5.4pt; border-top: black 1pt solid; padding-left: 5.4pt; background: #c4bc96; padding-bottom: 0cm; border-left: black 1pt solid; width: 175.3pt; padding-top: 0cm; border-bottom: black 1pt solid" valign="top" width="234"> <p style="line-height: normal"><strong><span style="font-family: 宋体">选项</span> </strong></p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; background: #c4bc96; padding-bottom: 0cm; width: 73.8pt; padding-top: 0cm" valign="top" width="98"> <p style="line-height: normal"><strong><span style="font-family: 宋体">类型</span> </strong></p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; background: #c4bc96; padding-bottom: 0cm; width: 111.4pt; padding-top: 0cm" valign="top" width="149"> <p style="line-height: normal"><strong><span style="font-family: 宋体">默认值</span> </strong></p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; background: #c4bc96; padding-bottom: 0cm; width: 65.6pt; padding-top: 0cm" valign="top" width="87"> <p style="line-height: normal"><strong><span style="font-family: 宋体">描述</span> </strong></p></td></tr> <tr> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 175.3pt; padding-top: 0cm" valign="top" width="234"> <p style="line-height: normal">io.sort.mb </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 73.8pt; padding-top: 0cm" valign="top" width="98"> <p style="line-height: normal">int </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 111.4pt; padding-top: 0cm" valign="top" width="149"> <p style="line-height: normal">100 </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 65.6pt; padding-top: 0cm" valign="top" width="87"> <p style="line-height: normal"><span style="font-family: 宋体">缓存</span> map <span style="font-family: 宋体">中间结果的</span> buffer <span style="font-family: 宋体">大小</span> (in MB) </p></td></tr> <tr> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 175.3pt; padding-top: 0cm" valign="top" width="234"> <p style="line-height: normal">io.sort.record.percent </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 73.8pt; padding-top: 0cm" valign="top" width="98"> <p style="line-height: normal">float </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 111.4pt; padding-top: 0cm" valign="top" width="149"> <p style="line-height: normal">0.05 </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 65.6pt; padding-top: 0cm" valign="top" width="87"> <p style="line-height: normal">io.sort.mb <span style="font-family: 宋体">中用来保存</span> map output <span style="font-family: 宋体">记录边界的百分比，其他缓存用来保存数据</span> </p></td></tr> <tr> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 175.3pt; padding-top: 0cm" valign="top" width="234"> <p style="line-height: normal">io.sort.spill.percent </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 73.8pt; padding-top: 0cm" valign="top" width="98"> <p style="line-height: normal">float </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 111.4pt; padding-top: 0cm" valign="top" width="149"> <p style="line-height: normal">0.80 </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 65.6pt; padding-top: 0cm" valign="top" width="87"> <p style="line-height: normal">map <span style="font-family: 宋体">开始做</span> spill <span style="font-family: 宋体">操作的阈值</span> </p></td></tr> <tr> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 175.3pt; padding-top: 0cm" valign="top" width="234"> <p style="line-height: normal">io.sort.factor </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 73.8pt; padding-top: 0cm" valign="top" width="98"> <p style="line-height: normal">int </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 111.4pt; padding-top: 0cm" valign="top" width="149"> <p style="line-height: normal">10 </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 65.6pt; padding-top: 0cm" valign="top" width="87"> <p style="line-height: normal"><span style="font-family: 宋体">做</span> merge <span style="font-family: 宋体">操作时同时操作的</span> stream <span style="font-family: 宋体">数上限。</span> </p></td></tr> <tr> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 175.3pt; padding-top: 0cm" valign="top" width="234"> <p style="line-height: normal">min.num.spill.for.combine </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 73.8pt; padding-top: 0cm" valign="top" width="98"> <p style="line-height: normal">int </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 111.4pt; padding-top: 0cm" valign="top" width="149"> <p style="line-height: normal">3 </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 65.6pt; padding-top: 0cm" valign="top" width="87"> <p style="line-height: normal">combiner <span style="font-family: 宋体">函数运行的最小</span> spill <span style="font-family: 宋体">数</span> </p></td></tr> <tr> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 175.3pt; padding-top: 0cm" valign="top" width="234"> <p style="line-height: normal">mapred.compress.map.output </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 73.8pt; padding-top: 0cm" valign="top" width="98"> <p style="line-height: normal">boolean </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 111.4pt; padding-top: 0cm" valign="top" width="149"> <p style="line-height: normal">false </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 65.6pt; padding-top: 0cm" valign="top" width="87"> <p style="line-height: normal">map <span style="font-family: 宋体">中间结果是否采用压缩</span> </p></td></tr> <tr> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 175.3pt; padding-top: 0cm" valign="top" width="234"> <p style="line-height: normal">mapred.map.output.compression.codec </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 73.8pt; padding-top: 0cm" valign="top" width="98"> <p style="line-height: normal">class name </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 111.4pt; padding-top: 0cm" valign="top" width="149"> <p style="line-height: normal;" align="left">org.apache.<a href="http://www.linuxidc.com/topicnews.aspx?tid=13" target="_blank" title="Hadoop">Hadoop</a>.io. </p> <p style="line-height: normal">compress.DefaultCodec </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 65.6pt; padding-top: 0cm" valign="top" width="87"> <p style="line-height: normal">map <span style="font-family: 宋体">中间结果的压缩格式</span> </p></td></tr></tbody></table> <p>&nbsp; </p> <h2><span>2 </span>Reduce side tuning <span style="font-family: 宋体">参数</span> </h2> <h3><span>2.1 </span>ReduceTask <span style="font-family: 宋体">运行内部原理</span> </h3> <p><img alt="" src="http://www.linuxidc.com/upload/2012_01/120116103478481.gif" /> <br /></p> <p style="text-indent: 21pt">reduce <span style="font-family: 宋体">的运行是分成三个阶段的。分别为</span> copy-&gt;sort-&gt;reduce <span style="font-family: 宋体">。由于</span> job <span style="font-family: 宋体">的每一个</span> map <span style="font-family: 宋体">都会根据</span> reduce(n) <span style="font-family: 宋体">数将数据分成</span> map <span style="font-family: 宋体">输出结果分成</span> n <span style="font-family: 宋体">个</span> partition <span style="font-family: 宋体">，所以</span> map <span style="font-family: 宋体">的中间结果中是有可能包含每一个</span> reduce <span style="font-family: 宋体">需要处理的部分数据的。所以，为了优化</span> reduce <span style="font-family: 宋体">的执行时间，</span> hadoop <span style="font-family: 宋体">中是等</span> job <span style="font-family: 宋体">的第一个</span> map <span style="font-family: 宋体">结束后，所有的</span> reduce <span style="font-family: 宋体">就开始尝试从完成的</span> map <span style="font-family: 宋体">中下载该</span> reduce <span style="font-family: 宋体">对应的</span> partition <span style="font-family: 宋体">部分数据。这个过程就是通常所说的</span> shuffle <span style="font-family: 宋体">，也就是</span> copy <span style="font-family: 宋体">过程。</span> </p> <p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Reduce task</span> <span style="font-family: 宋体">在做</span> shuffle <span style="font-family: 宋体">时，实际上就是从不同的已经完成的</span> map <span style="font-family: 宋体">上去下载属于自己这个</span> reduce <span style="font-family: 宋体">的部分数据，由于</span> map <span style="font-family: 宋体">通常有许多个，所以对一个</span> reduce <span style="font-family: 宋体">来说，下载也可以是并行的从多个</span> map <span style="font-family: 宋体">下载，这个并行度是可以调整的，调整参数为：</span> <strong><span style="color: red">mapred.reduce.parallel.copies</span> </strong><span style="font-family: 宋体">（</span> default 5 <span style="font-family: 宋体">）。默认情况下，每个只会有</span> 5 <span style="font-family: 宋体">个并行的下载线程在从</span> map <span style="font-family: 宋体">下数据，如果一个时间段内</span> job <span style="font-family: 宋体">完成的</span> map <span style="font-family: 宋体">有</span> 100 <span style="font-family: 宋体">个或者更多，那么</span> reduce <span style="font-family: 宋体">也最多只能同时下载</span> 5 <span style="font-family: 宋体">个</span> map <span style="font-family: 宋体">的数据，所以这个参数比较适合</span> map <span style="font-family: 宋体">很多并且完成的比较快的</span> job <span style="font-family: 宋体">的情况下调大，有利于</span> reduce <span style="font-family: 宋体">更快的获取属于自己部分的数据。</span> </p> <p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reduce</span> <span style="font-family: 宋体">的每一个下载线程在下载某个</span> map <span style="font-family: 宋体">数据的时候，有可能因为那个</span> map <span style="font-family: 宋体">中间结果所在机器发生错误，或者中间结果的文件丢失，或者网络瞬断等等情况，这样</span> reduce <span style="font-family: 宋体">的下载就有可能失败，所以</span> reduce <span style="font-family: 宋体">的下载线程并不会无休止的等待下去，当一定时间后下载仍然失败，那么下载线程就会放弃这次下载，并在随后尝试从另外的地方下载（因为这段时间</span> map <span style="font-family: 宋体">可能重跑）。所以</span> reduce <span style="font-family: 宋体">下载线程的这个最大的下载时间段是可以调整的，调整参数为：</span> <strong><span style="color: red">mapred.reduce.copy.backoff</span> </strong><span style="font-family: 宋体">（</span> default 300 <span style="font-family: 宋体">秒）。如果集群环境的网络本身是瓶颈，那么用户可以通过调大这个参数来避免</span> reduce <span style="font-family: 宋体">下载线程被误判为失败的情况。不过在网络环境比较好的情况下，没有必要调整。通常来说专业的集群网络不应该有太大问题，所以这个参数需要调整的情况不多。</span> </p> <p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Reduce</span> <span style="font-family: 宋体">将</span> map <span style="font-family: 宋体">结果下载到本地时，同样也是需要进行</span> merge <span style="font-family: 宋体">的，所以</span> io.sort.factor <span style="font-family: 宋体">的配置选项同样会影响</span> reduce <span style="font-family: 宋体">进行</span> merge <span style="font-family: 宋体">时的行为，该参数的详细介绍上文已经提到，当发现</span> reduce <span style="font-family: 宋体">在</span> shuffle <span style="font-family: 宋体">阶段</span> iowait <span style="font-family: 宋体">非常的高的时候，就有可能通过调大这个参数来加大一次</span> merge <span style="font-family: 宋体">时的并发吞吐，优化</span> reduce <span style="font-family: 宋体">效率。</span> </p> <p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Reduce</span> <span style="font-family: 宋体">在</span> shuffle <span style="font-family: 宋体">阶段对下载来的</span> map <span style="font-family: 宋体">数据，并不是立刻就写入磁盘的，而是会先缓存在内存中，然后当使用内存达到一定量的时候才刷入磁盘。这个内存大小的控制就不像</span> map <span style="font-family: 宋体">一样可以通过</span> io.sort.mb <span style="font-family: 宋体">来设定了，而是通过另外一个参数来设置：</span> <strong><span style="color: red">mapred.job.shuffle.input.buffer.percent </span></strong><span style="font-family: 宋体">（</span> default 0.7 <span style="font-family: 宋体">），这个参数其实是一个百分比，意思是说，</span> shuffile <span style="font-family: 宋体">在</span> reduce <span style="font-family: 宋体">内存中的数据最多使用内存量为：</span> 0.7 <span style="font-family: 宋体">&#215;</span> maxHeap of reduce task <span style="font-family: 宋体">。也就是说，如果该</span> reduce task <span style="font-family: 宋体">的最大</span> heap <span style="font-family: 宋体">使用量（通常通过</span> mapred.child.java.opts <span style="font-family: 宋体">来设置，比如设置为</span> -Xmx1024m <span style="font-family: 宋体">）的一定比例用来缓存数据。默认情况下，</span> reduce <span style="font-family: 宋体">会使用其</span> heapsize <span style="font-family: 宋体">的</span> 70% <span style="font-family: 宋体">来在内存中缓存数据。如果</span> reduce <span style="font-family: 宋体">的</span> heap <span style="font-family: 宋体">由于业务原因调整的比较大，相应的缓存大小也会变大，这也是为什么</span> reduce <span style="font-family: 宋体">用来做缓存的参数是一个百分比，而不是一个固定的值了。</span> </p> <p style="text-indent: 21.2pt"><span style="font-family: 宋体">假设</span> mapred.job.shuffle.input.buffer.percent <span style="font-family: 宋体">为</span> 0.7 <span style="font-family: 宋体">，</span> reduce task <span style="font-family: 宋体">的</span> max heapsize <span style="font-family: 宋体">为</span> 1G <span style="font-family: 宋体">，那么用来做下载数据缓存的内存就为大概</span> 700MB <span style="font-family: 宋体">左右，这</span> 700M <span style="font-family: 宋体">的内存，跟</span> map <span style="font-family: 宋体">端一样，也不是要等到全部写满才会往磁盘刷的，而是当这</span> 700M <span style="font-family: 宋体">中被使用到了一定的限度（通常是一个百分比），就会开始往磁盘刷。这个限度阈值也是可以通过</span> job <span style="font-family: 宋体">参数来设定的，设定参数为：</span> <strong><span style="color: red">mapred.job.shuffle.merge.percent</span> </strong><span style="font-family: 宋体">（</span> default 0.66 <span style="font-family: 宋体">）。如果下载速度很快，很容易就把内存缓存撑大，那么调整一下这个参数有可能会对</span> reduce <span style="font-family: 宋体">的性能有所帮助。</span> </p> <p style="text-indent: 21.2pt"><span style="font-family: 宋体">当</span> reduce <span style="font-family: 宋体">将所有的</span> map <span style="font-family: 宋体">上对应自己</span> partition <span style="font-family: 宋体">的数据下载完成后，就会开始真正的</span> reduce <span style="font-family: 宋体">计算阶段（中间有个</span> sort <span style="font-family: 宋体">阶段通常时间非常短，几秒钟就完成了，因为整个下载阶段就已经是边下载边</span> sort <span style="font-family: 宋体">，然后边</span> merge <span style="font-family: 宋体">的）。当</span> reduce task <span style="font-family: 宋体">真正进入</span> reduce <span style="font-family: 宋体">函数的计算阶段的时候，有一个参数也是可以调整</span> reduce <span style="font-family: 宋体">的计算行为。也就是：</span> <strong><span style="color: red">mapred.job.reduce.input.buffer.percent</span> </strong><span style="font-family: 宋体">（</span> default 0.0 <span style="font-family: 宋体">）。由于</span> reduce <span style="font-family: 宋体">计算时肯定也是需要消耗内存的，而在读取</span> reduce <span style="font-family: 宋体">需要的数据时，同样是需要内存作为</span> buffer <span style="font-family: 宋体">，这个参数是控制，需要多少的内存百分比来作为</span> reduce <span style="font-family: 宋体">读已经</span> sort <span style="font-family: 宋体">好的数据的</span> buffer <span style="font-family: 宋体">百分比。默认情况下为</span> 0 <span style="font-family: 宋体">，也就是说，默认情况下，</span> reduce <span style="font-family: 宋体">是全部从磁盘开始读处理数据。如果这个参数大于</span> 0 <span style="font-family: 宋体">，那么就会有一定量的数据被缓存在内存并输送给</span> reduce <span style="font-family: 宋体">，当</span> reduce <span style="font-family: 宋体">计算逻辑消耗内存很小时，可以分一部分内存用来缓存数据，反正</span> reduce <span style="font-family: 宋体">的内存闲着也是闲着。</span> </p> <h3><span>2.2 </span>Reduce side <span style="font-family: 宋体">相关参数调优</span> </h3> <table style="border-right: medium none; border-top: medium none; border-left: medium none; border-bottom: medium none; border-collapse: collapse" border="1" cellpadding="0" cellspacing="0"> <tbody> <tr> <td style="border-right: black 1pt solid; padding-right: 5.4pt; border-top: black 1pt solid; padding-left: 5.4pt; background: #c4bc96; padding-bottom: 0cm; border-left: black 1pt solid; width: 175.3pt; padding-top: 0cm; border-bottom: black 1pt solid" valign="top" width="234"> <p style="line-height: normal"><strong><span style="font-family: 宋体">选项</span> </strong></p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; background: #c4bc96; padding-bottom: 0cm; width: 42.75pt; padding-top: 0cm" valign="top" width="57"> <p style="line-height: normal"><strong><span style="font-family: 宋体">类型</span> </strong></p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; background: #c4bc96; padding-bottom: 0cm; width: 49.6pt; padding-top: 0cm" valign="top" width="66"> <p style="line-height: normal"><strong><span style="font-family: 宋体">默认值</span> </strong></p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; background: #c4bc96; padding-bottom: 0cm; width: 158.45pt; padding-top: 0cm" valign="top" width="211"> <p style="line-height: normal"><strong><span style="font-family: 宋体">描述</span> </strong></p></td></tr> <tr> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 175.3pt; padding-top: 0cm" valign="top" width="234"> <p style="line-height: normal">mapred.reduce.parallel.copies </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 42.75pt; padding-top: 0cm" valign="top" width="57"> <p style="line-height: normal">int </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 49.6pt; padding-top: 0cm" valign="top" width="66"> <p style="line-height: normal">5 </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 158.45pt; padding-top: 0cm" valign="top" width="211"> <p style="line-height: normal"><span style="font-family: 宋体">每个</span> reduce <span style="font-family: 宋体">并行下载</span> map <span style="font-family: 宋体">结果的最大线程数</span> </p></td></tr> <tr> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 175.3pt; padding-top: 0cm" valign="top" width="234"> <p style="line-height: normal">mapred.reduce.copy.backoff </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 42.75pt; padding-top: 0cm" valign="top" width="57"> <p style="line-height: normal">int </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 49.6pt; padding-top: 0cm" valign="top" width="66"> <p style="line-height: normal">300 </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 158.45pt; padding-top: 0cm" valign="top" width="211"> <p style="line-height: normal">reduce <span style="font-family: 宋体">下载线程最大等待时间（</span> in sec <span style="font-family: ��体">）</span> </p></td></tr> <tr> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 175.3pt; padding-top: 0cm" valign="top" width="234"> <p style="line-height: normal">io.sort.factor </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 42.75pt; padding-top: 0cm" valign="top" width="57"> <p style="line-height: normal">int </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 49.6pt; padding-top: 0cm" valign="top" width="66"> <p style="line-height: normal">10 </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 158.45pt; padding-top: 0cm" valign="top" width="211"> <p style="line-height: normal"><span style="font-family: 宋体">同上</span> </p></td></tr> <tr> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 175.3pt; padding-top: 0cm" valign="top" width="234"> <p style="line-height: normal">mapred.job.shuffle.input.buffer.percent </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 42.75pt; padding-top: 0cm" valign="top" width="57"> <p style="line-height: normal">float </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 49.6pt; padding-top: 0cm" valign="top" width="66"> <p style="line-height: normal">0.7 </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 158.45pt; padding-top: 0cm" valign="top" width="211"> <p style="line-height: normal"><span style="font-family: 宋体">用来缓存</span> shuffle <span style="font-family: 宋体">数据的</span> reduce task heap <span style="font-family: 宋体">百分比</span> </p></td></tr> <tr> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 175.3pt; padding-top: 0cm" valign="top" width="234"> <p style="line-height: normal">mapred.job.shuffle.merge.percent </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 42.75pt; padding-top: 0cm" valign="top" width="57"> <p style="line-height: normal">float </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 49.6pt; padding-top: 0cm" valign="top" width="66"> <p style="line-height: normal">0.66 </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 158.45pt; padding-top: 0cm" valign="top" width="211"> <p style="line-height: normal"><span style="font-family: 宋体">缓存的内存中多少百分比后开始做</span> merge <span style="font-family: 宋体">操作</span> </p></td></tr> <tr> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 175.3pt; padding-top: 0cm" valign="top" width="234"> <p style="line-height: normal">mapred.job.reduce.input.buffer.percent </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 42.75pt; padding-top: 0cm" valign="top" width="57"> <p style="line-height: normal">float </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 49.6pt; padding-top: 0cm" valign="top" width="66"> <p style="line-height: normal">0.0 </p></td> <td style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 0cm; width: 158.45pt; padding-top: 0cm" valign="top" width="211"> <p style="line-height: normal">sort <span style="font-family: 宋体">完成后</span> reduce <span style="font-family: 宋体">计算阶段用来缓存数据的百分比</span> </p></td></tr></tbody></table><a href="http://www.linuxidc.com" target="_blank"><img src="http://www.linuxidc.com/linuxfile/logo.gif" alt="linux" height="17" width="15" /></a><a href="http://www.linuxidc.com" target="_blank"></a></div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/420297.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2014-11-19 13:42 <a href="http://www.blogjava.net/wangxinsh55/archive/2014/11/19/420297.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>mapreduce job让一个文件只由一个map来处理</title><link>http://www.blogjava.net/wangxinsh55/archive/2014/09/16/417971.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Tue, 16 Sep 2014 01:28:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2014/09/16/417971.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/417971.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2014/09/16/417971.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/417971.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/417971.html</trackback:ping><description><![CDATA[<div><div> 						<p><div>http://www.rigongyizu.com/mapreduce-job-one-map-process-one-file/</div><br /></p><p>有一批数据用<a href="http://www.rigongyizu.com/tag/hadoop/" title="查看hadoop中的全部文章" target="_blank">hadoop</a> mapreduce job处理时，业务特点要求一个文件对应一个map来处理，如果两个或多个map处理了同一个文件，可能会有问题。开始想通过设置 dfs.blocksize 或者 mapreduce.input.file<a href="http://www.rigongyizu.com/tag/inputformat/" title="查看inputformat中的全部文章" target="_blank">inputformat</a>.split.minsize/maxsize 参数来控制map的个数，后来想到其实不用这么复杂，在自定义的InputFormat里面直接让文件不要进行split就可以了。</p> <div nogutter=""  "="" id="highlighter_665528"><div><div alt1"=""><table><tbody><tr><td><code>public</code> <code>class</code> <code>CustemDocInputFormat </code><code>extends</code> <code>TextInputFormat {</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td>&nbsp;</td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>@Override</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>public</code> <code>RecordReader&lt;LongWritable, Text&gt; createRecordReader(InputSplit split, TaskAttemptContext context) {</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>DocRecordReader reader = </code><code>null</code><code>;</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>try</code> <code>{</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>reader = </code><code>new</code> <code>DocRecordReader(); </code><code>// 自定义的reader</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>} </code><code>catch</code> <code>(IOException e) {</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>e.printStackTrace();</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>}</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>return</code> <code>reader;</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>}</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td>&nbsp;</td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>@Override</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>protected</code> <code>boolean</code> <code>isSplitable(JobContext context, Path file) {</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>return</code> <code>false</code><code>;</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>}</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>}</code></td></tr></tbody></table></div></div></div> <p>这样，输入文件有多少个，job就会启动多少个map了。</p>  <div wp_rp_plain"="" id="wp_rp_first"><div><h3>相关文章</h3><ul wp_rp"=""><li data-position="0" data-poid="in-1093" data-post-type="none"><small>2014年8月19日</small> <a href="http://www.rigongyizu.com/hadoop-one-map-process-one-directory/">Hadoop : 一个目录下的数据只由一个map处理</a></li><li data-position="1" data-poid="in-1074" data-post-type="none"><small>2014年6月27日</small> <a href="http://www.rigongyizu.com/hadoop-job-optimize-combinefileinputformat/">一个Hadoop程序的优化过程 &#8211; 根据文件实际大小实现CombineFileInputFormat</a></li><li data-position="2" data-poid="in-818" data-post-type="none"><small>2013年9月23日</small> <a href="http://www.rigongyizu.com/use-multiinputformat-read-different-files-in-one-job/">hadoop用MultipleInputs/MultiInputFormat实现一个mapreduce job中读取不同格式的文件</a></li><li data-position="3" data-poid="in-289" data-post-type="none"><small>2012年1月9日</small> <a href="http://www.rigongyizu.com/hadoop-mapreduce-hive-use-sequecefile-lzo/">hadoop mapreduce和hive中使用SequeceFile+lzo格式数据</a></li><li data-position="4" data-poid="in-939" data-post-type="none"><small>2014年3月11日</small> <a href="http://www.rigongyizu.com/hadoop-datanode-cannot-start-invalid-volume/">hadoop集群DataNode起不来：&#8220;DiskChecker$DiskErrorException: Invalid volume failure  config value: 1&#8221;</a></li></ul></div></div> 											</div></div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/417971.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2014-09-16 09:28 <a href="http://www.blogjava.net/wangxinsh55/archive/2014/09/16/417971.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hadoop用MultipleInputs/MultiInputFormat实现一个mapreduce job中读取不同格式的文件</title><link>http://www.blogjava.net/wangxinsh55/archive/2014/09/16/417969.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Tue, 16 Sep 2014 01:27:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2014/09/16/417969.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/417969.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2014/09/16/417969.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/417969.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/417969.html</trackback:ping><description><![CDATA[<div>http://www.rigongyizu.com/use-multiinputformat-read-different-files-in-one-job/</div><br /><div><div> 						<p><a href="http://www.rigongyizu.com/tag/hadoop/" title="查看hadoop中的全部文章" target="_blank">hadoop</a>中提供了 <a title="Hadoop 0.20.2中怎么使用MultipleOutputFormat实现多文件输出和完全自定义文件名" href="http://www.rigongyizu.com/hadoop-multiple-outputformat/" target="_blank">MultiOutputFormat</a> 能将结果数据输出到不同的目录，也提供了 FileInputFormat 来一次读取多个目录的数据，但是默认一个job只能使用 job.setInputFormatClass 设置使用一个inputfomat处理一种格式的数据。如果需要实现 <em>在一个job中同时读取来自不同目录的不同格式文件</em> 的功能，就需要自己实现一个 MultiInputFormat 来读取不同格式的文件了(原来已经提供了<a title="MultipleInputs" href="http://hadoop.apache.org/docs/current/api/org/apache/hadoop/mapred/lib/MultipleInputs.html" target="_blank">MultipleInputs</a>)。</p> <p>例如：有一个mapreduce job需要同时读取两种格式的数据，一种格式是普通的文本文件，用 LineRecordReader 一行一行读取；另外一种文件是伪XML文件，用自定义的AJoinRecordReader读取。</p> <p>自己实现了一个简单的 MultiInputFormat 如下：</p> <div nogutter=""  "="" id="highlighter_820124"><div><div alt1"=""><table><tbody><tr><td><code>import</code> <code>org.apache.hadoop.io.LongWritable;</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>import</code> <code>org.apache.hadoop.io.Text;</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>import</code> <code>org.apache.hadoop.mapreduce.InputSplit;</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>import</code> <code>org.apache.hadoop.mapreduce.RecordReader;</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>import</code> <code>org.apache.hadoop.mapreduce.TaskAttemptContext;</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>import</code> <code>org.apache.hadoop.mapreduce.lib.input.FileSplit;</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>import</code> <code>org.apache.hadoop.mapreduce.lib.input.LineRecordReader;</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>import</code> <code>org.apache.hadoop.mapreduce.lib.input.TextInputFormat;</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td>&nbsp;</td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>public</code> <code>class</code> <code>MultiInputFormat </code><code>extends</code> <code>TextInputFormat {</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td>&nbsp;</td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>@Override</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>public</code> <code>RecordReader&lt;LongWritable, Text&gt; createRecordReader(InputSplit split, TaskAttemptContext context) {</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>RecordReader reader = </code><code>null</code><code>;</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>try</code> <code>{</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>String inputfile = ((FileSplit) split).getPath().toString();</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>String xmlpath = context.getConfiguration().get(</code><code>"xml_prefix"</code><code>);</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>String textpath = context.getConfiguration().get(</code><code>"text_prefix"</code><code>);</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td>&nbsp;</td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>if</code> <code>(-</code><code>1</code> <code>!= inputfile.indexOf(xmlpath)) {</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>reader = </code><code>new</code> <code>AJoinRecordReader();</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>} </code><code>else</code> <code>if</code> <code>(-</code><code>1</code> <code>!= inputfile.indexOf(textpath)) {</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>reader = </code><code>new</code> <code>LineRecordReader();</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>} </code><code>else</code> <code>{</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>reader = </code><code>new</code> <code>LineRecordReader();</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>}</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>} </code><code>catch</code> <code>(IOException e) {</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>// do something ...</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>}</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td>&nbsp;</td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>return</code> <code>reader;</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>}</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>}</code></td></tr></tbody></table></div></div></div> <p>其实原理很简单，就是在 createRecordReader 的时候，通过 ((FileSplit)  split).getPath().toString() 获取到当前要处理的文件名，然后根据特征匹配，选取对应的 RecordReader  即可。xml_prefix和text_prefix可以在程序启动时通过 -D 传给Configuration。</p> <p>比如某次执行打印的值如下：</p> <div nogutter=""  "="" id="highlighter_494004"><div><div alt1"=""><table><tbody><tr><td><code>inputfile=<a href="hdfs://test042092.sqa.cm4:9000/">hdfs://test042092.sqa.cm4:9000/</a></code><code>test</code><code>/input_xml/common-part-00068</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>xmlpath_prefix=<a href="hdfs://test042092.sqa.cm4:9000/">hdfs://test042092.sqa.cm4:9000/</a></code><code>test</code><code>/input_xml</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>textpath_prefix=<a href="hdfs://test042092.sqa.cm4:9000/">hdfs://test042092.sqa.cm4:9000/</a></code><code>test</code><code>/input_txt</code></td></tr></tbody></table></div></div></div> <p>这里只是通过简单的文件路径和标示符匹配来做，也可以采用更复杂的方法，比如文件名、文件后缀等。</p> <p>接着在map类中，也同样可以根据不同的文件名特征进行不同的处理：</p> <div nogutter=""  "="" id="highlighter_596127"><div><div alt1"=""><table><tbody><tr><td><code>@Override</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>public</code> <code>void</code> <code>map(LongWritable offset, Text inValue, Context context)</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>throws</code> <code>IOException {</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td>&nbsp;</td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>String inputfile = ((FileSplit) context.getInputSplit()).getPath()</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>.toString();</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td>&nbsp;</td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>if</code> <code>(-</code><code>1</code> <code>!= inputfile.indexOf(textpath)) {</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>......</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>} </code><code>else</code> <code>if</code> <code>(-</code><code>1</code> <code>!= inputfile.indexOf(xmlpath)) {</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>......</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>} </code><code>else</code> <code>{</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>......</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>}</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>}</code></td></tr></tbody></table></div></div></div> <hr /> <p>这种方式太土了，原来<a href="http://www.rigongyizu.com/tag/hadoop/" title="查看hadoop中的全部文章" target="_blank">hadoop</a>里面已经提供了 <a title="MultipleInputs" href="http://hadoop.apache.org/docs/current/api/org/apache/hadoop/mapred/lib/MultipleInputs.html" target="_blank">MultipleInputs</a> 来实现对一个目录指定一个<a href="http://www.rigongyizu.com/tag/inputformat/" title="查看inputformat中的全部文章" target="_blank">inputformat</a>和对应的map处理类。</p> <div nogutter=""  "="" id="highlighter_525908"><div><div alt1"=""><table><tbody><tr><td><code>MultipleInputs.addInputPath(conf, </code><code>new</code> <code>Path(</code><code>"/foo"</code><code>), TextInputFormat.</code><code>class</code><code>,</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;</code><code>MapClass.</code><code>class</code><code>);</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>MultipleInputs.addInputPath(conf, </code><code>new</code> <code>Path(</code><code>"/bar"</code><code>),</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;</code><code>KeyValueTextInputFormat.</code><code>class</code><code>, MapClass2.</code><code>class</code><code>);</code></td></tr></tbody></table></div></div></div>  <div wp_rp_plain"="" id="wp_rp_first"><div><h3>相关文章</h3><ul wp_rp"=""><li data-position="0" data-poid="in-1093" data-post-type="none"><small>2014年8月19日</small> <a href="http://www.rigongyizu.com/hadoop-one-map-process-one-directory/">Hadoop : 一个目录下的数据只由一个map处理</a></li><li data-position="1" data-poid="in-1074" data-post-type="none"><small>2014年6月27日</small> <a href="http://www.rigongyizu.com/hadoop-job-optimize-combinefileinputformat/">一个Hadoop程序的优化过程 &#8211; 根据文件实际大小实现CombineFileInputFormat</a></li><li data-position="2" data-poid="in-840" data-post-type="none"><small>2013年10月12日</small> <a href="http://www.rigongyizu.com/mapreduce-job-one-map-process-one-file/">mapreduce job让一个文件只由一个map来处理</a></li><li data-position="3" data-poid="in-289" data-post-type="none"><small>2012年1月9日</small> <a href="http://www.rigongyizu.com/hadoop-mapreduce-hive-use-sequecefile-lzo/">hadoop mapreduce和hive中使用SequeceFile+lzo格式数据</a></li><li data-position="4" data-poid="in-939" data-post-type="none"><small>2014年3月11日</small> <a href="http://www.rigongyizu.com/hadoop-datanode-cannot-start-invalid-volume/">hadoop集群DataNode起不来：&#8220;DiskChecker$DiskErrorException: Invalid volume failure  config value: 1&#8221;</a></li></ul></div></div> 											</div></div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/417969.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2014-09-16 09:27 <a href="http://www.blogjava.net/wangxinsh55/archive/2014/09/16/417969.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一个Hadoop程序的优化过程 – 根据文件实际大小实现CombineFileInputFormat</title><link>http://www.blogjava.net/wangxinsh55/archive/2014/09/16/417968.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Tue, 16 Sep 2014 01:25:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2014/09/16/417968.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/417968.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2014/09/16/417968.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/417968.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/417968.html</trackback:ping><description><![CDATA[<div>http://www.rigongyizu.com/hadoop-job-optimize-combinefileinputformat/</div><br /><div><div> 						<p>某日，接手了同事写的从<a href="http://www.rigongyizu.com/tag/hadoop/" title="查看hadoop中的全部文章" target="_blank">Hadoop</a>集群拷贝数据到另外一个集群的程序，该程序是运行在Hadoop集群上的job。这个job只有map阶段，读取hdfs目录下数据的数据，然后写入到另外一个集群。</p> <p>显然，这个程序没有考虑大数据量的情况，如果输入目录下文件很多或数据量很大，就会导致map数很多。而实际上我们需要拷贝的一个数据源就有近 6T，job启动起来有1w多个map，一下子整个queue的资源就占满了。虽然通过调整一些参数可以控制map数(也就是并发数)，但是无法准确的控 制map数，而且换个数据源又得重新配置参数。</p> <p>第一个改进的版本是，加了Reduce过程，以期望通过设置Reduce数量来控制并发数。这样虽然能精确地控制并发数，但是增加了shuffle 过程，实际运行中发现输入数据有倾斜（而partition的key由于业务需要无法更改），导致部分机器网络被打满，从而影响到了集群中的其他应用。即 使通过 mapred.reduce.parallel.copies  参数来限制shuffle也是治标不治本。这个平白增加的shuffle过程实际上浪费了很多网络带宽和IO。</p> <p>最理想的情况当然是只有map阶段，而且能够准确的控制并发数了。</p> <p>于是，第二个优化版本诞生了。这个job只有map阶段，采用<a href="https://hadoop.apache.org/docs/r2.2.0/api/org/apache/hadoop/mapreduce/lib/input/CombineFileInputFormat.html" title="CombineFileInputFormat" target="_blank">CombineFileInputFormat</a>， 它可以将多个小文件打包成一个InputSplit提供给一个Map处理，避免因为大量小文件问题，启动大量map。通过  mapred.max.split.size  参数可以大概地控制并发数。本以为这样就能解决问题了，结果又发现了数据倾斜的问题。这种粗略地分splits的方式，导致有的map处理的数据少，有的 map处理的数据多，并不均匀。几个拖后退的map就导致job的实际运行时间长了一倍多。</p> <p>看来只有让每个map处理的数据量一样多，才能完美的解决这个问题了。</p> <p>第三个版本也诞生了，这次是重写了CombineFileInputFormat，自己实现getSplits方法。由于输入数据为SequenceFile格式，因此需要一个SequenceFileRecordReaderWrapper类。</p> <p>实现代码如下：<br /> CustomCombineSequenceFileInputFormat.java</p> <div nogutter=""  "="" id="highlighter_630364"><div><div alt1"=""><table><tbody><tr><td><code>import</code> <code>java.io.IOException;</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td>&nbsp;</td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>import</code> <code>org.apache.hadoop.classification.InterfaceAudience;</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>import</code> <code>org.apache.hadoop.classification.InterfaceStability;</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>import</code> <code>org.apache.hadoop.mapreduce.InputSplit;</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>import</code> <code>org.apache.hadoop.mapreduce.RecordReader;</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>import</code> <code>org.apache.hadoop.mapreduce.TaskAttemptContext;</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>import</code> <code>org.apache.hadoop.mapreduce.lib.input.CombineFileInputFormat;</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>import</code> <code>org.apache.hadoop.mapreduce.lib.input.CombineFileRecordReader;</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>import</code> <code>org.apache.hadoop.mapreduce.lib.input.CombineFileRecordReaderWrapper;</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>import</code> <code>org.apache.hadoop.mapreduce.lib.input.CombineFileSplit;</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>import</code> <code>org.apache.hadoop.mapreduce.lib.input.SequenceFileInputFormat;</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td>&nbsp;</td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>/**</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;</code><code>* Input format that is a &lt;code&gt;CombineFileInputFormat&lt;/code&gt;-equivalent for</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;</code><code>* &lt;code&gt;SequenceFileInputFormat&lt;/code&gt;.</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;</code><code>* </code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;</code><code>* @see CombineFileInputFormat</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;</code><code>*/</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>@InterfaceAudience</code><code>.Public</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>@InterfaceStability</code><code>.Stable</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>public</code> <code>class</code> <code>CustomCombineSequenceFileInputFormat&lt;K, V&gt; </code><code>extends</code> <code>MultiFileInputFormat&lt;K, V&gt; {</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>@SuppressWarnings</code><code>({</code><code>"rawtypes"</code><code>, </code><code>"unchecked"</code><code>})</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>public</code> <code>RecordReader&lt;K, V&gt; createRecordReader(InputSplit split, TaskAttemptContext context)</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>throws</code> <code>IOException {</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>return</code> <code>new</code> <code>CombineFileRecordReader((CombineFileSplit) split, context,</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>SequenceFileRecordReaderWrapper.</code><code>class</code><code>);</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>}</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td>&nbsp;</td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>/**</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>* A record reader that may be passed to &lt;code&gt;CombineFileRecordReader&lt;/code&gt; so that it can be</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>* used in a &lt;code&gt;CombineFileInputFormat&lt;/code&gt;-equivalent for</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>* &lt;code&gt;SequenceFileInputFormat&lt;/code&gt;.</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>* </code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>* @see CombineFileRecordReader</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>* @see CombineFileInputFormat</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>* @see SequenceFileInputFormat</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>*/</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>private</code> <code>static</code> <code>class</code> <code>SequenceFileRecordReaderWrapper&lt;K, V&gt;</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>extends</code> <code>CombineFileRecordReaderWrapper&lt;K, V&gt; {</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>// this constructor signature is required by CombineFileRecordReader</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>public</code> <code>SequenceFileRecordReaderWrapper(CombineFileSplit split, TaskAttemptContext context,</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>Integer idx) </code><code>throws</code> <code>IOException, InterruptedException {</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>super</code><code>(</code><code>new</code> <code>SequenceFileInputFormat&lt;K, V&gt;(), split, context, idx);</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>}</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>}</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>}</code></td></tr></tbody></table></div></div></div> <p>MultiFileInputFormat.java</p> <div nogutter=""  "="" id="highlighter_34724"><div><div alt1"=""><table><tbody><tr><td><code>import</code> <code>java.io.IOException;</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>import</code> <code>java.util.ArrayList;</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>import</code> <code>java.util.List;</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td>&nbsp;</td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>import</code> <code>org.apache.commons.logging.Log;</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>import</code> <code>org.apache.commons.logging.LogFactory;</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>import</code> <code>org.apache.hadoop.fs.FileStatus;</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>import</code> <code>org.apache.hadoop.fs.Path;</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>import</code> <code>org.apache.hadoop.mapreduce.InputSplit;</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>import</code> <code>org.apache.hadoop.mapreduce.Job;</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>import</code> <code>org.apache.hadoop.mapreduce.JobContext;</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>import</code> <code>org.apache.hadoop.mapreduce.lib.input.CombineFileInputFormat;</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>import</code> <code>org.apache.hadoop.mapreduce.lib.input.CombineFileSplit;</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td>&nbsp;</td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>/**</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;</code><code>* multiple files can be combined in one InputSplit so that InputSplit number can be limited!</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;</code><code>*/</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>public</code> <code>abstract</code> <code>class</code> <code>MultiFileInputFormat&lt;K, V&gt; </code><code>extends</code> <code>CombineFileInputFormat&lt;K, V&gt; {</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td>&nbsp;</td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>private</code> <code>static</code> <code>final</code> <code>Log LOG = LogFactory.getLog(MultiFileInputFormat.</code><code>class</code><code>);</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>public</code> <code>static</code> <code>final</code> <code>String CONFNAME_INPUT_SPLIT_MAX_NUM = </code><code>"multifileinputformat.max_split_num"</code><code>;</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>public</code> <code>static</code> <code>final</code> <code>Integer DEFAULT_MAX_SPLIT_NUM = </code><code>50</code><code>;</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td>&nbsp;</td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>public</code> <code>static</code> <code>void</code> <code>setMaxInputSplitNum(Job job, Integer maxSplitNum) {</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>job.getConfiguration().setInt(CONFNAME_INPUT_SPLIT_MAX_NUM, maxSplitNum);</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>}</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td>&nbsp;</td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>@Override</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>public</code> <code>List&lt;InputSplit&gt; getSplits(JobContext job) </code><code>throws</code> <code>IOException {</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>// get all the files in input path</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>List&lt;FileStatus&gt; stats = listStatus(job);</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>List&lt;InputSplit&gt; splits = </code><code>new</code> <code>ArrayList&lt;InputSplit&gt;();</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>if</code> <code>(stats.size() == </code><code>0</code><code>) {</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>return</code> <code>splits;</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>}</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>// 计算split的平均长度</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>long</code> <code>totalLen = </code><code>0</code><code>;</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>for</code> <code>(FileStatus stat : stats) {</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>totalLen += stat.getLen();</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>}</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>int</code> <code>maxSplitNum = job.getConfiguration().getInt(CONFNAME_INPUT_SPLIT_MAX_NUM, DEFAULT_MAX_SPLIT_NUM);</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>int</code> <code>expectSplitNum = maxSplitNum &lt; stats.size() ? maxSplitNum : stats.size();</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>long</code> <code>averageLen = totalLen / expectSplitNum;</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>LOG.info(</code><code>"Prepare InputSplit : averageLen("</code> <code>+ averageLen + </code><code>") totalLen("</code> <code>+ totalLen</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>+ </code><code>") expectSplitNum("</code> <code>+ expectSplitNum + </code><code>") "</code><code>);</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>// 设置inputSplit</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>List&lt;Path&gt; pathLst = </code><code>new</code> <code>ArrayList&lt;Path&gt;();</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>List&lt;Long&gt; offsetLst = </code><code>new</code> <code>ArrayList&lt;Long&gt;();</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>List&lt;Long&gt; lengthLst = </code><code>new</code> <code>ArrayList&lt;Long&gt;();</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>long</code> <code>currentLen = </code><code>0</code><code>;</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>for</code> <code>(</code><code>int</code> <code>i = </code><code>0</code><code>; i &lt; stats.size(); i++) {</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>FileStatus stat = stats.get(i);</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>pathLst.add(stat.getPath());</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>offsetLst.add(0L);</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>lengthLst.add(stat.getLen());</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>currentLen += stat.getLen();</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>if</code> <code>(splits.size() &lt; expectSplitNum - </code><code>1</code>&nbsp;&nbsp; <code>&amp;&amp; currentLen &gt; averageLen) {</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>Path[] pathArray = </code><code>new</code> <code>Path[pathLst.size()];</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>CombineFileSplit thissplit = </code><code>new</code> <code>CombineFileSplit(pathLst.toArray(pathArray),</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>getLongArray(offsetLst), getLongArray(lengthLst), </code><code>new</code> <code>String[</code><code>0</code><code>]);</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>LOG.info(</code><code>"combineFileSplit("</code> <code>+ splits.size() + </code><code>") fileNum("</code> <code>+ pathLst.size()</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>+ </code><code>") length("</code> <code>+ currentLen + </code><code>")"</code><code>);</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>splits.add(thissplit);</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>//</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>pathLst.clear();</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>offsetLst.clear();</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>lengthLst.clear();</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>currentLen = </code><code>0</code><code>;</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>}</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>}</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>if</code> <code>(pathLst.size() &gt; </code><code>0</code><code>) {</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>Path[] pathArray = </code><code>new</code> <code>Path[pathLst.size()];</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>CombineFileSplit thissplit =</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>new</code> <code>CombineFileSplit(pathLst.toArray(pathArray), getLongArray(offsetLst),</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>getLongArray(lengthLst), </code><code>new</code> <code>String[</code><code>0</code><code>]);</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>LOG.info(</code><code>"combineFileSplit("</code> <code>+ splits.size() + </code><code>") fileNum("</code> <code>+ pathLst.size()</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>+ </code><code>") length("</code> <code>+ currentLen + </code><code>")"</code><code>);</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>splits.add(thissplit);</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>}</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>return</code> <code>splits;</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>}</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td>&nbsp;</td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>private</code> <code>long</code><code>[] getLongArray(List&lt;Long&gt; lst) {</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>long</code><code>[] rst = </code><code>new</code> <code>long</code><code>[lst.size()];</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>for</code> <code>(</code><code>int</code> <code>i = </code><code>0</code><code>; i &lt; lst.size(); i++) {</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>rst[i] = lst.get(i);</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>}</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code>return</code> <code>rst;</code></td></tr></tbody></table></div><div alt1"=""><table><tbody><tr><td><code>&nbsp;&nbsp;&nbsp;&nbsp;</code><code>}</code></td></tr></tbody></table></div><div alt2"=""><table><tbody><tr><td><code>}</code></td></tr></tbody></table></div></div></div> <p>通过 multifile<a href="http://www.rigongyizu.com/tag/inputformat/" title="查看inputformat中的全部文章" target="_blank">inputformat</a>.max_split_num 参数就可以较为准确的控制map数量，而且会发现每个map处理的数据量很均匀。至此，问题总算解决了。</p>  <div wp_rp_plain"="" id="wp_rp_first"><div><h3>相关文章</h3><ul wp_rp"=""><li data-position="0" data-poid="in-1093" data-post-type="none"><small>2014年8月19日</small> <a href="http://www.rigongyizu.com/hadoop-one-map-process-one-directory/">Hadoop : 一个目录下的数据只由一个map处理</a></li><li data-position="1" data-poid="in-840" data-post-type="none"><small>2013年10月12日</small> <a href="http://www.rigongyizu.com/mapreduce-job-one-map-process-one-file/">mapreduce job让一个文件只由一个map来处理</a></li><li data-position="2" data-poid="in-818" data-post-type="none"><small>2013年9月23日</small> <a href="http://www.rigongyizu.com/use-multiinputformat-read-different-files-in-one-job/">hadoop用MultipleInputs/MultiInputFormat实现一个mapreduce job中读取不同格式的文件</a></li><li data-position="3" data-poid="in-289" data-post-type="none"><small>2012年1月9日</small> <a href="http://www.rigongyizu.com/hadoop-mapreduce-hive-use-sequecefile-lzo/">hadoop mapreduce和hive中使用SequeceFile+lzo格式数据</a></li><li data-position="4" data-poid="in-939" data-post-type="none"><small>2014年3月11日</small> <a href="http://www.rigongyizu.com/hadoop-datanode-cannot-start-invalid-volume/">hadoop集群DataNode起不来：&#8220;DiskChecker$DiskErrorException: Invalid volume failure  config value: 1&#8221;</a></li></ul></div></div> 											</div></div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/417968.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2014-09-16 09:25 <a href="http://www.blogjava.net/wangxinsh55/archive/2014/09/16/417968.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>