MaskTask的并行度决定Map阶段的任务处理并发度,进而影响整个job的处理速度。在这里并不是MapTask越多越好,也不是越少越好。
首先说一下MapTak并行决定机制:
那什么是数据块?什么是数据切片?
5. 数据块:Block是HDFS物理上把数据块分成一块一块。默认数据块为128M,当然也可以调整。
6. 数据切片:数据切片只是逻辑上对输入进行切片,并不会在磁盘上将其切分成片进行存储。
举例说明:
如果有一个文件有300M,
7. 假设切片的大小设置为100M,呢么我们将会产生3个切片。
8. 假设切片大小设置为128M
可以看到都是产生三个切片,但是切片大小为100M的需要消耗大量IO处理,因为切片数据有跨集群的情况。所以第二种会更好。
9. 切片会以文件单独切片,不会把文件汇总然后在切片,如果有两个文件,第一个文件为300M,第二个文件80M,切片大小问128M,呢么最后会文件1产生3个切片,文件2产生1个切片,共4个切片。
Job提交流程
FileinputFormat 切片解析 input.getSplits(job)
Math.max(minSize,Math.min(maxSize,blockSize));
mapreduce.input.fileinputformat.split.minSize = 1 默认值为1
mapreduce.input.fileinputformat.split.maxSize = Long.MAXValue 默认值为Long.MAXValue
因此,默认情况下,切片大小=blocksize
如何修改minSize,maxSize参数?
使用代码和配置文件都可以
maxsize(切片最大值):参数如果调整的比blocksize小,则会让切片变小,而且就等于配置的这个参数的值。
minsize(切片最小值):参数调的比blockSize大,则可以让切片变得比blockSize大
如果输入数据有两个文件,
file1.txt 320M
file2.txt 10M
经过FileInputFormate的切片机制运算后:
file1.txt.split1------0~128
file1.txt.split2------128~256
file1.txt.split3------256~300
file2.txt.split1------0~10
【Hadoop】2.MapReduce示例——WordCount(统计单词)
框架默认的TextInputFormat切片机制是对任务按照文件规划切片,不管文件多小,都会是一个单独的切片,都会交给一个MapTask,这样就会出现另外一种情况,如果有100个5KB的文件,就会出现100个切片,效率很低
CombineTextInputFormat用于小文件过多的场景,它可以将多个小文件从逻辑上规划到一个切片中,这样,多个小文件就可以交给一个MapTask处理。
通过APICombineTextInputFoemat.setMaxInputSplitSize(job,4194304);设置大小 单位为B
4194304B=4 * 1024 * 1024
注意:虚拟存储切片最大值设置最好根据实际的小文件大小情况来设置具体的值
前期我们准备7个小文件,分别以不作处理和使用CombineTextInputFormat作区分,观察splits个数。
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
// 获取job对象
System.setProperty("hadoop.home.dir", "E:\\hadoop-2.7.1");
Configuration configuration = new Configuration();
FileSystem fs = FileSystem.get(configuration);
//configuration.set("mapreduce.framework.name","local");
//configuration.set("fs.defaultFS","file:///");
Job job = Job.getInstance(configuration);
// 设置加载类
job.setJarByClass(WordCountDriver.class);
// 设置map和reduce类
job.setMapperClass(WordCountMapper.class);
job.setReducerClass(WordCountReduce.class);
// 设置mapper输出类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
// 设置最终输出类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
// 设置输入文件和输出文件
FileInputFormat.setInputPaths(job,new Path("E:\\hdfs\\input\\"));
Path outPath = new Path("E:\\hdfs\\output");
if (fs.exists(outPath)) {
fs.delete(outPath, true);
}
// 数据输出路径
FileOutputFormat.setOutputPath(job, new Path("E:\\hdfs\\output"));
boolean waitForCompletion = job.waitForCompletion(true);
System.out.println(waitForCompletion);
System.exit(waitForCompletion?0:1);
// 命令执行MR
// hadoop jar 目标jar包 目标类 输入路径 输出路径
// hadoop jar **.jar com.xing.MapReduce.WordCount.WordCountDriver 输入路径 输出路径
}
2. CombineTextInputFormat
添加几行代码:
// 设置CombineTextInputFormat
job.setInputFormatClass(CombineTextInputFormat.class);
CombineTextInputFormat.setMaxInputSplitSize(job,10*1024); //单位是b 字节
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
// 获取job对象
System.setProperty("hadoop.home.dir", "E:\\hadoop-2.7.1");
Configuration configuration = new Configuration();
FileSystem fs = FileSystem.get(configuration);
//configuration.set("mapreduce.framework.name","local");
//configuration.set("fs.defaultFS","file:///");
Job job = Job.getInstance(configuration);
// 设置加载类
job.setJarByClass(WordCountDriver.class);
// 设置map和reduce类
job.setMapperClass(WordCountMapper.class);
job.setReducerClass(WordCountReduce.class);
// 设置CombineTextInputFormat
job.setInputFormatClass(CombineTextInputFormat.class);
CombineTextInputFormat.setMaxInputSplitSize(job,10*1024); //单位是b 字节
// 设置mapper输出类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
// 设置最终输出类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
// 设置输入文件和输出文件
FileInputFormat.setInputPaths(job,new Path("E:\\hdfs\\input\\"));
Path outPath = new Path("E:\\hdfs\\output");
if (fs.exists(outPath)) {
fs.delete(outPath, true);
}
// 数据输出路径
FileOutputFormat.setOutputPath(job, new Path("E:\\hdfs\\output"));
boolean waitForCompletion = job.waitForCompletion(true);
System.out.println(waitForCompletion);
System.exit(waitForCompletion?0:1);
// 命令执行MR
// hadoop jar 目标jar包 目标类 输入路径 输出路径
// hadoop jar **.jar com.xing.MapReduce.WordCount.WordCountDriver 输入路径 输出路径
}
切片机制说完了,就说说FileInputFormat实现类都有哪些。
在运行MapReduce程序时,输入的文件格式包括:基于行的日志文件,二进制格式文件,数据库表等。针对不同的数据类型,需要选择不同的输入类
FileinputFormat常见的接口实现类为:TextInputFormat,KeyValueTextInputFormat,NLineInputFormat,CombineTextInputFormat和自定义InputFormat(这个很重要)
这个是默认的FileInputFormat实现类。按行读取每条记录。
键是存储该行在整个文件中的起始字节偏移量,LongWritable类型。
值是该行的内容,不包括任何终止符(换行符和回车符)
示例,一个分片包含了如下:
abc 14
yes
aaaa
结果:
(0,abc 14)
(7,yes)
(11,aaaa)
每一行均是一条记录,被分隔符分割为key,value。可以通过在驱动类中设置configuration.set(KeyValueLineRecordReader.KEY_VALUE_SEPERATOR, "\t");
来设定分隔符。默认分隔符是tab("\t") 。
// 设置切割符
conf.set(KeyValueLineRecordReader.KEY_VALUE_SEPERATOR, "\t");
// 设置输入格式
job.setInputFormatClass(KeyValueTextInputFormat.class);
示例:
xiaoming——> im a student
xiaohong——> im a student2
wangming——> im a student3
结果:
(xiaoming,im a student)
(xiaohong,im a student2)
(wangming, im a student3)
使用NlineInputFormat,代表了每个map进程处理的InputSplit不在按照Block划分,而是按照NLineInputFormat指定的行数N来划分。即输入文件的总行数/N=切片数 ,如果不整除,切片数=商+1
// 设置每个切片InputSplit中划分三条记录
NLineInputFormat.setNumLinesPerSplit(job, 3);
// 使用NLineInputFormat处理记录数
job.setInputFormatClass(NLineInputFormat.class);
示例:
N=2
一个文件包含了如下:
abc 14
yes
aaaa
结果:
第一个切片:
(0,abc 14)
(7,yes)
第二个切片:
(11,aaaa)
这里的键值对得值和TextInputFormat一样的